1 | //===- bolt/Target/X86/X86MCPlusBuilder.cpp -------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file provides X86-specific MCPlus builder. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "MCTargetDesc/X86BaseInfo.h" |
14 | #include "MCTargetDesc/X86EncodingOptimization.h" |
15 | #include "MCTargetDesc/X86MCTargetDesc.h" |
16 | #include "X86MCSymbolizer.h" |
17 | #include "bolt/Core/MCPlus.h" |
18 | #include "bolt/Core/MCPlusBuilder.h" |
19 | #include "llvm/BinaryFormat/ELF.h" |
20 | #include "llvm/MC/MCContext.h" |
21 | #include "llvm/MC/MCFixupKindInfo.h" |
22 | #include "llvm/MC/MCInst.h" |
23 | #include "llvm/MC/MCInstBuilder.h" |
24 | #include "llvm/MC/MCInstrInfo.h" |
25 | #include "llvm/MC/MCRegister.h" |
26 | #include "llvm/MC/MCRegisterInfo.h" |
27 | #include "llvm/Support/CommandLine.h" |
28 | #include "llvm/Support/DataExtractor.h" |
29 | #include "llvm/Support/Debug.h" |
30 | #include "llvm/Support/Errc.h" |
31 | #include "llvm/Support/ErrorHandling.h" |
32 | #include "llvm/Support/ErrorOr.h" |
33 | #include <set> |
34 | |
35 | #define DEBUG_TYPE "mcplus" |
36 | |
37 | using namespace llvm; |
38 | using namespace bolt; |
39 | |
40 | namespace opts { |
41 | |
42 | extern cl::OptionCategory BoltOptCategory; |
43 | |
44 | static cl::opt<bool> X86StripRedundantAddressSize( |
45 | "x86-strip-redundant-address-size" , |
46 | cl::desc("Remove redundant Address-Size override prefix" ), cl::init(Val: true), |
47 | cl::cat(BoltOptCategory)); |
48 | |
49 | } // namespace opts |
50 | |
51 | namespace { |
52 | |
53 | bool isMOVSX64rm32(const MCInst &Inst) { |
54 | return Inst.getOpcode() == X86::MOVSX64rm32; |
55 | } |
56 | |
57 | bool isADD64rr(const MCInst &Inst) { return Inst.getOpcode() == X86::ADD64rr; } |
58 | |
59 | bool isADDri(const MCInst &Inst) { |
60 | return Inst.getOpcode() == X86::ADD64ri32 || |
61 | Inst.getOpcode() == X86::ADD64ri8; |
62 | } |
63 | |
64 | // Create instruction to increment contents of target by 1 |
65 | static InstructionListType createIncMemory(const MCSymbol *Target, |
66 | MCContext *Ctx) { |
67 | InstructionListType Insts; |
68 | Insts.emplace_back(); |
69 | Insts.back().setOpcode(X86::LOCK_INC64m); |
70 | Insts.back().clear(); |
71 | Insts.back().addOperand(Op: MCOperand::createReg(X86::Reg: RIP)); // BaseReg |
72 | Insts.back().addOperand(Op: MCOperand::createImm(Val: 1)); // ScaleAmt |
73 | Insts.back().addOperand(Op: MCOperand::createReg(X86::Reg: NoRegister)); // IndexReg |
74 | |
75 | Insts.back().addOperand(Op: MCOperand::createExpr( |
76 | Val: MCSymbolRefExpr::create(Symbol: Target, Kind: MCSymbolRefExpr::VK_None, |
77 | Ctx&: *Ctx))); // Displacement |
78 | Insts.back().addOperand( |
79 | Op: MCOperand::createReg(X86::Reg: NoRegister)); // AddrSegmentReg |
80 | return Insts; |
81 | } |
82 | |
83 | #define GET_INSTRINFO_OPERAND_TYPES_ENUM |
84 | #define GET_INSTRINFO_OPERAND_TYPE |
85 | #define GET_INSTRINFO_MEM_OPERAND_SIZE |
86 | #include "X86GenInstrInfo.inc" |
87 | |
88 | class X86MCPlusBuilder : public MCPlusBuilder { |
89 | public: |
90 | using MCPlusBuilder::MCPlusBuilder; |
91 | |
92 | std::unique_ptr<MCSymbolizer> |
93 | createTargetSymbolizer(BinaryFunction &Function, |
94 | bool CreateNewSymbols) const override { |
95 | return std::make_unique<X86MCSymbolizer>(Function, CreateNewSymbols); |
96 | } |
97 | |
98 | bool isBranch(const MCInst &Inst) const override { |
99 | return Analysis->isBranch(Inst) && !isTailCall(Inst); |
100 | } |
101 | |
102 | bool isNoop(const MCInst &Inst) const override { |
103 | return X86::isNOP(Inst.getOpcode()); |
104 | } |
105 | |
106 | unsigned getCondCode(const MCInst &Inst) const override { |
107 | unsigned Opcode = Inst.getOpcode(); |
108 | if (X86::isJCC(Opcode)) |
109 | return Inst.getOperand(i: Info->get(Opcode).NumOperands - 1).getImm(); |
110 | return X86::COND_INVALID; |
111 | } |
112 | |
113 | unsigned getInvertedCondCode(unsigned CC) const override { |
114 | switch (CC) { |
115 | default: return X86::COND_INVALID; |
116 | case X86::COND_E: return X86::COND_NE; |
117 | case X86::COND_NE: return X86::COND_E; |
118 | case X86::COND_L: return X86::COND_GE; |
119 | case X86::COND_LE: return X86::COND_G; |
120 | case X86::COND_G: return X86::COND_LE; |
121 | case X86::COND_GE: return X86::COND_L; |
122 | case X86::COND_B: return X86::COND_AE; |
123 | case X86::COND_BE: return X86::COND_A; |
124 | case X86::COND_A: return X86::COND_BE; |
125 | case X86::COND_AE: return X86::COND_B; |
126 | case X86::COND_S: return X86::COND_NS; |
127 | case X86::COND_NS: return X86::COND_S; |
128 | case X86::COND_P: return X86::COND_NP; |
129 | case X86::COND_NP: return X86::COND_P; |
130 | case X86::COND_O: return X86::COND_NO; |
131 | case X86::COND_NO: return X86::COND_O; |
132 | } |
133 | } |
134 | |
135 | unsigned getCondCodesLogicalOr(unsigned CC1, unsigned CC2) const override { |
136 | enum DecodedCondCode : uint8_t { |
137 | DCC_EQUAL = 0x1, |
138 | DCC_GREATER = 0x2, |
139 | DCC_LESSER = 0x4, |
140 | DCC_GREATER_OR_LESSER = 0x6, |
141 | DCC_UNSIGNED = 0x8, |
142 | DCC_SIGNED = 0x10, |
143 | DCC_INVALID = 0x20, |
144 | }; |
145 | |
146 | auto decodeCondCode = [&](unsigned CC) -> uint8_t { |
147 | switch (CC) { |
148 | default: return DCC_INVALID; |
149 | case X86::COND_E: return DCC_EQUAL; |
150 | case X86::COND_NE: return DCC_GREATER | DCC_LESSER; |
151 | case X86::COND_L: return DCC_LESSER | DCC_SIGNED; |
152 | case X86::COND_LE: return DCC_EQUAL | DCC_LESSER | DCC_SIGNED; |
153 | case X86::COND_G: return DCC_GREATER | DCC_SIGNED; |
154 | case X86::COND_GE: return DCC_GREATER | DCC_EQUAL | DCC_SIGNED; |
155 | case X86::COND_B: return DCC_LESSER | DCC_UNSIGNED; |
156 | case X86::COND_BE: return DCC_EQUAL | DCC_LESSER | DCC_UNSIGNED; |
157 | case X86::COND_A: return DCC_GREATER | DCC_UNSIGNED; |
158 | case X86::COND_AE: return DCC_GREATER | DCC_EQUAL | DCC_UNSIGNED; |
159 | } |
160 | }; |
161 | |
162 | uint8_t DCC = decodeCondCode(CC1) | decodeCondCode(CC2); |
163 | |
164 | if (DCC & DCC_INVALID) |
165 | return X86::COND_INVALID; |
166 | |
167 | if (DCC & DCC_SIGNED && DCC & DCC_UNSIGNED) |
168 | return X86::COND_INVALID; |
169 | |
170 | switch (DCC) { |
171 | default: return X86::COND_INVALID; |
172 | case DCC_EQUAL | DCC_LESSER | DCC_SIGNED: return X86::COND_LE; |
173 | case DCC_EQUAL | DCC_LESSER | DCC_UNSIGNED: return X86::COND_BE; |
174 | case DCC_EQUAL | DCC_GREATER | DCC_SIGNED: return X86::COND_GE; |
175 | case DCC_EQUAL | DCC_GREATER | DCC_UNSIGNED: return X86::COND_AE; |
176 | case DCC_GREATER | DCC_LESSER | DCC_SIGNED: return X86::COND_NE; |
177 | case DCC_GREATER | DCC_LESSER | DCC_UNSIGNED: return X86::COND_NE; |
178 | case DCC_GREATER | DCC_LESSER: return X86::COND_NE; |
179 | case DCC_EQUAL | DCC_SIGNED: return X86::COND_E; |
180 | case DCC_EQUAL | DCC_UNSIGNED: return X86::COND_E; |
181 | case DCC_EQUAL: return X86::COND_E; |
182 | case DCC_LESSER | DCC_SIGNED: return X86::COND_L; |
183 | case DCC_LESSER | DCC_UNSIGNED: return X86::COND_B; |
184 | case DCC_GREATER | DCC_SIGNED: return X86::COND_G; |
185 | case DCC_GREATER | DCC_UNSIGNED: return X86::COND_A; |
186 | } |
187 | } |
188 | |
189 | bool isValidCondCode(unsigned CC) const override { |
190 | return (CC != X86::COND_INVALID); |
191 | } |
192 | |
193 | bool isBreakpoint(const MCInst &Inst) const override { |
194 | return Inst.getOpcode() == X86::INT3; |
195 | } |
196 | |
197 | bool isPrefix(const MCInst &Inst) const override { |
198 | const MCInstrDesc &Desc = Info->get(Opcode: Inst.getOpcode()); |
199 | return X86II::isPrefix(TSFlags: Desc.TSFlags); |
200 | } |
201 | |
202 | bool isRep(const MCInst &Inst) const override { |
203 | return Inst.getFlags() == X86::IP_HAS_REPEAT; |
204 | } |
205 | |
206 | bool deleteREPPrefix(MCInst &Inst) const override { |
207 | if (Inst.getFlags() == X86::IP_HAS_REPEAT) { |
208 | Inst.setFlags(0); |
209 | return true; |
210 | } |
211 | return false; |
212 | } |
213 | |
214 | bool isIndirectCall(const MCInst &Inst) const override { |
215 | return isCall(Inst) && |
216 | ((getMemoryOperandNo(Inst) != -1) || Inst.getOperand(i: 0).isReg()); |
217 | } |
218 | |
219 | bool isPop(const MCInst &Inst) const override { |
220 | return getPopSize(Inst) == 0 ? false : true; |
221 | } |
222 | |
223 | bool isTerminateBranch(const MCInst &Inst) const override { |
224 | return Inst.getOpcode() == X86::ENDBR32 || Inst.getOpcode() == X86::ENDBR64; |
225 | } |
226 | |
227 | int getPopSize(const MCInst &Inst) const override { |
228 | switch (Inst.getOpcode()) { |
229 | case X86::POP16r: |
230 | case X86::POP16rmm: |
231 | case X86::POP16rmr: |
232 | case X86::POPF16: |
233 | case X86::POPA16: |
234 | case X86::POPDS16: |
235 | case X86::POPES16: |
236 | case X86::POPFS16: |
237 | case X86::POPGS16: |
238 | case X86::POPSS16: |
239 | return 2; |
240 | case X86::POP32r: |
241 | case X86::POP32rmm: |
242 | case X86::POP32rmr: |
243 | case X86::POPA32: |
244 | case X86::POPDS32: |
245 | case X86::POPES32: |
246 | case X86::POPF32: |
247 | case X86::POPFS32: |
248 | case X86::POPGS32: |
249 | case X86::POPSS32: |
250 | return 4; |
251 | case X86::POP64r: |
252 | case X86::POP64rmm: |
253 | case X86::POP64rmr: |
254 | case X86::POPF64: |
255 | case X86::POPFS64: |
256 | case X86::POPGS64: |
257 | return 8; |
258 | } |
259 | return 0; |
260 | } |
261 | |
262 | bool isPush(const MCInst &Inst) const override { |
263 | return getPushSize(Inst) == 0 ? false : true; |
264 | } |
265 | |
266 | int getPushSize(const MCInst &Inst) const override { |
267 | switch (Inst.getOpcode()) { |
268 | case X86::PUSH16i8: |
269 | case X86::PUSH16r: |
270 | case X86::PUSH16rmm: |
271 | case X86::PUSH16rmr: |
272 | case X86::PUSHA16: |
273 | case X86::PUSHCS16: |
274 | case X86::PUSHDS16: |
275 | case X86::PUSHES16: |
276 | case X86::PUSHF16: |
277 | case X86::PUSHFS16: |
278 | case X86::PUSHGS16: |
279 | case X86::PUSHSS16: |
280 | case X86::PUSH16i: |
281 | return 2; |
282 | case X86::PUSH32i8: |
283 | case X86::PUSH32r: |
284 | case X86::PUSH32rmm: |
285 | case X86::PUSH32rmr: |
286 | case X86::PUSHA32: |
287 | case X86::PUSHCS32: |
288 | case X86::PUSHDS32: |
289 | case X86::PUSHES32: |
290 | case X86::PUSHF32: |
291 | case X86::PUSHFS32: |
292 | case X86::PUSHGS32: |
293 | case X86::PUSHSS32: |
294 | case X86::PUSH32i: |
295 | return 4; |
296 | case X86::PUSH64i32: |
297 | case X86::PUSH64i8: |
298 | case X86::PUSH64r: |
299 | case X86::PUSH64rmm: |
300 | case X86::PUSH64rmr: |
301 | case X86::PUSHF64: |
302 | case X86::PUSHFS64: |
303 | case X86::PUSHGS64: |
304 | return 8; |
305 | } |
306 | return 0; |
307 | } |
308 | |
309 | bool isSUB(const MCInst &Inst) const override { |
310 | return X86::isSUB(Inst.getOpcode()); |
311 | } |
312 | |
313 | bool isLEA64r(const MCInst &Inst) const override { |
314 | return Inst.getOpcode() == X86::LEA64r; |
315 | } |
316 | |
317 | bool isLeave(const MCInst &Inst) const override { |
318 | return Inst.getOpcode() == X86::LEAVE || Inst.getOpcode() == X86::LEAVE64; |
319 | } |
320 | |
321 | bool isMoveMem2Reg(const MCInst &Inst) const override { |
322 | switch (Inst.getOpcode()) { |
323 | case X86::MOV16rm: |
324 | case X86::MOV32rm: |
325 | case X86::MOV64rm: |
326 | return true; |
327 | } |
328 | return false; |
329 | } |
330 | |
331 | bool isUnsupportedInstruction(const MCInst &Inst) const override { |
332 | switch (Inst.getOpcode()) { |
333 | default: |
334 | return false; |
335 | |
336 | case X86::LOOP: |
337 | case X86::LOOPE: |
338 | case X86::LOOPNE: |
339 | case X86::JECXZ: |
340 | case X86::JRCXZ: |
341 | // These have a short displacement, and therefore (often) break after |
342 | // basic block relayout. |
343 | return true; |
344 | } |
345 | } |
346 | |
347 | bool mayLoad(const MCInst &Inst) const override { |
348 | if (isPop(Inst)) |
349 | return true; |
350 | |
351 | int MemOpNo = getMemoryOperandNo(Inst); |
352 | const MCInstrDesc &MCII = Info->get(Opcode: Inst.getOpcode()); |
353 | |
354 | if (MemOpNo == -1) |
355 | return false; |
356 | |
357 | return MCII.mayLoad(); |
358 | } |
359 | |
360 | bool mayStore(const MCInst &Inst) const override { |
361 | if (isPush(Inst)) |
362 | return true; |
363 | |
364 | int MemOpNo = getMemoryOperandNo(Inst); |
365 | const MCInstrDesc &MCII = Info->get(Opcode: Inst.getOpcode()); |
366 | |
367 | if (MemOpNo == -1) |
368 | return false; |
369 | |
370 | return MCII.mayStore(); |
371 | } |
372 | |
373 | bool isCleanRegXOR(const MCInst &Inst) const override { |
374 | switch (Inst.getOpcode()) { |
375 | case X86::XOR16rr: |
376 | case X86::XOR32rr: |
377 | case X86::XOR64rr: |
378 | break; |
379 | default: |
380 | return false; |
381 | } |
382 | return (Inst.getOperand(i: 0).getReg() == Inst.getOperand(i: 2).getReg()); |
383 | } |
384 | |
385 | bool isPacked(const MCInst &Inst) const override { |
386 | const MCInstrDesc &Desc = Info->get(Opcode: Inst.getOpcode()); |
387 | return (Desc.TSFlags & X86II::OpPrefixMask) == X86II::PD; |
388 | } |
389 | |
390 | bool shouldRecordCodeRelocation(uint32_t RelType) const override { |
391 | switch (RelType) { |
392 | case ELF::R_X86_64_8: |
393 | case ELF::R_X86_64_16: |
394 | case ELF::R_X86_64_32: |
395 | case ELF::R_X86_64_32S: |
396 | case ELF::R_X86_64_64: |
397 | case ELF::R_X86_64_PC8: |
398 | case ELF::R_X86_64_PC32: |
399 | case ELF::R_X86_64_PC64: |
400 | case ELF::R_X86_64_GOTPC64: |
401 | case ELF::R_X86_64_GOTPCRELX: |
402 | case ELF::R_X86_64_REX_GOTPCRELX: |
403 | return true; |
404 | case ELF::R_X86_64_PLT32: |
405 | case ELF::R_X86_64_GOTPCREL: |
406 | case ELF::R_X86_64_TPOFF32: |
407 | case ELF::R_X86_64_GOTTPOFF: |
408 | return false; |
409 | default: |
410 | llvm_unreachable("Unexpected x86 relocation type in code" ); |
411 | } |
412 | } |
413 | |
414 | StringRef getTrapFillValue() const override { return StringRef("\314" , 1); } |
415 | |
416 | struct IndJmpMatcherFrag1 : MCInstMatcher { |
417 | std::unique_ptr<MCInstMatcher> Base; |
418 | std::unique_ptr<MCInstMatcher> Scale; |
419 | std::unique_ptr<MCInstMatcher> Index; |
420 | std::unique_ptr<MCInstMatcher> Offset; |
421 | |
422 | IndJmpMatcherFrag1(std::unique_ptr<MCInstMatcher> Base, |
423 | std::unique_ptr<MCInstMatcher> Scale, |
424 | std::unique_ptr<MCInstMatcher> Index, |
425 | std::unique_ptr<MCInstMatcher> Offset) |
426 | : Base(std::move(Base)), Scale(std::move(Scale)), |
427 | Index(std::move(Index)), Offset(std::move(Offset)) {} |
428 | |
429 | bool match(const MCRegisterInfo &MRI, MCPlusBuilder &MIB, |
430 | MutableArrayRef<MCInst> InInstrWindow, int OpNum) override { |
431 | if (!MCInstMatcher::match(MRI, MIB, InInstrWindow, OpNum)) |
432 | return false; |
433 | |
434 | if (CurInst->getOpcode() != X86::JMP64m) |
435 | return false; |
436 | |
437 | int MemOpNo = MIB.getMemoryOperandNo(Inst: *CurInst); |
438 | if (MemOpNo == -1) |
439 | return false; |
440 | |
441 | if (!Base->match(MRI, MIB, this->InstrWindow, MemOpNo + X86::AddrBaseReg)) |
442 | return false; |
443 | if (!Scale->match(MRI, MIB, this->InstrWindow, |
444 | MemOpNo + X86::AddrScaleAmt)) |
445 | return false; |
446 | if (!Index->match(MRI, MIB, this->InstrWindow, |
447 | MemOpNo + X86::AddrIndexReg)) |
448 | return false; |
449 | if (!Offset->match(MRI, MIB, this->InstrWindow, MemOpNo + X86::AddrDisp)) |
450 | return false; |
451 | return true; |
452 | } |
453 | |
454 | void annotate(MCPlusBuilder &MIB, StringRef Annotation) override { |
455 | MIB.addAnnotation(*CurInst, Annotation, true); |
456 | Base->annotate(MIB, Annotation); |
457 | Scale->annotate(MIB, Annotation); |
458 | Index->annotate(MIB, Annotation); |
459 | Offset->annotate(MIB, Annotation); |
460 | } |
461 | }; |
462 | |
463 | std::unique_ptr<MCInstMatcher> |
464 | matchIndJmp(std::unique_ptr<MCInstMatcher> Base, |
465 | std::unique_ptr<MCInstMatcher> Scale, |
466 | std::unique_ptr<MCInstMatcher> Index, |
467 | std::unique_ptr<MCInstMatcher> Offset) const override { |
468 | return std::unique_ptr<MCInstMatcher>( |
469 | new IndJmpMatcherFrag1(std::move(Base), std::move(Scale), |
470 | std::move(Index), std::move(Offset))); |
471 | } |
472 | |
473 | struct IndJmpMatcherFrag2 : MCInstMatcher { |
474 | std::unique_ptr<MCInstMatcher> Reg; |
475 | |
476 | IndJmpMatcherFrag2(std::unique_ptr<MCInstMatcher> Reg) |
477 | : Reg(std::move(Reg)) {} |
478 | |
479 | bool match(const MCRegisterInfo &MRI, MCPlusBuilder &MIB, |
480 | MutableArrayRef<MCInst> InInstrWindow, int OpNum) override { |
481 | if (!MCInstMatcher::match(MRI, MIB, InInstrWindow, OpNum)) |
482 | return false; |
483 | |
484 | if (CurInst->getOpcode() != X86::JMP64r) |
485 | return false; |
486 | |
487 | return Reg->match(MRI, MIB, this->InstrWindow, 0); |
488 | } |
489 | |
490 | void annotate(MCPlusBuilder &MIB, StringRef Annotation) override { |
491 | MIB.addAnnotation(*CurInst, Annotation, true); |
492 | Reg->annotate(MIB, Annotation); |
493 | } |
494 | }; |
495 | |
496 | std::unique_ptr<MCInstMatcher> |
497 | matchIndJmp(std::unique_ptr<MCInstMatcher> Target) const override { |
498 | return std::unique_ptr<MCInstMatcher>( |
499 | new IndJmpMatcherFrag2(std::move(Target))); |
500 | } |
501 | |
502 | struct LoadMatcherFrag1 : MCInstMatcher { |
503 | std::unique_ptr<MCInstMatcher> Base; |
504 | std::unique_ptr<MCInstMatcher> Scale; |
505 | std::unique_ptr<MCInstMatcher> Index; |
506 | std::unique_ptr<MCInstMatcher> Offset; |
507 | |
508 | LoadMatcherFrag1(std::unique_ptr<MCInstMatcher> Base, |
509 | std::unique_ptr<MCInstMatcher> Scale, |
510 | std::unique_ptr<MCInstMatcher> Index, |
511 | std::unique_ptr<MCInstMatcher> Offset) |
512 | : Base(std::move(Base)), Scale(std::move(Scale)), |
513 | Index(std::move(Index)), Offset(std::move(Offset)) {} |
514 | |
515 | bool match(const MCRegisterInfo &MRI, MCPlusBuilder &MIB, |
516 | MutableArrayRef<MCInst> InInstrWindow, int OpNum) override { |
517 | if (!MCInstMatcher::match(MRI, MIB, InInstrWindow, OpNum)) |
518 | return false; |
519 | |
520 | if (CurInst->getOpcode() != X86::MOV64rm && |
521 | CurInst->getOpcode() != X86::MOVSX64rm32) |
522 | return false; |
523 | |
524 | int MemOpNo = MIB.getMemoryOperandNo(Inst: *CurInst); |
525 | if (MemOpNo == -1) |
526 | return false; |
527 | |
528 | if (!Base->match(MRI, MIB, this->InstrWindow, MemOpNo + X86::AddrBaseReg)) |
529 | return false; |
530 | if (!Scale->match(MRI, MIB, this->InstrWindow, |
531 | MemOpNo + X86::AddrScaleAmt)) |
532 | return false; |
533 | if (!Index->match(MRI, MIB, this->InstrWindow, |
534 | MemOpNo + X86::AddrIndexReg)) |
535 | return false; |
536 | if (!Offset->match(MRI, MIB, this->InstrWindow, MemOpNo + X86::AddrDisp)) |
537 | return false; |
538 | return true; |
539 | } |
540 | |
541 | void annotate(MCPlusBuilder &MIB, StringRef Annotation) override { |
542 | MIB.addAnnotation(*CurInst, Annotation, true); |
543 | Base->annotate(MIB, Annotation); |
544 | Scale->annotate(MIB, Annotation); |
545 | Index->annotate(MIB, Annotation); |
546 | Offset->annotate(MIB, Annotation); |
547 | } |
548 | }; |
549 | |
550 | std::unique_ptr<MCInstMatcher> |
551 | matchLoad(std::unique_ptr<MCInstMatcher> Base, |
552 | std::unique_ptr<MCInstMatcher> Scale, |
553 | std::unique_ptr<MCInstMatcher> Index, |
554 | std::unique_ptr<MCInstMatcher> Offset) const override { |
555 | return std::unique_ptr<MCInstMatcher>( |
556 | new LoadMatcherFrag1(std::move(Base), std::move(Scale), |
557 | std::move(Index), std::move(Offset))); |
558 | } |
559 | |
560 | struct AddMatcher : MCInstMatcher { |
561 | std::unique_ptr<MCInstMatcher> A; |
562 | std::unique_ptr<MCInstMatcher> B; |
563 | |
564 | AddMatcher(std::unique_ptr<MCInstMatcher> A, |
565 | std::unique_ptr<MCInstMatcher> B) |
566 | : A(std::move(A)), B(std::move(B)) {} |
567 | |
568 | bool match(const MCRegisterInfo &MRI, MCPlusBuilder &MIB, |
569 | MutableArrayRef<MCInst> InInstrWindow, int OpNum) override { |
570 | if (!MCInstMatcher::match(MRI, MIB, InInstrWindow, OpNum)) |
571 | return false; |
572 | |
573 | if (CurInst->getOpcode() == X86::ADD64rr || |
574 | CurInst->getOpcode() == X86::ADD64rr_DB || |
575 | CurInst->getOpcode() == X86::ADD64rr_REV) { |
576 | if (!A->match(MRI, MIB, this->InstrWindow, 1)) { |
577 | if (!B->match(MRI, MIB, this->InstrWindow, 1)) |
578 | return false; |
579 | return A->match(MRI, MIB, this->InstrWindow, 2); |
580 | } |
581 | |
582 | if (B->match(MRI, MIB, this->InstrWindow, 2)) |
583 | return true; |
584 | |
585 | if (!B->match(MRI, MIB, this->InstrWindow, 1)) |
586 | return false; |
587 | return A->match(MRI, MIB, this->InstrWindow, 2); |
588 | } |
589 | |
590 | return false; |
591 | } |
592 | |
593 | void annotate(MCPlusBuilder &MIB, StringRef Annotation) override { |
594 | MIB.addAnnotation(*CurInst, Annotation, true); |
595 | A->annotate(MIB, Annotation); |
596 | B->annotate(MIB, Annotation); |
597 | } |
598 | }; |
599 | |
600 | std::unique_ptr<MCInstMatcher> |
601 | matchAdd(std::unique_ptr<MCInstMatcher> A, |
602 | std::unique_ptr<MCInstMatcher> B) const override { |
603 | return std::unique_ptr<MCInstMatcher>( |
604 | new AddMatcher(std::move(A), std::move(B))); |
605 | } |
606 | |
607 | struct LEAMatcher : MCInstMatcher { |
608 | std::unique_ptr<MCInstMatcher> Target; |
609 | |
610 | LEAMatcher(std::unique_ptr<MCInstMatcher> Target) |
611 | : Target(std::move(Target)) {} |
612 | |
613 | bool match(const MCRegisterInfo &MRI, MCPlusBuilder &MIB, |
614 | MutableArrayRef<MCInst> InInstrWindow, int OpNum) override { |
615 | if (!MCInstMatcher::match(MRI, MIB, InInstrWindow, OpNum)) |
616 | return false; |
617 | |
618 | if (CurInst->getOpcode() != X86::LEA64r) |
619 | return false; |
620 | |
621 | if (CurInst->getOperand(1 + X86::AddrScaleAmt).getImm() != 1 || |
622 | CurInst->getOperand(1 + X86::AddrIndexReg).getReg() != |
623 | X86::NoRegister || |
624 | (CurInst->getOperand(1 + X86::AddrBaseReg).getReg() != |
625 | X86::NoRegister && |
626 | CurInst->getOperand(1 + X86::AddrBaseReg).getReg() != X86::RIP)) |
627 | return false; |
628 | |
629 | return Target->match(MRI, MIB, this->InstrWindow, 1 + X86::AddrDisp); |
630 | } |
631 | |
632 | void annotate(MCPlusBuilder &MIB, StringRef Annotation) override { |
633 | MIB.addAnnotation(*CurInst, Annotation, true); |
634 | Target->annotate(MIB, Annotation); |
635 | } |
636 | }; |
637 | |
638 | std::unique_ptr<MCInstMatcher> |
639 | matchLoadAddr(std::unique_ptr<MCInstMatcher> Target) const override { |
640 | return std::unique_ptr<MCInstMatcher>(new LEAMatcher(std::move(Target))); |
641 | } |
642 | |
643 | bool hasPCRelOperand(const MCInst &Inst) const override { |
644 | for (const MCOperand &Operand : Inst) |
645 | if (Operand.isReg() && Operand.getReg() == X86::RIP) |
646 | return true; |
647 | return false; |
648 | } |
649 | |
650 | int getMemoryOperandNo(const MCInst &Inst) const override { |
651 | unsigned Opcode = Inst.getOpcode(); |
652 | const MCInstrDesc &Desc = Info->get(Opcode); |
653 | int MemOpNo = X86II::getMemoryOperandNo(TSFlags: Desc.TSFlags); |
654 | if (MemOpNo >= 0) |
655 | MemOpNo += X86II::getOperandBias(Desc); |
656 | return MemOpNo; |
657 | } |
658 | |
659 | bool hasEVEXEncoding(const MCInst &Inst) const override { |
660 | const MCInstrDesc &Desc = Info->get(Opcode: Inst.getOpcode()); |
661 | return (Desc.TSFlags & X86II::EncodingMask) == X86II::EVEX; |
662 | } |
663 | |
664 | std::optional<X86MemOperand> |
665 | evaluateX86MemoryOperand(const MCInst &Inst) const override { |
666 | int MemOpNo = getMemoryOperandNo(Inst); |
667 | if (MemOpNo < 0) |
668 | return std::nullopt; |
669 | unsigned MemOpOffset = static_cast<unsigned>(MemOpNo); |
670 | |
671 | if (MemOpOffset + X86::AddrSegmentReg >= MCPlus::getNumPrimeOperands(Inst)) |
672 | return std::nullopt; |
673 | |
674 | const MCOperand &Base = Inst.getOperand(i: MemOpOffset + X86::AddrBaseReg); |
675 | const MCOperand &Scale = Inst.getOperand(i: MemOpOffset + X86::AddrScaleAmt); |
676 | const MCOperand &Index = Inst.getOperand(i: MemOpOffset + X86::AddrIndexReg); |
677 | const MCOperand &Disp = Inst.getOperand(i: MemOpOffset + X86::AddrDisp); |
678 | const MCOperand &Segment = |
679 | Inst.getOperand(i: MemOpOffset + X86::AddrSegmentReg); |
680 | |
681 | // Make sure it is a well-formed memory operand. |
682 | if (!Base.isReg() || !Scale.isImm() || !Index.isReg() || |
683 | (!Disp.isImm() && !Disp.isExpr()) || !Segment.isReg()) |
684 | return std::nullopt; |
685 | |
686 | X86MemOperand MO; |
687 | MO.BaseRegNum = Base.getReg(); |
688 | MO.ScaleImm = Scale.getImm(); |
689 | MO.IndexRegNum = Index.getReg(); |
690 | MO.DispImm = Disp.isImm() ? Disp.getImm() : 0; |
691 | MO.DispExpr = Disp.isExpr() ? Disp.getExpr() : nullptr; |
692 | MO.SegRegNum = Segment.getReg(); |
693 | return MO; |
694 | } |
695 | |
696 | bool evaluateMemOperandTarget(const MCInst &Inst, uint64_t &Target, |
697 | uint64_t Address, |
698 | uint64_t Size) const override { |
699 | std::optional<X86MemOperand> MO = evaluateX86MemoryOperand(Inst); |
700 | if (!MO) |
701 | return false; |
702 | |
703 | // Make sure it's a well-formed addressing we can statically evaluate. |
704 | if ((MO->BaseRegNum != X86::RIP && MO->BaseRegNum != X86::NoRegister) || |
705 | MO->IndexRegNum != X86::NoRegister || |
706 | MO->SegRegNum != X86::NoRegister || MO->DispExpr) |
707 | return false; |
708 | |
709 | Target = MO->DispImm; |
710 | if (MO->BaseRegNum == X86::RIP) { |
711 | assert(Size != 0 && "instruction size required in order to statically " |
712 | "evaluate RIP-relative address" ); |
713 | Target += Address + Size; |
714 | } |
715 | return true; |
716 | } |
717 | |
718 | MCInst::iterator getMemOperandDisp(MCInst &Inst) const override { |
719 | int MemOpNo = getMemoryOperandNo(Inst); |
720 | if (MemOpNo < 0) |
721 | return Inst.end(); |
722 | return Inst.begin() + (MemOpNo + X86::AddrDisp); |
723 | } |
724 | |
725 | bool replaceMemOperandDisp(MCInst &Inst, MCOperand Operand) const override { |
726 | MCOperand *OI = getMemOperandDisp(Inst); |
727 | if (OI == Inst.end()) |
728 | return false; |
729 | *OI = Operand; |
730 | return true; |
731 | } |
732 | |
733 | /// Get the registers used as function parameters. |
734 | /// This function is specific to the x86_64 abi on Linux. |
735 | BitVector getRegsUsedAsParams() const override { |
736 | BitVector Regs = BitVector(RegInfo->getNumRegs(), false); |
737 | Regs |= getAliases(X86::RSI); |
738 | Regs |= getAliases(X86::RDI); |
739 | Regs |= getAliases(X86::RDX); |
740 | Regs |= getAliases(X86::RCX); |
741 | Regs |= getAliases(X86::R8); |
742 | Regs |= getAliases(X86::R9); |
743 | return Regs; |
744 | } |
745 | |
746 | void getCalleeSavedRegs(BitVector &Regs) const override { |
747 | Regs |= getAliases(X86::RBX); |
748 | Regs |= getAliases(X86::RBP); |
749 | Regs |= getAliases(X86::R12); |
750 | Regs |= getAliases(X86::R13); |
751 | Regs |= getAliases(X86::R14); |
752 | Regs |= getAliases(X86::R15); |
753 | } |
754 | |
755 | void getDefaultDefIn(BitVector &Regs) const override { |
756 | assert(Regs.size() >= RegInfo->getNumRegs() && |
757 | "The size of BitVector is less than RegInfo->getNumRegs()." ); |
758 | Regs.set(X86::RAX); |
759 | Regs.set(X86::RCX); |
760 | Regs.set(X86::RDX); |
761 | Regs.set(X86::RSI); |
762 | Regs.set(X86::RDI); |
763 | Regs.set(X86::R8); |
764 | Regs.set(X86::R9); |
765 | Regs.set(X86::XMM0); |
766 | Regs.set(X86::XMM1); |
767 | Regs.set(X86::XMM2); |
768 | Regs.set(X86::XMM3); |
769 | Regs.set(X86::XMM4); |
770 | Regs.set(X86::XMM5); |
771 | Regs.set(X86::XMM6); |
772 | Regs.set(X86::XMM7); |
773 | } |
774 | |
775 | void getDefaultLiveOut(BitVector &Regs) const override { |
776 | assert(Regs.size() >= RegInfo->getNumRegs() && |
777 | "The size of BitVector is less than RegInfo->getNumRegs()." ); |
778 | Regs |= getAliases(X86::RAX); |
779 | Regs |= getAliases(X86::RDX); |
780 | Regs |= getAliases(X86::RCX); |
781 | Regs |= getAliases(X86::XMM0); |
782 | Regs |= getAliases(X86::XMM1); |
783 | } |
784 | |
785 | void getGPRegs(BitVector &Regs, bool IncludeAlias) const override { |
786 | if (IncludeAlias) { |
787 | Regs |= getAliases(X86::RAX); |
788 | Regs |= getAliases(X86::RBX); |
789 | Regs |= getAliases(X86::RBP); |
790 | Regs |= getAliases(X86::RSI); |
791 | Regs |= getAliases(X86::RDI); |
792 | Regs |= getAliases(X86::RDX); |
793 | Regs |= getAliases(X86::RCX); |
794 | Regs |= getAliases(X86::R8); |
795 | Regs |= getAliases(X86::R9); |
796 | Regs |= getAliases(X86::R10); |
797 | Regs |= getAliases(X86::R11); |
798 | Regs |= getAliases(X86::R12); |
799 | Regs |= getAliases(X86::R13); |
800 | Regs |= getAliases(X86::R14); |
801 | Regs |= getAliases(X86::R15); |
802 | return; |
803 | } |
804 | Regs.set(X86::RAX); |
805 | Regs.set(X86::RBX); |
806 | Regs.set(X86::RBP); |
807 | Regs.set(X86::RSI); |
808 | Regs.set(X86::RDI); |
809 | Regs.set(X86::RDX); |
810 | Regs.set(X86::RCX); |
811 | Regs.set(X86::R8); |
812 | Regs.set(X86::R9); |
813 | Regs.set(X86::R10); |
814 | Regs.set(X86::R11); |
815 | Regs.set(X86::R12); |
816 | Regs.set(X86::R13); |
817 | Regs.set(X86::R14); |
818 | Regs.set(X86::R15); |
819 | } |
820 | |
821 | void getClassicGPRegs(BitVector &Regs) const override { |
822 | Regs |= getAliases(X86::RAX); |
823 | Regs |= getAliases(X86::RBX); |
824 | Regs |= getAliases(X86::RBP); |
825 | Regs |= getAliases(X86::RSI); |
826 | Regs |= getAliases(X86::RDI); |
827 | Regs |= getAliases(X86::RDX); |
828 | Regs |= getAliases(X86::RCX); |
829 | } |
830 | |
831 | void getRepRegs(BitVector &Regs) const override { |
832 | Regs |= getAliases(X86::RCX); |
833 | } |
834 | |
835 | MCPhysReg getAliasSized(MCPhysReg Reg, uint8_t Size) const override { |
836 | Reg = getX86SubSuperRegister(Reg, Size: Size * 8); |
837 | assert((Reg != X86::NoRegister) && "Invalid register" ); |
838 | return Reg; |
839 | } |
840 | |
841 | bool isUpper8BitReg(MCPhysReg Reg) const override { |
842 | switch (Reg) { |
843 | case X86::AH: |
844 | case X86::BH: |
845 | case X86::CH: |
846 | case X86::DH: |
847 | return true; |
848 | default: |
849 | return false; |
850 | } |
851 | } |
852 | |
853 | bool cannotUseREX(const MCInst &Inst) const override { |
854 | switch (Inst.getOpcode()) { |
855 | case X86::MOV8mr_NOREX: |
856 | case X86::MOV8rm_NOREX: |
857 | case X86::MOV8rr_NOREX: |
858 | case X86::MOVSX32rm8_NOREX: |
859 | case X86::MOVSX32rr8_NOREX: |
860 | case X86::MOVZX32rm8_NOREX: |
861 | case X86::MOVZX32rr8_NOREX: |
862 | case X86::MOV8mr: |
863 | case X86::MOV8rm: |
864 | case X86::MOV8rr: |
865 | case X86::MOVSX32rm8: |
866 | case X86::MOVSX32rr8: |
867 | case X86::MOVZX32rm8: |
868 | case X86::MOVZX32rr8: |
869 | case X86::TEST8ri: |
870 | for (const MCOperand &Operand : MCPlus::primeOperands(Inst)) { |
871 | if (!Operand.isReg()) |
872 | continue; |
873 | if (isUpper8BitReg(Reg: Operand.getReg())) |
874 | return true; |
875 | } |
876 | [[fallthrough]]; |
877 | default: |
878 | return false; |
879 | } |
880 | } |
881 | |
882 | static uint8_t getMemDataSize(const MCInst &Inst, int MemOpNo) { |
883 | using namespace llvm::X86; |
884 | int OpType = getOperandType(Inst.getOpcode(), MemOpNo); |
885 | return getMemOperandSize(OpType) / 8; |
886 | } |
887 | |
888 | /// Classifying a stack access as *not* "SIMPLE" here means we don't know how |
889 | /// to change this instruction memory access. It will disable any changes to |
890 | /// the stack layout, so we can't do the most aggressive form of shrink |
891 | /// wrapping. We must do so in a way that keeps the original stack layout. |
892 | /// Otherwise you need to adjust the offset of all instructions accessing the |
893 | /// stack: we can't do that anymore because there is one instruction that is |
894 | /// not simple. There are other implications as well. We have heuristics to |
895 | /// detect when a register is callee-saved and thus eligible for shrink |
896 | /// wrapping. If you are restoring a register using a non-simple stack access, |
897 | /// then it is classified as NOT callee-saved, and it disables shrink wrapping |
898 | /// for *that* register (but not for others). |
899 | /// |
900 | /// Classifying a stack access as "size 0" or detecting an indexed memory |
901 | /// access (to address a vector, for example) here means we know there is a |
902 | /// stack access, but we can't quite understand how wide is the access in |
903 | /// bytes. This is very serious because we can't understand how memory |
904 | /// accesses alias with each other for this function. This will essentially |
905 | /// disable not only shrink wrapping but all frame analysis, it will fail it |
906 | /// as "we don't understand this function and we give up on it". |
907 | bool isStackAccess(const MCInst &Inst, bool &IsLoad, bool &IsStore, |
908 | bool &IsStoreFromReg, MCPhysReg &Reg, int32_t &SrcImm, |
909 | uint16_t &StackPtrReg, int64_t &StackOffset, uint8_t &Size, |
910 | bool &IsSimple, bool &IsIndexed) const override { |
911 | // Detect simple push/pop cases first |
912 | if (int Sz = getPushSize(Inst)) { |
913 | IsLoad = false; |
914 | IsStore = true; |
915 | IsStoreFromReg = true; |
916 | StackPtrReg = X86::RSP; |
917 | StackOffset = -Sz; |
918 | Size = Sz; |
919 | IsSimple = true; |
920 | if (Inst.getOperand(i: 0).isImm()) |
921 | SrcImm = Inst.getOperand(i: 0).getImm(); |
922 | else if (Inst.getOperand(i: 0).isReg()) |
923 | Reg = Inst.getOperand(i: 0).getReg(); |
924 | else |
925 | IsSimple = false; |
926 | |
927 | return true; |
928 | } |
929 | if (int Sz = getPopSize(Inst)) { |
930 | IsLoad = true; |
931 | IsStore = false; |
932 | if (Inst.getNumOperands() == 0 || !Inst.getOperand(i: 0).isReg()) { |
933 | IsSimple = false; |
934 | } else { |
935 | Reg = Inst.getOperand(i: 0).getReg(); |
936 | IsSimple = true; |
937 | } |
938 | StackPtrReg = X86::RSP; |
939 | StackOffset = 0; |
940 | Size = Sz; |
941 | return true; |
942 | } |
943 | |
944 | struct InstInfo { |
945 | // Size in bytes that Inst loads from memory. |
946 | uint8_t DataSize; |
947 | bool IsLoad; |
948 | bool IsStore; |
949 | bool StoreFromReg; |
950 | bool Simple; |
951 | }; |
952 | |
953 | InstInfo I; |
954 | int MemOpNo = getMemoryOperandNo(Inst); |
955 | const MCInstrDesc &MCII = Info->get(Opcode: Inst.getOpcode()); |
956 | // If it is not dealing with a memory operand, we discard it |
957 | if (MemOpNo == -1 || MCII.isCall()) |
958 | return false; |
959 | |
960 | switch (Inst.getOpcode()) { |
961 | default: { |
962 | bool IsLoad = MCII.mayLoad(); |
963 | bool IsStore = MCII.mayStore(); |
964 | // Is it LEA? (deals with memory but is not loading nor storing) |
965 | if (!IsLoad && !IsStore) { |
966 | I = {.DataSize: 0, .IsLoad: IsLoad, .IsStore: IsStore, .StoreFromReg: false, .Simple: false}; |
967 | break; |
968 | } |
969 | uint8_t Sz = getMemDataSize(Inst, MemOpNo); |
970 | I = {.DataSize: Sz, .IsLoad: IsLoad, .IsStore: IsStore, .StoreFromReg: false, .Simple: false}; |
971 | break; |
972 | } |
973 | // Report simple stack accesses |
974 | case X86::MOV8rm: I = {.DataSize: 1, .IsLoad: true, .IsStore: false, .StoreFromReg: false, .Simple: true}; break; |
975 | case X86::MOV16rm: I = {.DataSize: 2, .IsLoad: true, .IsStore: false, .StoreFromReg: false, .Simple: true}; break; |
976 | case X86::MOV32rm: I = {.DataSize: 4, .IsLoad: true, .IsStore: false, .StoreFromReg: false, .Simple: true}; break; |
977 | case X86::MOV64rm: I = {.DataSize: 8, .IsLoad: true, .IsStore: false, .StoreFromReg: false, .Simple: true}; break; |
978 | case X86::MOV8mr: I = {.DataSize: 1, .IsLoad: false, .IsStore: true, .StoreFromReg: true, .Simple: true}; break; |
979 | case X86::MOV16mr: I = {.DataSize: 2, .IsLoad: false, .IsStore: true, .StoreFromReg: true, .Simple: true}; break; |
980 | case X86::MOV32mr: I = {.DataSize: 4, .IsLoad: false, .IsStore: true, .StoreFromReg: true, .Simple: true}; break; |
981 | case X86::MOV64mr: I = {.DataSize: 8, .IsLoad: false, .IsStore: true, .StoreFromReg: true, .Simple: true}; break; |
982 | case X86::MOV8mi: I = {.DataSize: 1, .IsLoad: false, .IsStore: true, .StoreFromReg: false, .Simple: true}; break; |
983 | case X86::MOV16mi: I = {.DataSize: 2, .IsLoad: false, .IsStore: true, .StoreFromReg: false, .Simple: true}; break; |
984 | case X86::MOV32mi: I = {.DataSize: 4, .IsLoad: false, .IsStore: true, .StoreFromReg: false, .Simple: true}; break; |
985 | } // end switch (Inst.getOpcode()) |
986 | |
987 | std::optional<X86MemOperand> MO = evaluateX86MemoryOperand(Inst); |
988 | if (!MO) { |
989 | LLVM_DEBUG(dbgs() << "Evaluate failed on " ); |
990 | LLVM_DEBUG(Inst.dump()); |
991 | return false; |
992 | } |
993 | |
994 | // Make sure it's a stack access |
995 | if (MO->BaseRegNum != X86::RBP && MO->BaseRegNum != X86::RSP) |
996 | return false; |
997 | |
998 | IsLoad = I.IsLoad; |
999 | IsStore = I.IsStore; |
1000 | IsStoreFromReg = I.StoreFromReg; |
1001 | Size = I.DataSize; |
1002 | IsSimple = I.Simple; |
1003 | StackPtrReg = MO->BaseRegNum; |
1004 | StackOffset = MO->DispImm; |
1005 | IsIndexed = |
1006 | MO->IndexRegNum != X86::NoRegister || MO->SegRegNum != X86::NoRegister; |
1007 | |
1008 | if (!I.Simple) |
1009 | return true; |
1010 | |
1011 | // Retrieve related register in simple MOV from/to stack operations. |
1012 | unsigned MemOpOffset = static_cast<unsigned>(MemOpNo); |
1013 | if (I.IsLoad) { |
1014 | MCOperand RegOpnd = Inst.getOperand(i: 0); |
1015 | assert(RegOpnd.isReg() && "unexpected destination operand" ); |
1016 | Reg = RegOpnd.getReg(); |
1017 | } else if (I.IsStore) { |
1018 | MCOperand SrcOpnd = |
1019 | Inst.getOperand(i: MemOpOffset + X86::AddrSegmentReg + 1); |
1020 | if (I.StoreFromReg) { |
1021 | assert(SrcOpnd.isReg() && "unexpected source operand" ); |
1022 | Reg = SrcOpnd.getReg(); |
1023 | } else { |
1024 | assert(SrcOpnd.isImm() && "unexpected source operand" ); |
1025 | SrcImm = SrcOpnd.getImm(); |
1026 | } |
1027 | } |
1028 | |
1029 | return true; |
1030 | } |
1031 | |
1032 | void changeToPushOrPop(MCInst &Inst) const override { |
1033 | assert(!isPush(Inst) && !isPop(Inst)); |
1034 | |
1035 | struct InstInfo { |
1036 | // Size in bytes that Inst loads from memory. |
1037 | uint8_t DataSize; |
1038 | bool IsLoad; |
1039 | bool StoreFromReg; |
1040 | }; |
1041 | |
1042 | InstInfo I; |
1043 | switch (Inst.getOpcode()) { |
1044 | default: { |
1045 | llvm_unreachable("Unhandled opcode" ); |
1046 | return; |
1047 | } |
1048 | case X86::MOV16rm: I = {.DataSize: 2, .IsLoad: true, .StoreFromReg: false}; break; |
1049 | case X86::MOV32rm: I = {.DataSize: 4, .IsLoad: true, .StoreFromReg: false}; break; |
1050 | case X86::MOV64rm: I = {.DataSize: 8, .IsLoad: true, .StoreFromReg: false}; break; |
1051 | case X86::MOV16mr: I = {.DataSize: 2, .IsLoad: false, .StoreFromReg: true}; break; |
1052 | case X86::MOV32mr: I = {.DataSize: 4, .IsLoad: false, .StoreFromReg: true}; break; |
1053 | case X86::MOV64mr: I = {.DataSize: 8, .IsLoad: false, .StoreFromReg: true}; break; |
1054 | case X86::MOV16mi: I = {.DataSize: 2, .IsLoad: false, .StoreFromReg: false}; break; |
1055 | case X86::MOV32mi: I = {.DataSize: 4, .IsLoad: false, .StoreFromReg: false}; break; |
1056 | } // end switch (Inst.getOpcode()) |
1057 | |
1058 | std::optional<X86MemOperand> MO = evaluateX86MemoryOperand(Inst); |
1059 | if (!MO) { |
1060 | llvm_unreachable("Evaluate failed" ); |
1061 | return; |
1062 | } |
1063 | // Make sure it's a stack access |
1064 | if (MO->BaseRegNum != X86::RBP && MO->BaseRegNum != X86::RSP) { |
1065 | llvm_unreachable("Not a stack access" ); |
1066 | return; |
1067 | } |
1068 | |
1069 | unsigned MemOpOffset = getMemoryOperandNo(Inst); |
1070 | unsigned NewOpcode = 0; |
1071 | if (I.IsLoad) { |
1072 | switch (I.DataSize) { |
1073 | case 2: NewOpcode = X86::POP16r; break; |
1074 | case 4: NewOpcode = X86::POP32r; break; |
1075 | case 8: NewOpcode = X86::POP64r; break; |
1076 | default: |
1077 | llvm_unreachable("Unexpected size" ); |
1078 | } |
1079 | unsigned RegOpndNum = Inst.getOperand(i: 0).getReg(); |
1080 | Inst.clear(); |
1081 | Inst.setOpcode(NewOpcode); |
1082 | Inst.addOperand(Op: MCOperand::createReg(Reg: RegOpndNum)); |
1083 | } else { |
1084 | MCOperand SrcOpnd = |
1085 | Inst.getOperand(i: MemOpOffset + X86::AddrSegmentReg + 1); |
1086 | if (I.StoreFromReg) { |
1087 | switch (I.DataSize) { |
1088 | case 2: NewOpcode = X86::PUSH16r; break; |
1089 | case 4: NewOpcode = X86::PUSH32r; break; |
1090 | case 8: NewOpcode = X86::PUSH64r; break; |
1091 | default: |
1092 | llvm_unreachable("Unexpected size" ); |
1093 | } |
1094 | assert(SrcOpnd.isReg() && "Unexpected source operand" ); |
1095 | unsigned RegOpndNum = SrcOpnd.getReg(); |
1096 | Inst.clear(); |
1097 | Inst.setOpcode(NewOpcode); |
1098 | Inst.addOperand(Op: MCOperand::createReg(Reg: RegOpndNum)); |
1099 | } else { |
1100 | switch (I.DataSize) { |
1101 | case 2: NewOpcode = X86::PUSH16i8; break; |
1102 | case 4: NewOpcode = X86::PUSH32i8; break; |
1103 | case 8: NewOpcode = X86::PUSH64i32; break; |
1104 | default: |
1105 | llvm_unreachable("Unexpected size" ); |
1106 | } |
1107 | assert(SrcOpnd.isImm() && "Unexpected source operand" ); |
1108 | int64_t SrcImm = SrcOpnd.getImm(); |
1109 | Inst.clear(); |
1110 | Inst.setOpcode(NewOpcode); |
1111 | Inst.addOperand(Op: MCOperand::createImm(Val: SrcImm)); |
1112 | } |
1113 | } |
1114 | } |
1115 | |
1116 | bool isStackAdjustment(const MCInst &Inst) const override { |
1117 | switch (Inst.getOpcode()) { |
1118 | default: |
1119 | return false; |
1120 | case X86::SUB64ri32: |
1121 | case X86::SUB64ri8: |
1122 | case X86::ADD64ri32: |
1123 | case X86::ADD64ri8: |
1124 | case X86::LEA64r: |
1125 | break; |
1126 | } |
1127 | |
1128 | return any_of(defOperands(Inst), [](const MCOperand &Op) { |
1129 | return Op.isReg() && Op.getReg() == X86::RSP; |
1130 | }); |
1131 | } |
1132 | |
1133 | bool |
1134 | evaluateStackOffsetExpr(const MCInst &Inst, int64_t &Output, |
1135 | std::pair<MCPhysReg, int64_t> Input1, |
1136 | std::pair<MCPhysReg, int64_t> Input2) const override { |
1137 | |
1138 | auto getOperandVal = [&](MCPhysReg Reg) -> ErrorOr<int64_t> { |
1139 | if (Reg == Input1.first) |
1140 | return Input1.second; |
1141 | if (Reg == Input2.first) |
1142 | return Input2.second; |
1143 | return make_error_code(errc::result_out_of_range); |
1144 | }; |
1145 | |
1146 | switch (Inst.getOpcode()) { |
1147 | default: |
1148 | return false; |
1149 | |
1150 | case X86::SUB64ri32: |
1151 | case X86::SUB64ri8: |
1152 | if (!Inst.getOperand(i: 2).isImm()) |
1153 | return false; |
1154 | if (ErrorOr<int64_t> InputVal = |
1155 | getOperandVal(Inst.getOperand(1).getReg())) |
1156 | Output = *InputVal - Inst.getOperand(i: 2).getImm(); |
1157 | else |
1158 | return false; |
1159 | break; |
1160 | case X86::ADD64ri32: |
1161 | case X86::ADD64ri8: |
1162 | if (!Inst.getOperand(i: 2).isImm()) |
1163 | return false; |
1164 | if (ErrorOr<int64_t> InputVal = |
1165 | getOperandVal(Inst.getOperand(1).getReg())) |
1166 | Output = *InputVal + Inst.getOperand(i: 2).getImm(); |
1167 | else |
1168 | return false; |
1169 | break; |
1170 | case X86::ADD64i32: |
1171 | if (!Inst.getOperand(i: 0).isImm()) |
1172 | return false; |
1173 | if (ErrorOr<int64_t> InputVal = getOperandVal(X86::RAX)) |
1174 | Output = *InputVal + Inst.getOperand(i: 0).getImm(); |
1175 | else |
1176 | return false; |
1177 | break; |
1178 | |
1179 | case X86::LEA64r: { |
1180 | std::optional<X86MemOperand> MO = evaluateX86MemoryOperand(Inst); |
1181 | if (!MO) |
1182 | return false; |
1183 | |
1184 | if (MO->BaseRegNum == X86::NoRegister || |
1185 | MO->IndexRegNum != X86::NoRegister || |
1186 | MO->SegRegNum != X86::NoRegister || MO->DispExpr) |
1187 | return false; |
1188 | |
1189 | if (ErrorOr<int64_t> InputVal = getOperandVal(MO->BaseRegNum)) |
1190 | Output = *InputVal + MO->DispImm; |
1191 | else |
1192 | return false; |
1193 | |
1194 | break; |
1195 | } |
1196 | } |
1197 | return true; |
1198 | } |
1199 | |
1200 | bool isRegToRegMove(const MCInst &Inst, MCPhysReg &From, |
1201 | MCPhysReg &To) const override { |
1202 | switch (Inst.getOpcode()) { |
1203 | default: |
1204 | return false; |
1205 | case X86::LEAVE: |
1206 | case X86::LEAVE64: |
1207 | To = getStackPointer(); |
1208 | From = getFramePointer(); |
1209 | return true; |
1210 | case X86::MOV64rr: |
1211 | To = Inst.getOperand(i: 0).getReg(); |
1212 | From = Inst.getOperand(i: 1).getReg(); |
1213 | return true; |
1214 | } |
1215 | } |
1216 | |
1217 | MCPhysReg getStackPointer() const override { return X86::RSP; } |
1218 | MCPhysReg getFramePointer() const override { return X86::RBP; } |
1219 | MCPhysReg getFlagsReg() const override { return X86::EFLAGS; } |
1220 | |
1221 | bool escapesVariable(const MCInst &Inst, |
1222 | bool HasFramePointer) const override { |
1223 | int MemOpNo = getMemoryOperandNo(Inst); |
1224 | const MCInstrDesc &MCII = Info->get(Opcode: Inst.getOpcode()); |
1225 | const unsigned NumDefs = MCII.getNumDefs(); |
1226 | static BitVector SPBPAliases(BitVector(getAliases(X86::RSP)) |= |
1227 | getAliases(X86::RBP)); |
1228 | static BitVector SPAliases(getAliases(X86::RSP)); |
1229 | |
1230 | // FIXME: PUSH can be technically a leak, but let's ignore this for now |
1231 | // because a lot of harmless prologue code will spill SP to the stack. |
1232 | // Unless push is clearly pushing an object address to the stack as |
1233 | // demonstrated by having a MemOp. |
1234 | bool IsPush = isPush(Inst); |
1235 | if (IsPush && MemOpNo == -1) |
1236 | return false; |
1237 | |
1238 | // We use this to detect LEA (has memop but does not access mem) |
1239 | bool AccessMem = MCII.mayLoad() || MCII.mayStore(); |
1240 | bool DoesLeak = false; |
1241 | for (int I = 0, E = MCPlus::getNumPrimeOperands(Inst); I != E; ++I) { |
1242 | // Ignore if SP/BP is used to dereference memory -- that's fine |
1243 | if (MemOpNo != -1 && !IsPush && AccessMem && I >= MemOpNo && |
1244 | I <= MemOpNo + 5) |
1245 | continue; |
1246 | // Ignore if someone is writing to SP/BP |
1247 | if (I < static_cast<int>(NumDefs)) |
1248 | continue; |
1249 | |
1250 | const MCOperand &Operand = Inst.getOperand(i: I); |
1251 | if (HasFramePointer && Operand.isReg() && SPBPAliases[Operand.getReg()]) { |
1252 | DoesLeak = true; |
1253 | break; |
1254 | } |
1255 | if (!HasFramePointer && Operand.isReg() && SPAliases[Operand.getReg()]) { |
1256 | DoesLeak = true; |
1257 | break; |
1258 | } |
1259 | } |
1260 | |
1261 | // If potential leak, check if it is not just writing to itself/sp/bp |
1262 | if (DoesLeak) { |
1263 | DoesLeak = !any_of(defOperands(Inst), [&](const MCOperand &Operand) { |
1264 | assert(Operand.isReg()); |
1265 | MCPhysReg Reg = Operand.getReg(); |
1266 | return HasFramePointer ? SPBPAliases[Reg] : SPAliases[Reg]; |
1267 | }); |
1268 | } |
1269 | return DoesLeak; |
1270 | } |
1271 | |
1272 | bool addToImm(MCInst &Inst, int64_t &Amt, MCContext *Ctx) const override { |
1273 | unsigned ImmOpNo = -1U; |
1274 | int MemOpNo = getMemoryOperandNo(Inst); |
1275 | if (MemOpNo != -1) |
1276 | ImmOpNo = MemOpNo + X86::AddrDisp; |
1277 | else |
1278 | for (unsigned Index = 0; Index < MCPlus::getNumPrimeOperands(Inst); |
1279 | ++Index) |
1280 | if (Inst.getOperand(i: Index).isImm()) |
1281 | ImmOpNo = Index; |
1282 | if (ImmOpNo == -1U) |
1283 | return false; |
1284 | |
1285 | MCOperand &Operand = Inst.getOperand(i: ImmOpNo); |
1286 | Amt += Operand.getImm(); |
1287 | Operand.setImm(Amt); |
1288 | // Check for the need for relaxation |
1289 | if (int64_t(Amt) == int64_t(int8_t(Amt))) |
1290 | return true; |
1291 | |
1292 | // Relax instruction |
1293 | switch (Inst.getOpcode()) { |
1294 | case X86::SUB64ri8: |
1295 | Inst.setOpcode(X86::SUB64ri32); |
1296 | break; |
1297 | case X86::ADD64ri8: |
1298 | Inst.setOpcode(X86::ADD64ri32); |
1299 | break; |
1300 | default: |
1301 | // No need for relaxation |
1302 | break; |
1303 | } |
1304 | return true; |
1305 | } |
1306 | |
1307 | /// TODO: this implementation currently works for the most common opcodes that |
1308 | /// load from memory. It can be extended to work with memory store opcodes as |
1309 | /// well as more memory load opcodes. |
1310 | bool replaceMemOperandWithImm(MCInst &Inst, StringRef ConstantData, |
1311 | uint64_t Offset) const override { |
1312 | enum CheckSignExt : uint8_t { |
1313 | NOCHECK = 0, |
1314 | CHECK8, |
1315 | CHECK32, |
1316 | }; |
1317 | |
1318 | using CheckList = std::vector<std::pair<CheckSignExt, unsigned>>; |
1319 | struct InstInfo { |
1320 | // Size in bytes that Inst loads from memory. |
1321 | uint8_t DataSize; |
1322 | |
1323 | // True when the target operand has to be duplicated because the opcode |
1324 | // expects a LHS operand. |
1325 | bool HasLHS; |
1326 | |
1327 | // List of checks and corresponding opcodes to be used. We try to use the |
1328 | // smallest possible immediate value when various sizes are available, |
1329 | // hence we may need to check whether a larger constant fits in a smaller |
1330 | // immediate. |
1331 | CheckList Checks; |
1332 | }; |
1333 | |
1334 | InstInfo I; |
1335 | |
1336 | switch (Inst.getOpcode()) { |
1337 | default: { |
1338 | switch (getPopSize(Inst)) { |
1339 | case 2: I = {2, false, {{NOCHECK, X86::MOV16ri}}}; break; |
1340 | case 4: I = {4, false, {{NOCHECK, X86::MOV32ri}}}; break; |
1341 | case 8: I = {8, false, {{CHECK32, X86::MOV64ri32}, |
1342 | {NOCHECK, X86::MOV64rm}}}; break; |
1343 | default: return false; |
1344 | } |
1345 | break; |
1346 | } |
1347 | |
1348 | // MOV |
1349 | case X86::MOV8rm: I = {1, false, {{NOCHECK, X86::MOV8ri}}}; break; |
1350 | case X86::MOV16rm: I = {2, false, {{NOCHECK, X86::MOV16ri}}}; break; |
1351 | case X86::MOV32rm: I = {4, false, {{NOCHECK, X86::MOV32ri}}}; break; |
1352 | case X86::MOV64rm: I = {8, false, {{CHECK32, X86::MOV64ri32}, |
1353 | {NOCHECK, X86::MOV64rm}}}; break; |
1354 | |
1355 | // MOVZX |
1356 | case X86::MOVZX16rm8: I = {1, false, {{NOCHECK, X86::MOV16ri}}}; break; |
1357 | case X86::MOVZX32rm8: I = {1, false, {{NOCHECK, X86::MOV32ri}}}; break; |
1358 | case X86::MOVZX32rm16: I = {2, false, {{NOCHECK, X86::MOV32ri}}}; break; |
1359 | |
1360 | // CMP |
1361 | case X86::CMP8rm: I = {1, false, {{NOCHECK, X86::CMP8ri}}}; break; |
1362 | case X86::CMP16rm: I = {2, false, {{CHECK8, X86::CMP16ri8}, |
1363 | {NOCHECK, X86::CMP16ri}}}; break; |
1364 | case X86::CMP32rm: I = {4, false, {{CHECK8, X86::CMP32ri8}, |
1365 | {NOCHECK, X86::CMP32ri}}}; break; |
1366 | case X86::CMP64rm: I = {8, false, {{CHECK8, X86::CMP64ri8}, |
1367 | {CHECK32, X86::CMP64ri32}, |
1368 | {NOCHECK, X86::CMP64rm}}}; break; |
1369 | |
1370 | // TEST |
1371 | case X86::TEST8mr: I = {1, false, {{NOCHECK, X86::TEST8ri}}}; break; |
1372 | case X86::TEST16mr: I = {2, false, {{NOCHECK, X86::TEST16ri}}}; break; |
1373 | case X86::TEST32mr: I = {4, false, {{NOCHECK, X86::TEST32ri}}}; break; |
1374 | case X86::TEST64mr: I = {8, false, {{CHECK32, X86::TEST64ri32}, |
1375 | {NOCHECK, X86::TEST64mr}}}; break; |
1376 | |
1377 | // ADD |
1378 | case X86::ADD8rm: I = {1, true, {{NOCHECK, X86::ADD8ri}}}; break; |
1379 | case X86::ADD16rm: I = {2, true, {{CHECK8, X86::ADD16ri8}, |
1380 | {NOCHECK, X86::ADD16ri}}}; break; |
1381 | case X86::ADD32rm: I = {4, true, {{CHECK8, X86::ADD32ri8}, |
1382 | {NOCHECK, X86::ADD32ri}}}; break; |
1383 | case X86::ADD64rm: I = {8, true, {{CHECK8, X86::ADD64ri8}, |
1384 | {CHECK32, X86::ADD64ri32}, |
1385 | {NOCHECK, X86::ADD64rm}}}; break; |
1386 | |
1387 | // SUB |
1388 | case X86::SUB8rm: I = {1, true, {{NOCHECK, X86::SUB8ri}}}; break; |
1389 | case X86::SUB16rm: I = {2, true, {{CHECK8, X86::SUB16ri8}, |
1390 | {NOCHECK, X86::SUB16ri}}}; break; |
1391 | case X86::SUB32rm: I = {4, true, {{CHECK8, X86::SUB32ri8}, |
1392 | {NOCHECK, X86::SUB32ri}}}; break; |
1393 | case X86::SUB64rm: I = {8, true, {{CHECK8, X86::SUB64ri8}, |
1394 | {CHECK32, X86::SUB64ri32}, |
1395 | {NOCHECK, X86::SUB64rm}}}; break; |
1396 | |
1397 | // AND |
1398 | case X86::AND8rm: I = {1, true, {{NOCHECK, X86::AND8ri}}}; break; |
1399 | case X86::AND16rm: I = {2, true, {{CHECK8, X86::AND16ri8}, |
1400 | {NOCHECK, X86::AND16ri}}}; break; |
1401 | case X86::AND32rm: I = {4, true, {{CHECK8, X86::AND32ri8}, |
1402 | {NOCHECK, X86::AND32ri}}}; break; |
1403 | case X86::AND64rm: I = {8, true, {{CHECK8, X86::AND64ri8}, |
1404 | {CHECK32, X86::AND64ri32}, |
1405 | {NOCHECK, X86::AND64rm}}}; break; |
1406 | |
1407 | // OR |
1408 | case X86::OR8rm: I = {1, true, {{NOCHECK, X86::OR8ri}}}; break; |
1409 | case X86::OR16rm: I = {2, true, {{CHECK8, X86::OR16ri8}, |
1410 | {NOCHECK, X86::OR16ri}}}; break; |
1411 | case X86::OR32rm: I = {4, true, {{CHECK8, X86::OR32ri8}, |
1412 | {NOCHECK, X86::OR32ri}}}; break; |
1413 | case X86::OR64rm: I = {8, true, {{CHECK8, X86::OR64ri8}, |
1414 | {CHECK32, X86::OR64ri32}, |
1415 | {NOCHECK, X86::OR64rm}}}; break; |
1416 | |
1417 | // XOR |
1418 | case X86::XOR8rm: I = {1, true, {{NOCHECK, X86::XOR8ri}}}; break; |
1419 | case X86::XOR16rm: I = {2, true, {{CHECK8, X86::XOR16ri8}, |
1420 | {NOCHECK, X86::XOR16ri}}}; break; |
1421 | case X86::XOR32rm: I = {4, true, {{CHECK8, X86::XOR32ri8}, |
1422 | {NOCHECK, X86::XOR32ri}}}; break; |
1423 | case X86::XOR64rm: I = {8, true, {{CHECK8, X86::XOR64ri8}, |
1424 | {CHECK32, X86::XOR64ri32}, |
1425 | {NOCHECK, X86::XOR64rm}}}; break; |
1426 | } |
1427 | |
1428 | // Compute the immediate value. |
1429 | assert(Offset + I.DataSize <= ConstantData.size() && |
1430 | "invalid offset for given constant data" ); |
1431 | int64_t ImmVal = |
1432 | DataExtractor(ConstantData, true, 8).getSigned(offset_ptr: &Offset, size: I.DataSize); |
1433 | |
1434 | // Compute the new opcode. |
1435 | unsigned NewOpcode = 0; |
1436 | for (const std::pair<CheckSignExt, unsigned> &Check : I.Checks) { |
1437 | NewOpcode = Check.second; |
1438 | if (Check.first == NOCHECK) |
1439 | break; |
1440 | if (Check.first == CHECK8 && isInt<8>(ImmVal)) |
1441 | break; |
1442 | if (Check.first == CHECK32 && isInt<32>(ImmVal)) |
1443 | break; |
1444 | } |
1445 | if (NewOpcode == Inst.getOpcode()) |
1446 | return false; |
1447 | |
1448 | // Modify the instruction. |
1449 | MCOperand ImmOp = MCOperand::createImm(Val: ImmVal); |
1450 | uint32_t TargetOpNum = 0; |
1451 | // Test instruction does not follow the regular pattern of putting the |
1452 | // memory reference of a load (5 MCOperands) last in the list of operands. |
1453 | // Since it is not modifying the register operand, it is not treated as |
1454 | // a destination operand and it is not the first operand as it is in the |
1455 | // other instructions we treat here. |
1456 | if (NewOpcode == X86::TEST8ri || NewOpcode == X86::TEST16ri || |
1457 | NewOpcode == X86::TEST32ri || NewOpcode == X86::TEST64ri32) |
1458 | TargetOpNum = getMemoryOperandNo(Inst) + X86::AddrNumOperands; |
1459 | |
1460 | MCOperand TargetOp = Inst.getOperand(i: TargetOpNum); |
1461 | Inst.clear(); |
1462 | Inst.setOpcode(NewOpcode); |
1463 | Inst.addOperand(Op: TargetOp); |
1464 | if (I.HasLHS) |
1465 | Inst.addOperand(Op: TargetOp); |
1466 | Inst.addOperand(Op: ImmOp); |
1467 | |
1468 | return true; |
1469 | } |
1470 | |
1471 | /// TODO: this implementation currently works for the most common opcodes that |
1472 | /// load from memory. It can be extended to work with memory store opcodes as |
1473 | /// well as more memory load opcodes. |
1474 | bool replaceMemOperandWithReg(MCInst &Inst, MCPhysReg RegNum) const override { |
1475 | unsigned NewOpcode; |
1476 | |
1477 | switch (Inst.getOpcode()) { |
1478 | default: { |
1479 | switch (getPopSize(Inst)) { |
1480 | case 2: NewOpcode = X86::MOV16rr; break; |
1481 | case 4: NewOpcode = X86::MOV32rr; break; |
1482 | case 8: NewOpcode = X86::MOV64rr; break; |
1483 | default: return false; |
1484 | } |
1485 | break; |
1486 | } |
1487 | |
1488 | // MOV |
1489 | case X86::MOV8rm: NewOpcode = X86::MOV8rr; break; |
1490 | case X86::MOV16rm: NewOpcode = X86::MOV16rr; break; |
1491 | case X86::MOV32rm: NewOpcode = X86::MOV32rr; break; |
1492 | case X86::MOV64rm: NewOpcode = X86::MOV64rr; break; |
1493 | } |
1494 | |
1495 | // Modify the instruction. |
1496 | MCOperand RegOp = MCOperand::createReg(Reg: RegNum); |
1497 | MCOperand TargetOp = Inst.getOperand(i: 0); |
1498 | Inst.clear(); |
1499 | Inst.setOpcode(NewOpcode); |
1500 | Inst.addOperand(Op: TargetOp); |
1501 | Inst.addOperand(Op: RegOp); |
1502 | |
1503 | return true; |
1504 | } |
1505 | |
1506 | bool isRedundantMove(const MCInst &Inst) const override { |
1507 | switch (Inst.getOpcode()) { |
1508 | default: |
1509 | return false; |
1510 | |
1511 | // MOV |
1512 | case X86::MOV8rr: |
1513 | case X86::MOV16rr: |
1514 | case X86::MOV32rr: |
1515 | case X86::MOV64rr: |
1516 | break; |
1517 | } |
1518 | |
1519 | assert(Inst.getOperand(0).isReg() && Inst.getOperand(1).isReg()); |
1520 | return Inst.getOperand(i: 0).getReg() == Inst.getOperand(i: 1).getReg(); |
1521 | } |
1522 | |
1523 | bool requiresAlignedAddress(const MCInst &Inst) const override { |
1524 | const MCInstrDesc &Desc = Info->get(Opcode: Inst.getOpcode()); |
1525 | for (unsigned int I = 0; I < Desc.getNumOperands(); ++I) { |
1526 | const MCOperandInfo &Op = Desc.operands()[I]; |
1527 | if (Op.OperandType != MCOI::OPERAND_REGISTER) |
1528 | continue; |
1529 | if (Op.RegClass == X86::VR128RegClassID) |
1530 | return true; |
1531 | } |
1532 | return false; |
1533 | } |
1534 | |
1535 | bool convertJmpToTailCall(MCInst &Inst) override { |
1536 | if (isTailCall(Inst)) |
1537 | return false; |
1538 | |
1539 | int NewOpcode; |
1540 | switch (Inst.getOpcode()) { |
1541 | default: |
1542 | return false; |
1543 | case X86::JMP_1: |
1544 | case X86::JMP_2: |
1545 | case X86::JMP_4: |
1546 | NewOpcode = X86::JMP_4; |
1547 | break; |
1548 | case X86::JMP16m: |
1549 | case X86::JMP32m: |
1550 | case X86::JMP64m: |
1551 | NewOpcode = X86::JMP32m; |
1552 | break; |
1553 | case X86::JMP16r: |
1554 | case X86::JMP32r: |
1555 | case X86::JMP64r: |
1556 | NewOpcode = X86::JMP32r; |
1557 | break; |
1558 | } |
1559 | |
1560 | Inst.setOpcode(NewOpcode); |
1561 | setTailCall(Inst); |
1562 | return true; |
1563 | } |
1564 | |
1565 | bool convertTailCallToJmp(MCInst &Inst) override { |
1566 | int NewOpcode; |
1567 | switch (Inst.getOpcode()) { |
1568 | default: |
1569 | return false; |
1570 | case X86::JMP_4: |
1571 | NewOpcode = X86::JMP_1; |
1572 | break; |
1573 | case X86::JMP32m: |
1574 | NewOpcode = X86::JMP64m; |
1575 | break; |
1576 | case X86::JMP32r: |
1577 | NewOpcode = X86::JMP64r; |
1578 | break; |
1579 | } |
1580 | |
1581 | Inst.setOpcode(NewOpcode); |
1582 | removeAnnotation(Inst, Index: MCPlus::MCAnnotation::kTailCall); |
1583 | clearOffset(Inst); |
1584 | return true; |
1585 | } |
1586 | |
1587 | bool convertTailCallToCall(MCInst &Inst) override { |
1588 | int NewOpcode; |
1589 | switch (Inst.getOpcode()) { |
1590 | default: |
1591 | return false; |
1592 | case X86::JMP_4: |
1593 | NewOpcode = X86::CALL64pcrel32; |
1594 | break; |
1595 | case X86::JMP32m: |
1596 | NewOpcode = X86::CALL64m; |
1597 | break; |
1598 | case X86::JMP32r: |
1599 | NewOpcode = X86::CALL64r; |
1600 | break; |
1601 | } |
1602 | |
1603 | Inst.setOpcode(NewOpcode); |
1604 | removeAnnotation(Inst, Index: MCPlus::MCAnnotation::kTailCall); |
1605 | return true; |
1606 | } |
1607 | |
1608 | InstructionListType createIndirectPLTCall(MCInst &&DirectCall, |
1609 | const MCSymbol *TargetLocation, |
1610 | MCContext *Ctx) override { |
1611 | assert((DirectCall.getOpcode() == X86::CALL64pcrel32 || |
1612 | (DirectCall.getOpcode() == X86::JMP_4 && isTailCall(DirectCall))) && |
1613 | "64-bit direct (tail) call instruction expected" ); |
1614 | |
1615 | InstructionListType Code; |
1616 | // Create a new indirect call by converting the previous direct call. |
1617 | MCInst Inst = DirectCall; |
1618 | const auto NewOpcode = |
1619 | (Inst.getOpcode() == X86::CALL64pcrel32) ? X86::CALL64m : X86::JMP32m; |
1620 | Inst.setOpcode(NewOpcode); |
1621 | |
1622 | // Replace the first operand and preserve auxiliary operands of |
1623 | // the instruction. |
1624 | Inst.erase(I: Inst.begin()); |
1625 | Inst.insert(Inst.begin(), |
1626 | MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg |
1627 | Inst.insert(I: Inst.begin(), |
1628 | Op: MCOperand::createExpr( // Displacement |
1629 | Val: MCSymbolRefExpr::create(Symbol: TargetLocation, |
1630 | Kind: MCSymbolRefExpr::VK_None, Ctx&: *Ctx))); |
1631 | Inst.insert(Inst.begin(), |
1632 | MCOperand::createReg(X86::NoRegister)); // IndexReg |
1633 | Inst.insert(I: Inst.begin(), |
1634 | Op: MCOperand::createImm(Val: 1)); // ScaleAmt |
1635 | Inst.insert(Inst.begin(), |
1636 | MCOperand::createReg(X86::RIP)); // BaseReg |
1637 | |
1638 | Code.emplace_back(Inst); |
1639 | return Code; |
1640 | } |
1641 | |
1642 | void convertIndirectCallToLoad(MCInst &Inst, MCPhysReg Reg) override { |
1643 | bool IsTailCall = isTailCall(Inst); |
1644 | if (IsTailCall) |
1645 | removeAnnotation(Inst, Index: MCPlus::MCAnnotation::kTailCall); |
1646 | if (Inst.getOpcode() == X86::CALL64m || |
1647 | (Inst.getOpcode() == X86::JMP32m && IsTailCall)) { |
1648 | Inst.setOpcode(X86::MOV64rm); |
1649 | Inst.insert(I: Inst.begin(), Op: MCOperand::createReg(Reg)); |
1650 | return; |
1651 | } |
1652 | if (Inst.getOpcode() == X86::CALL64r || |
1653 | (Inst.getOpcode() == X86::JMP32r && IsTailCall)) { |
1654 | Inst.setOpcode(X86::MOV64rr); |
1655 | Inst.insert(I: Inst.begin(), Op: MCOperand::createReg(Reg)); |
1656 | return; |
1657 | } |
1658 | LLVM_DEBUG(Inst.dump()); |
1659 | llvm_unreachable("not implemented" ); |
1660 | } |
1661 | |
1662 | bool shortenInstruction(MCInst &Inst, |
1663 | const MCSubtargetInfo &STI) const override { |
1664 | unsigned OldOpcode = Inst.getOpcode(); |
1665 | unsigned NewOpcode = OldOpcode; |
1666 | |
1667 | int MemOpNo = getMemoryOperandNo(Inst); |
1668 | |
1669 | // Check and remove redundant Address-Size override prefix. |
1670 | if (opts::X86StripRedundantAddressSize) { |
1671 | uint64_t TSFlags = Info->get(Opcode: OldOpcode).TSFlags; |
1672 | unsigned Flags = Inst.getFlags(); |
1673 | |
1674 | if (!X86_MC::needsAddressSizeOverride(MI: Inst, STI, MemoryOperand: MemOpNo, TSFlags) && |
1675 | Flags & X86::IP_HAS_AD_SIZE) |
1676 | Inst.setFlags(Flags ^ X86::IP_HAS_AD_SIZE); |
1677 | } |
1678 | |
1679 | // Check and remove EIZ/RIZ. These cases represent ambiguous cases where |
1680 | // SIB byte is present, but no index is used and modrm alone should have |
1681 | // been enough. Converting to NoRegister effectively removes the SIB byte. |
1682 | if (MemOpNo >= 0) { |
1683 | MCOperand &IndexOp = |
1684 | Inst.getOperand(i: static_cast<unsigned>(MemOpNo) + X86::AddrIndexReg); |
1685 | if (IndexOp.getReg() == X86::EIZ || IndexOp.getReg() == X86::RIZ) |
1686 | IndexOp = MCOperand::createReg(X86::NoRegister); |
1687 | } |
1688 | |
1689 | if (isBranch(Inst)) { |
1690 | NewOpcode = getShortBranchOpcode(Opcode: OldOpcode); |
1691 | } else if (OldOpcode == X86::MOV64ri) { |
1692 | if (Inst.getOperand(i: MCPlus::getNumPrimeOperands(Inst) - 1).isImm()) { |
1693 | const int64_t Imm = |
1694 | Inst.getOperand(i: MCPlus::getNumPrimeOperands(Inst) - 1).getImm(); |
1695 | if (int64_t(Imm) == int64_t(int32_t(Imm))) |
1696 | NewOpcode = X86::MOV64ri32; |
1697 | } |
1698 | } else { |
1699 | // If it's arithmetic instruction check if signed operand fits in 1 byte. |
1700 | const unsigned ShortOpcode = X86::getOpcodeForShortImmediateForm(Opcode: OldOpcode); |
1701 | if (ShortOpcode != OldOpcode && |
1702 | Inst.getOperand(i: MCPlus::getNumPrimeOperands(Inst) - 1).isImm()) { |
1703 | int64_t Imm = |
1704 | Inst.getOperand(i: MCPlus::getNumPrimeOperands(Inst) - 1).getImm(); |
1705 | if (int64_t(Imm) == int64_t(int8_t(Imm))) |
1706 | NewOpcode = ShortOpcode; |
1707 | } |
1708 | } |
1709 | |
1710 | if (NewOpcode == OldOpcode) |
1711 | return false; |
1712 | |
1713 | Inst.setOpcode(NewOpcode); |
1714 | return true; |
1715 | } |
1716 | |
1717 | bool |
1718 | convertMoveToConditionalMove(MCInst &Inst, unsigned CC, bool AllowStackMemOp, |
1719 | bool AllowBasePtrStackMemOp) const override { |
1720 | // - Register-register moves are OK |
1721 | // - Stores are filtered out by opcode (no store CMOV) |
1722 | // - Non-stack loads are prohibited (generally unsafe) |
1723 | // - Stack loads are OK if AllowStackMemOp is true |
1724 | // - Stack loads with RBP are OK if AllowBasePtrStackMemOp is true |
1725 | if (mayLoad(Inst)) { |
1726 | // If stack memory operands are not allowed, no loads are allowed |
1727 | if (!AllowStackMemOp) |
1728 | return false; |
1729 | |
1730 | // If stack memory operands are allowed, check if it's a load from stack |
1731 | bool IsLoad, IsStore, IsStoreFromReg, IsSimple, IsIndexed; |
1732 | MCPhysReg Reg; |
1733 | int32_t SrcImm; |
1734 | uint16_t StackPtrReg; |
1735 | int64_t StackOffset; |
1736 | uint8_t Size; |
1737 | bool IsStackAccess = |
1738 | isStackAccess(Inst, IsLoad, IsStore, IsStoreFromReg, Reg, SrcImm, |
1739 | StackPtrReg, StackOffset, Size, IsSimple, IsIndexed); |
1740 | // Prohibit non-stack-based loads |
1741 | if (!IsStackAccess) |
1742 | return false; |
1743 | // If stack memory operands are allowed, check if it's RBP-based |
1744 | if (!AllowBasePtrStackMemOp && |
1745 | RegInfo->isSubRegisterEq(X86::RBP, StackPtrReg)) |
1746 | return false; |
1747 | } |
1748 | |
1749 | unsigned NewOpcode = 0; |
1750 | switch (Inst.getOpcode()) { |
1751 | case X86::MOV16rr: |
1752 | NewOpcode = X86::CMOV16rr; |
1753 | break; |
1754 | case X86::MOV16rm: |
1755 | NewOpcode = X86::CMOV16rm; |
1756 | break; |
1757 | case X86::MOV32rr: |
1758 | NewOpcode = X86::CMOV32rr; |
1759 | break; |
1760 | case X86::MOV32rm: |
1761 | NewOpcode = X86::CMOV32rm; |
1762 | break; |
1763 | case X86::MOV64rr: |
1764 | NewOpcode = X86::CMOV64rr; |
1765 | break; |
1766 | case X86::MOV64rm: |
1767 | NewOpcode = X86::CMOV64rm; |
1768 | break; |
1769 | default: |
1770 | return false; |
1771 | } |
1772 | Inst.setOpcode(NewOpcode); |
1773 | // Insert CC at the end of prime operands, before annotations |
1774 | Inst.insert(I: Inst.begin() + MCPlus::getNumPrimeOperands(Inst), |
1775 | Op: MCOperand::createImm(Val: CC)); |
1776 | // CMOV is a 3-operand MCInst, so duplicate the destination as src1 |
1777 | Inst.insert(I: Inst.begin(), Op: Inst.getOperand(i: 0)); |
1778 | return true; |
1779 | } |
1780 | |
1781 | bool lowerTailCall(MCInst &Inst) override { |
1782 | if (Inst.getOpcode() == X86::JMP_4 && isTailCall(Inst)) { |
1783 | Inst.setOpcode(X86::JMP_1); |
1784 | removeAnnotation(Inst, Index: MCPlus::MCAnnotation::kTailCall); |
1785 | return true; |
1786 | } |
1787 | return false; |
1788 | } |
1789 | |
1790 | const MCSymbol *getTargetSymbol(const MCInst &Inst, |
1791 | unsigned OpNum = 0) const override { |
1792 | if (OpNum >= MCPlus::getNumPrimeOperands(Inst)) |
1793 | return nullptr; |
1794 | |
1795 | const MCOperand &Op = Inst.getOperand(i: OpNum); |
1796 | if (!Op.isExpr()) |
1797 | return nullptr; |
1798 | |
1799 | return MCPlusBuilder::getTargetSymbol(Expr: Op.getExpr()); |
1800 | } |
1801 | |
1802 | bool analyzeBranch(InstructionIterator Begin, InstructionIterator End, |
1803 | const MCSymbol *&TBB, const MCSymbol *&FBB, |
1804 | MCInst *&CondBranch, |
1805 | MCInst *&UncondBranch) const override { |
1806 | auto I = End; |
1807 | |
1808 | // Bottom-up analysis |
1809 | while (I != Begin) { |
1810 | --I; |
1811 | |
1812 | // Ignore nops and CFIs |
1813 | if (isPseudo(Inst: *I)) |
1814 | continue; |
1815 | |
1816 | // Stop when we find the first non-terminator |
1817 | if (!isTerminator(Inst: *I)) |
1818 | break; |
1819 | |
1820 | if (!isBranch(Inst: *I)) |
1821 | break; |
1822 | |
1823 | // Handle unconditional branches. |
1824 | if ((I->getOpcode() == X86::JMP_1 || I->getOpcode() == X86::JMP_2 || |
1825 | I->getOpcode() == X86::JMP_4) && |
1826 | !isTailCall(*I)) { |
1827 | // If any code was seen after this unconditional branch, we've seen |
1828 | // unreachable code. Ignore them. |
1829 | CondBranch = nullptr; |
1830 | UncondBranch = &*I; |
1831 | const MCSymbol *Sym = getTargetSymbol(Inst: *I); |
1832 | assert(Sym != nullptr && |
1833 | "Couldn't extract BB symbol from jump operand" ); |
1834 | TBB = Sym; |
1835 | continue; |
1836 | } |
1837 | |
1838 | // Ignore indirect branches |
1839 | if (getCondCode(Inst: *I) == X86::COND_INVALID) |
1840 | return false; |
1841 | |
1842 | if (CondBranch == nullptr) { |
1843 | const MCSymbol *TargetBB = getTargetSymbol(Inst: *I); |
1844 | if (TargetBB == nullptr) { |
1845 | // Unrecognized branch target |
1846 | return false; |
1847 | } |
1848 | FBB = TBB; |
1849 | TBB = TargetBB; |
1850 | CondBranch = &*I; |
1851 | continue; |
1852 | } |
1853 | |
1854 | llvm_unreachable("multiple conditional branches in one BB" ); |
1855 | } |
1856 | return true; |
1857 | } |
1858 | |
1859 | /// Analyzes PIC-style jump table code template and return identified |
1860 | /// IndirectBranchType, MemLocInstr (all cases) and FixedEntryLoadInstr |
1861 | /// (POSSIBLE_PIC_FIXED_BRANCH case). |
1862 | template <typename Itr> |
1863 | std::tuple<IndirectBranchType, MCInst *, MCInst *> |
1864 | analyzePICJumpTable(Itr II, Itr IE, MCPhysReg R1, MCPhysReg R2) const { |
1865 | // Analyze PIC-style jump table code template: |
1866 | // |
1867 | // lea PIC_JUMP_TABLE(%rip), {%r1|%r2} <- MemLocInstr |
1868 | // mov ({%r1|%r2}, %index, 4), {%r2|%r1} |
1869 | // add %r2, %r1 |
1870 | // jmp *%r1 |
1871 | // |
1872 | // or a fixed indirect jump template: |
1873 | // |
1874 | // movslq En(%rip), {%r2|%r1} <- FixedEntryLoadInstr |
1875 | // lea PIC_JUMP_TABLE(%rip), {%r1|%r2} <- MemLocInstr |
1876 | // add %r2, %r1 |
1877 | // jmp *%r1 |
1878 | // |
1879 | // (with any irrelevant instructions in-between) |
1880 | // |
1881 | // When we call this helper we've already determined %r1 and %r2, and |
1882 | // reverse instruction iterator \p II is pointing to the ADD instruction. |
1883 | // |
1884 | // PIC jump table looks like following: |
1885 | // |
1886 | // JT: ---------- |
1887 | // E1:| L1 - JT | |
1888 | // |----------| |
1889 | // E2:| L2 - JT | |
1890 | // |----------| |
1891 | // | | |
1892 | // ...... |
1893 | // En:| Ln - JT | |
1894 | // ---------- |
1895 | // |
1896 | // Where L1, L2, ..., Ln represent labels in the function. |
1897 | // |
1898 | // The actual relocations in the table will be of the form: |
1899 | // |
1900 | // Ln - JT |
1901 | // = (Ln - En) + (En - JT) |
1902 | // = R_X86_64_PC32(Ln) + En - JT |
1903 | // = R_X86_64_PC32(Ln + offsetof(En)) |
1904 | // |
1905 | auto isRIPRel = [&](X86MemOperand &MO) { |
1906 | // NB: DispExpr should be set |
1907 | return MO.DispExpr != nullptr && |
1908 | MO.BaseRegNum == RegInfo->getProgramCounter() && |
1909 | MO.IndexRegNum == X86::NoRegister && |
1910 | MO.SegRegNum == X86::NoRegister; |
1911 | }; |
1912 | auto isIndexed = [](X86MemOperand &MO, MCPhysReg R) { |
1913 | // NB: IndexRegNum should be set. |
1914 | return MO.IndexRegNum != X86::NoRegister && MO.BaseRegNum == R && |
1915 | MO.ScaleImm == 4 && MO.DispImm == 0 && |
1916 | MO.SegRegNum == X86::NoRegister; |
1917 | }; |
1918 | LLVM_DEBUG(dbgs() << "Checking for PIC jump table\n" ); |
1919 | MCInst *FirstInstr = nullptr; |
1920 | MCInst *SecondInstr = nullptr; |
1921 | enum { |
1922 | NOMATCH = 0, |
1923 | MATCH_JUMP_TABLE, |
1924 | MATCH_FIXED_BRANCH, |
1925 | } MatchingState = NOMATCH; |
1926 | while (++II != IE) { |
1927 | MCInst &Instr = *II; |
1928 | const MCInstrDesc &InstrDesc = Info->get(Opcode: Instr.getOpcode()); |
1929 | if (!InstrDesc.hasDefOfPhysReg(MI: Instr, Reg: R1, RI: *RegInfo) && |
1930 | !InstrDesc.hasDefOfPhysReg(MI: Instr, Reg: R2, RI: *RegInfo)) { |
1931 | // Ignore instructions that don't affect R1, R2 registers. |
1932 | continue; |
1933 | } |
1934 | const bool IsMOVSXInstr = isMOVSX64rm32(Inst: Instr); |
1935 | const bool IsLEAInstr = isLEA64r(Inst: Instr); |
1936 | if (MatchingState == NOMATCH) { |
1937 | if (IsMOVSXInstr) |
1938 | MatchingState = MATCH_JUMP_TABLE; |
1939 | else if (IsLEAInstr) |
1940 | MatchingState = MATCH_FIXED_BRANCH; |
1941 | else |
1942 | break; |
1943 | |
1944 | // Check if the first instruction is setting %r1 or %r2. In canonical |
1945 | // form lea sets %r1 and mov sets %r2. If it's the opposite - rename so |
1946 | // we have to only check a single form. |
1947 | unsigned DestReg = Instr.getOperand(i: 0).getReg(); |
1948 | MCPhysReg &ExpectReg = MatchingState == MATCH_JUMP_TABLE ? R2 : R1; |
1949 | if (DestReg != ExpectReg) |
1950 | std::swap(R1, R2); |
1951 | if (DestReg != ExpectReg) |
1952 | break; |
1953 | |
1954 | // Verify operands |
1955 | std::optional<X86MemOperand> MO = evaluateX86MemoryOperand(Instr); |
1956 | if (!MO) |
1957 | break; |
1958 | if ((MatchingState == MATCH_JUMP_TABLE && isIndexed(*MO, R1)) || |
1959 | (MatchingState == MATCH_FIXED_BRANCH && isRIPRel(*MO))) |
1960 | FirstInstr = &Instr; |
1961 | else |
1962 | break; |
1963 | } else { |
1964 | unsigned ExpectReg = MatchingState == MATCH_JUMP_TABLE ? R1 : R2; |
1965 | if (!InstrDesc.hasDefOfPhysReg(MI: Instr, Reg: ExpectReg, RI: *RegInfo)) |
1966 | continue; |
1967 | if ((MatchingState == MATCH_JUMP_TABLE && !IsLEAInstr) || |
1968 | (MatchingState == MATCH_FIXED_BRANCH && !IsMOVSXInstr)) |
1969 | break; |
1970 | if (Instr.getOperand(i: 0).getReg() != ExpectReg) |
1971 | break; |
1972 | |
1973 | // Verify operands. |
1974 | std::optional<X86MemOperand> MO = evaluateX86MemoryOperand(Instr); |
1975 | if (!MO) |
1976 | break; |
1977 | if (!isRIPRel(*MO)) |
1978 | break; |
1979 | SecondInstr = &Instr; |
1980 | break; |
1981 | } |
1982 | } |
1983 | |
1984 | if (!SecondInstr) |
1985 | return std::make_tuple(IndirectBranchType::UNKNOWN, nullptr, nullptr); |
1986 | |
1987 | if (MatchingState == MATCH_FIXED_BRANCH) { |
1988 | LLVM_DEBUG(dbgs() << "checking potential fixed indirect branch\n" ); |
1989 | return std::make_tuple(IndirectBranchType::POSSIBLE_PIC_FIXED_BRANCH, |
1990 | FirstInstr, SecondInstr); |
1991 | } |
1992 | LLVM_DEBUG(dbgs() << "checking potential PIC jump table\n" ); |
1993 | return std::make_tuple(IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE, |
1994 | SecondInstr, nullptr); |
1995 | } |
1996 | |
1997 | IndirectBranchType |
1998 | analyzeIndirectBranch(MCInst &Instruction, InstructionIterator Begin, |
1999 | InstructionIterator End, const unsigned PtrSize, |
2000 | MCInst *&MemLocInstrOut, unsigned &BaseRegNumOut, |
2001 | unsigned &IndexRegNumOut, int64_t &DispValueOut, |
2002 | const MCExpr *&DispExprOut, MCInst *&PCRelBaseOut, |
2003 | MCInst *&FixedEntryLoadInst) const override { |
2004 | // Try to find a (base) memory location from where the address for |
2005 | // the indirect branch is loaded. For X86-64 the memory will be specified |
2006 | // in the following format: |
2007 | // |
2008 | // {%rip}/{%basereg} + Imm + IndexReg * Scale |
2009 | // |
2010 | // We are interested in the cases where Scale == sizeof(uintptr_t) and |
2011 | // the contents of the memory are presumably an array of pointers to code. |
2012 | // |
2013 | // Normal jump table: |
2014 | // |
2015 | // jmp *(JUMP_TABLE, %index, Scale) <- MemLocInstr |
2016 | // |
2017 | // or |
2018 | // |
2019 | // mov (JUMP_TABLE, %index, Scale), %r1 <- MemLocInstr |
2020 | // ... |
2021 | // jmp %r1 |
2022 | // |
2023 | // We handle PIC-style jump tables separately. |
2024 | // |
2025 | MemLocInstrOut = nullptr; |
2026 | BaseRegNumOut = X86::NoRegister; |
2027 | IndexRegNumOut = X86::NoRegister; |
2028 | DispValueOut = 0; |
2029 | DispExprOut = nullptr; |
2030 | FixedEntryLoadInst = nullptr; |
2031 | |
2032 | std::reverse_iterator<InstructionIterator> II(End); |
2033 | std::reverse_iterator<InstructionIterator> IE(Begin); |
2034 | |
2035 | IndirectBranchType Type = IndirectBranchType::UNKNOWN; |
2036 | |
2037 | // An instruction referencing memory used by jump instruction (directly or |
2038 | // via register). This location could be an array of function pointers |
2039 | // in case of indirect tail call, or a jump table. |
2040 | MCInst *MemLocInstr = nullptr; |
2041 | |
2042 | if (MCPlus::getNumPrimeOperands(Inst: Instruction) == 1) { |
2043 | // If the indirect jump is on register - try to detect if the |
2044 | // register value is loaded from a memory location. |
2045 | assert(Instruction.getOperand(0).isReg() && "register operand expected" ); |
2046 | const unsigned R1 = Instruction.getOperand(i: 0).getReg(); |
2047 | // Check if one of the previous instructions defines the jump-on register. |
2048 | for (auto PrevII = II; PrevII != IE; ++PrevII) { |
2049 | MCInst &PrevInstr = *PrevII; |
2050 | const MCInstrDesc &PrevInstrDesc = Info->get(Opcode: PrevInstr.getOpcode()); |
2051 | |
2052 | if (!PrevInstrDesc.hasDefOfPhysReg(MI: PrevInstr, Reg: R1, RI: *RegInfo)) |
2053 | continue; |
2054 | |
2055 | if (isMoveMem2Reg(Inst: PrevInstr)) { |
2056 | MemLocInstr = &PrevInstr; |
2057 | break; |
2058 | } |
2059 | if (isADD64rr(Inst: PrevInstr)) { |
2060 | unsigned R2 = PrevInstr.getOperand(i: 2).getReg(); |
2061 | if (R1 == R2) |
2062 | return IndirectBranchType::UNKNOWN; |
2063 | std::tie(Type, MemLocInstr, FixedEntryLoadInst) = |
2064 | analyzePICJumpTable(PrevII, IE, R1, R2); |
2065 | break; |
2066 | } |
2067 | return IndirectBranchType::UNKNOWN; |
2068 | } |
2069 | if (!MemLocInstr) { |
2070 | // No definition seen for the register in this function so far. Could be |
2071 | // an input parameter - which means it is an external code reference. |
2072 | // It also could be that the definition happens to be in the code that |
2073 | // we haven't processed yet. Since we have to be conservative, return |
2074 | // as UNKNOWN case. |
2075 | return IndirectBranchType::UNKNOWN; |
2076 | } |
2077 | } else { |
2078 | MemLocInstr = &Instruction; |
2079 | } |
2080 | |
2081 | const MCRegister RIPRegister = RegInfo->getProgramCounter(); |
2082 | |
2083 | // Analyze the memory location. |
2084 | std::optional<X86MemOperand> MO = evaluateX86MemoryOperand(*MemLocInstr); |
2085 | if (!MO) |
2086 | return IndirectBranchType::UNKNOWN; |
2087 | |
2088 | BaseRegNumOut = MO->BaseRegNum; |
2089 | IndexRegNumOut = MO->IndexRegNum; |
2090 | DispValueOut = MO->DispImm; |
2091 | DispExprOut = MO->DispExpr; |
2092 | |
2093 | if ((MO->BaseRegNum != X86::NoRegister && MO->BaseRegNum != RIPRegister) || |
2094 | MO->SegRegNum != X86::NoRegister) |
2095 | return IndirectBranchType::UNKNOWN; |
2096 | |
2097 | if (MemLocInstr == &Instruction && |
2098 | (!MO->ScaleImm || MO->IndexRegNum == X86::NoRegister)) { |
2099 | MemLocInstrOut = MemLocInstr; |
2100 | return IndirectBranchType::POSSIBLE_FIXED_BRANCH; |
2101 | } |
2102 | |
2103 | switch (Type) { |
2104 | case IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE: |
2105 | if (MO->ScaleImm != 1 || MO->BaseRegNum != RIPRegister) |
2106 | return IndirectBranchType::UNKNOWN; |
2107 | break; |
2108 | case IndirectBranchType::POSSIBLE_PIC_FIXED_BRANCH: |
2109 | break; |
2110 | default: |
2111 | if (MO->ScaleImm != PtrSize) |
2112 | return IndirectBranchType::UNKNOWN; |
2113 | } |
2114 | |
2115 | MemLocInstrOut = MemLocInstr; |
2116 | |
2117 | return Type; |
2118 | } |
2119 | |
2120 | /// Analyze a callsite to see if it could be a virtual method call. This only |
2121 | /// checks to see if the overall pattern is satisfied, it does not guarantee |
2122 | /// that the callsite is a true virtual method call. |
2123 | /// The format of virtual method calls that are recognized is one of the |
2124 | /// following: |
2125 | /// |
2126 | /// Form 1: (found in debug code) |
2127 | /// add METHOD_OFFSET, %VtableReg |
2128 | /// mov (%VtableReg), %MethodReg |
2129 | /// ... |
2130 | /// call or jmp *%MethodReg |
2131 | /// |
2132 | /// Form 2: |
2133 | /// mov METHOD_OFFSET(%VtableReg), %MethodReg |
2134 | /// ... |
2135 | /// call or jmp *%MethodReg |
2136 | /// |
2137 | /// Form 3: |
2138 | /// ... |
2139 | /// call or jmp *METHOD_OFFSET(%VtableReg) |
2140 | /// |
2141 | bool analyzeVirtualMethodCall(InstructionIterator ForwardBegin, |
2142 | InstructionIterator ForwardEnd, |
2143 | std::vector<MCInst *> &MethodFetchInsns, |
2144 | unsigned &VtableRegNum, unsigned &MethodRegNum, |
2145 | uint64_t &MethodOffset) const override { |
2146 | VtableRegNum = X86::NoRegister; |
2147 | MethodRegNum = X86::NoRegister; |
2148 | MethodOffset = 0; |
2149 | |
2150 | std::reverse_iterator<InstructionIterator> Itr(ForwardEnd); |
2151 | std::reverse_iterator<InstructionIterator> End(ForwardBegin); |
2152 | |
2153 | MCInst &CallInst = *Itr++; |
2154 | assert(isIndirectBranch(CallInst) || isCall(CallInst)); |
2155 | |
2156 | // The call can just be jmp offset(reg) |
2157 | if (std::optional<X86MemOperand> MO = evaluateX86MemoryOperand(CallInst)) { |
2158 | if (!MO->DispExpr && MO->BaseRegNum != X86::RIP && |
2159 | MO->BaseRegNum != X86::RBP && MO->BaseRegNum != X86::NoRegister) { |
2160 | MethodRegNum = MO->BaseRegNum; |
2161 | if (MO->ScaleImm == 1 && MO->IndexRegNum == X86::NoRegister && |
2162 | MO->SegRegNum == X86::NoRegister) { |
2163 | VtableRegNum = MethodRegNum; |
2164 | MethodOffset = MO->DispImm; |
2165 | MethodFetchInsns.push_back(&CallInst); |
2166 | return true; |
2167 | } |
2168 | } |
2169 | return false; |
2170 | } |
2171 | if (CallInst.getOperand(i: 0).isReg()) |
2172 | MethodRegNum = CallInst.getOperand(i: 0).getReg(); |
2173 | else |
2174 | return false; |
2175 | |
2176 | if (MethodRegNum == X86::RIP || MethodRegNum == X86::RBP) { |
2177 | VtableRegNum = X86::NoRegister; |
2178 | MethodRegNum = X86::NoRegister; |
2179 | return false; |
2180 | } |
2181 | |
2182 | // find load from vtable, this may or may not include the method offset |
2183 | while (Itr != End) { |
2184 | MCInst &CurInst = *Itr++; |
2185 | const MCInstrDesc &Desc = Info->get(Opcode: CurInst.getOpcode()); |
2186 | if (Desc.hasDefOfPhysReg(MI: CurInst, Reg: MethodRegNum, RI: *RegInfo)) { |
2187 | if (!mayLoad(Inst: CurInst)) |
2188 | return false; |
2189 | if (std::optional<X86MemOperand> MO = |
2190 | evaluateX86MemoryOperand(CurInst)) { |
2191 | if (!MO->DispExpr && MO->ScaleImm == 1 && |
2192 | MO->BaseRegNum != X86::RIP && MO->BaseRegNum != X86::RBP && |
2193 | MO->BaseRegNum != X86::NoRegister && |
2194 | MO->IndexRegNum == X86::NoRegister && |
2195 | MO->SegRegNum == X86::NoRegister) { |
2196 | VtableRegNum = MO->BaseRegNum; |
2197 | MethodOffset = MO->DispImm; |
2198 | MethodFetchInsns.push_back(&CurInst); |
2199 | if (MethodOffset != 0) |
2200 | return true; |
2201 | break; |
2202 | } |
2203 | } |
2204 | return false; |
2205 | } |
2206 | } |
2207 | |
2208 | if (!VtableRegNum) |
2209 | return false; |
2210 | |
2211 | // look for any adds affecting the method register. |
2212 | while (Itr != End) { |
2213 | MCInst &CurInst = *Itr++; |
2214 | const MCInstrDesc &Desc = Info->get(Opcode: CurInst.getOpcode()); |
2215 | if (Desc.hasDefOfPhysReg(MI: CurInst, Reg: VtableRegNum, RI: *RegInfo)) { |
2216 | if (isADDri(Inst: CurInst)) { |
2217 | assert(!MethodOffset); |
2218 | MethodOffset = CurInst.getOperand(i: 2).getImm(); |
2219 | MethodFetchInsns.insert(MethodFetchInsns.begin(), &CurInst); |
2220 | break; |
2221 | } |
2222 | } |
2223 | } |
2224 | |
2225 | return true; |
2226 | } |
2227 | |
2228 | void createStackPointerIncrement(MCInst &Inst, int Size, |
2229 | bool NoFlagsClobber) const override { |
2230 | if (NoFlagsClobber) { |
2231 | Inst.setOpcode(X86::LEA64r); |
2232 | Inst.clear(); |
2233 | Inst.addOperand(MCOperand::createReg(X86::RSP)); |
2234 | Inst.addOperand(MCOperand::createReg(X86::RSP)); // BaseReg |
2235 | Inst.addOperand(Op: MCOperand::createImm(Val: 1)); // ScaleAmt |
2236 | Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // IndexReg |
2237 | Inst.addOperand(Op: MCOperand::createImm(Val: -Size)); // Displacement |
2238 | Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg |
2239 | return; |
2240 | } |
2241 | Inst.setOpcode(X86::SUB64ri8); |
2242 | Inst.clear(); |
2243 | Inst.addOperand(MCOperand::createReg(X86::RSP)); |
2244 | Inst.addOperand(MCOperand::createReg(X86::RSP)); |
2245 | Inst.addOperand(Op: MCOperand::createImm(Val: Size)); |
2246 | } |
2247 | |
2248 | void createStackPointerDecrement(MCInst &Inst, int Size, |
2249 | bool NoFlagsClobber) const override { |
2250 | if (NoFlagsClobber) { |
2251 | Inst.setOpcode(X86::LEA64r); |
2252 | Inst.clear(); |
2253 | Inst.addOperand(MCOperand::createReg(X86::RSP)); |
2254 | Inst.addOperand(MCOperand::createReg(X86::RSP)); // BaseReg |
2255 | Inst.addOperand(Op: MCOperand::createImm(Val: 1)); // ScaleAmt |
2256 | Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // IndexReg |
2257 | Inst.addOperand(Op: MCOperand::createImm(Val: Size)); // Displacement |
2258 | Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg |
2259 | return; |
2260 | } |
2261 | Inst.setOpcode(X86::ADD64ri8); |
2262 | Inst.clear(); |
2263 | Inst.addOperand(MCOperand::createReg(X86::RSP)); |
2264 | Inst.addOperand(MCOperand::createReg(X86::RSP)); |
2265 | Inst.addOperand(Op: MCOperand::createImm(Val: Size)); |
2266 | } |
2267 | |
2268 | void createSaveToStack(MCInst &Inst, const MCPhysReg &StackReg, int Offset, |
2269 | const MCPhysReg &SrcReg, int Size) const override { |
2270 | unsigned NewOpcode; |
2271 | switch (Size) { |
2272 | default: |
2273 | llvm_unreachable("Invalid operand size" ); |
2274 | return; |
2275 | case 2: NewOpcode = X86::MOV16mr; break; |
2276 | case 4: NewOpcode = X86::MOV32mr; break; |
2277 | case 8: NewOpcode = X86::MOV64mr; break; |
2278 | } |
2279 | Inst.setOpcode(NewOpcode); |
2280 | Inst.clear(); |
2281 | Inst.addOperand(Op: MCOperand::createReg(Reg: StackReg)); // BaseReg |
2282 | Inst.addOperand(Op: MCOperand::createImm(Val: 1)); // ScaleAmt |
2283 | Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // IndexReg |
2284 | Inst.addOperand(Op: MCOperand::createImm(Val: Offset)); // Displacement |
2285 | Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg |
2286 | Inst.addOperand(Op: MCOperand::createReg(Reg: SrcReg)); |
2287 | } |
2288 | |
2289 | void createRestoreFromStack(MCInst &Inst, const MCPhysReg &StackReg, |
2290 | int Offset, const MCPhysReg &DstReg, |
2291 | int Size) const override { |
2292 | return createLoad(Inst, StackReg, /*Scale=*/1, /*IndexReg=*/X86::NoRegister, |
2293 | Offset, nullptr, /*AddrSegmentReg=*/X86::NoRegister, |
2294 | DstReg, Size); |
2295 | } |
2296 | |
2297 | void createLoad(MCInst &Inst, const MCPhysReg &BaseReg, int64_t Scale, |
2298 | const MCPhysReg &IndexReg, int64_t Offset, |
2299 | const MCExpr *OffsetExpr, const MCPhysReg &AddrSegmentReg, |
2300 | const MCPhysReg &DstReg, int Size) const override { |
2301 | unsigned NewOpcode; |
2302 | switch (Size) { |
2303 | default: |
2304 | llvm_unreachable("Invalid operand size" ); |
2305 | return; |
2306 | case 2: NewOpcode = X86::MOV16rm; break; |
2307 | case 4: NewOpcode = X86::MOV32rm; break; |
2308 | case 8: NewOpcode = X86::MOV64rm; break; |
2309 | } |
2310 | Inst.setOpcode(NewOpcode); |
2311 | Inst.clear(); |
2312 | Inst.addOperand(Op: MCOperand::createReg(Reg: DstReg)); |
2313 | Inst.addOperand(Op: MCOperand::createReg(Reg: BaseReg)); |
2314 | Inst.addOperand(Op: MCOperand::createImm(Val: Scale)); |
2315 | Inst.addOperand(Op: MCOperand::createReg(Reg: IndexReg)); |
2316 | if (OffsetExpr) |
2317 | Inst.addOperand(Op: MCOperand::createExpr(Val: OffsetExpr)); // Displacement |
2318 | else |
2319 | Inst.addOperand(Op: MCOperand::createImm(Val: Offset)); // Displacement |
2320 | Inst.addOperand(Op: MCOperand::createReg(Reg: AddrSegmentReg)); // AddrSegmentReg |
2321 | } |
2322 | |
2323 | InstructionListType createLoadImmediate(const MCPhysReg Dest, |
2324 | uint64_t Imm) const override { |
2325 | InstructionListType Insts; |
2326 | Insts.emplace_back(); |
2327 | Insts.back().setOpcode(X86::MOV64ri32); |
2328 | Insts.back().clear(); |
2329 | Insts.back().addOperand(Op: MCOperand::createReg(Reg: Dest)); |
2330 | Insts.back().addOperand(Op: MCOperand::createImm(Val: Imm)); |
2331 | return Insts; |
2332 | } |
2333 | |
2334 | void createIJmp32Frag(SmallVectorImpl<MCInst> &Insts, |
2335 | const MCOperand &BaseReg, const MCOperand &Scale, |
2336 | const MCOperand &IndexReg, const MCOperand &Offset, |
2337 | const MCOperand &TmpReg) const override { |
2338 | // The code fragment we emit here is: |
2339 | // |
2340 | // mov32 (%base, %index, scale), %tmpreg |
2341 | // ijmp *(%tmpreg) |
2342 | // |
2343 | MCInst IJmp; |
2344 | IJmp.setOpcode(X86::JMP64r); |
2345 | IJmp.addOperand(Op: TmpReg); |
2346 | |
2347 | MCInst Load; |
2348 | Load.setOpcode(X86::MOV32rm); |
2349 | Load.addOperand(Op: TmpReg); |
2350 | Load.addOperand(Op: BaseReg); |
2351 | Load.addOperand(Op: Scale); |
2352 | Load.addOperand(Op: IndexReg); |
2353 | Load.addOperand(Op: Offset); |
2354 | Load.addOperand(MCOperand::createReg(X86::NoRegister)); |
2355 | |
2356 | Insts.push_back(Load); |
2357 | Insts.push_back(IJmp); |
2358 | } |
2359 | |
2360 | void createNoop(MCInst &Inst) const override { |
2361 | Inst.setOpcode(X86::NOOP); |
2362 | Inst.clear(); |
2363 | } |
2364 | |
2365 | void createReturn(MCInst &Inst) const override { |
2366 | Inst.setOpcode(X86::RET64); |
2367 | Inst.clear(); |
2368 | } |
2369 | |
2370 | InstructionListType createInlineMemcpy(bool ReturnEnd) const override { |
2371 | InstructionListType Code; |
2372 | if (ReturnEnd) |
2373 | Code.emplace_back(MCInstBuilder(X86::LEA64r) |
2374 | .addReg(X86::RAX) |
2375 | .addReg(X86::RDI) |
2376 | .addImm(1) |
2377 | .addReg(X86::RDX) |
2378 | .addImm(0) |
2379 | .addReg(X86::NoRegister)); |
2380 | else |
2381 | Code.emplace_back(MCInstBuilder(X86::MOV64rr) |
2382 | .addReg(X86::RAX) |
2383 | .addReg(X86::RDI)); |
2384 | |
2385 | Code.emplace_back(MCInstBuilder(X86::MOV32rr) |
2386 | .addReg(X86::ECX) |
2387 | .addReg(X86::EDX)); |
2388 | Code.emplace_back(MCInstBuilder(X86::REP_MOVSB_64)); |
2389 | |
2390 | return Code; |
2391 | } |
2392 | |
2393 | InstructionListType createOneByteMemcpy() const override { |
2394 | InstructionListType Code; |
2395 | Code.emplace_back(MCInstBuilder(X86::MOV8rm) |
2396 | .addReg(X86::CL) |
2397 | .addReg(X86::RSI) |
2398 | .addImm(0) |
2399 | .addReg(X86::NoRegister) |
2400 | .addImm(0) |
2401 | .addReg(X86::NoRegister)); |
2402 | Code.emplace_back(MCInstBuilder(X86::MOV8mr) |
2403 | .addReg(X86::RDI) |
2404 | .addImm(0) |
2405 | .addReg(X86::NoRegister) |
2406 | .addImm(0) |
2407 | .addReg(X86::NoRegister) |
2408 | .addReg(X86::CL)); |
2409 | Code.emplace_back(MCInstBuilder(X86::MOV64rr) |
2410 | .addReg(X86::RAX) |
2411 | .addReg(X86::RDI)); |
2412 | return Code; |
2413 | } |
2414 | |
2415 | InstructionListType createCmpJE(MCPhysReg RegNo, int64_t Imm, |
2416 | const MCSymbol *Target, |
2417 | MCContext *Ctx) const override { |
2418 | InstructionListType Code; |
2419 | Code.emplace_back(MCInstBuilder(X86::CMP64ri8) |
2420 | .addReg(RegNo) |
2421 | .addImm(Imm)); |
2422 | Code.emplace_back(MCInstBuilder(X86::JCC_1) |
2423 | .addExpr(MCSymbolRefExpr::create( |
2424 | Target, MCSymbolRefExpr::VK_None, *Ctx)) |
2425 | .addImm(X86::COND_E)); |
2426 | return Code; |
2427 | } |
2428 | |
2429 | InstructionListType createCmpJNE(MCPhysReg RegNo, int64_t Imm, |
2430 | const MCSymbol *Target, |
2431 | MCContext *Ctx) const override { |
2432 | InstructionListType Code; |
2433 | Code.emplace_back(MCInstBuilder(X86::CMP64ri8).addReg(RegNo).addImm(Imm)); |
2434 | Code.emplace_back(MCInstBuilder(X86::JCC_1) |
2435 | .addExpr(MCSymbolRefExpr::create( |
2436 | Target, MCSymbolRefExpr::VK_None, *Ctx)) |
2437 | .addImm(X86::COND_NE)); |
2438 | return Code; |
2439 | } |
2440 | |
2441 | std::optional<Relocation> |
2442 | createRelocation(const MCFixup &Fixup, |
2443 | const MCAsmBackend &MAB) const override { |
2444 | MCFixupKindInfo FKI = MAB.getFixupKindInfo(Kind: Fixup.getKind()); |
2445 | |
2446 | assert(FKI.TargetOffset == 0 && "0-bit relocation offset expected" ); |
2447 | const uint64_t RelOffset = Fixup.getOffset(); |
2448 | |
2449 | uint32_t RelType; |
2450 | if (FKI.Flags & MCFixupKindInfo::FKF_IsPCRel) { |
2451 | switch (FKI.TargetSize) { |
2452 | default: |
2453 | return std::nullopt; |
2454 | case 8: RelType = ELF::R_X86_64_PC8; break; |
2455 | case 16: RelType = ELF::R_X86_64_PC16; break; |
2456 | case 32: RelType = ELF::R_X86_64_PC32; break; |
2457 | case 64: RelType = ELF::R_X86_64_PC64; break; |
2458 | } |
2459 | } else { |
2460 | switch (FKI.TargetSize) { |
2461 | default: |
2462 | return std::nullopt; |
2463 | case 8: RelType = ELF::R_X86_64_8; break; |
2464 | case 16: RelType = ELF::R_X86_64_16; break; |
2465 | case 32: RelType = ELF::R_X86_64_32; break; |
2466 | case 64: RelType = ELF::R_X86_64_64; break; |
2467 | } |
2468 | } |
2469 | |
2470 | auto [RelSymbol, RelAddend] = extractFixupExpr(Fixup); |
2471 | |
2472 | return Relocation({RelOffset, RelSymbol, RelType, RelAddend, 0}); |
2473 | } |
2474 | |
2475 | bool replaceImmWithSymbolRef(MCInst &Inst, const MCSymbol *Symbol, |
2476 | int64_t Addend, MCContext *Ctx, int64_t &Value, |
2477 | uint32_t RelType) const override { |
2478 | unsigned ImmOpNo = -1U; |
2479 | |
2480 | for (unsigned Index = 0; Index < MCPlus::getNumPrimeOperands(Inst); |
2481 | ++Index) { |
2482 | if (Inst.getOperand(i: Index).isImm()) { |
2483 | ImmOpNo = Index; |
2484 | // TODO: this is a bit hacky. It finds the correct operand by |
2485 | // searching for a specific immediate value. If no value is |
2486 | // provided it defaults to the last immediate operand found. |
2487 | // This could lead to unexpected results if the instruction |
2488 | // has more than one immediate with the same value. |
2489 | if (Inst.getOperand(i: ImmOpNo).getImm() == Value) |
2490 | break; |
2491 | } |
2492 | } |
2493 | |
2494 | if (ImmOpNo == -1U) |
2495 | return false; |
2496 | |
2497 | Value = Inst.getOperand(i: ImmOpNo).getImm(); |
2498 | |
2499 | setOperandToSymbolRef(Inst, OpNum: ImmOpNo, Symbol, Addend, Ctx, RelType); |
2500 | |
2501 | return true; |
2502 | } |
2503 | |
2504 | bool replaceRegWithImm(MCInst &Inst, unsigned Register, |
2505 | int64_t Imm) const override { |
2506 | |
2507 | enum CheckSignExt : uint8_t { |
2508 | NOCHECK = 0, |
2509 | CHECK8, |
2510 | CHECK32, |
2511 | }; |
2512 | |
2513 | using CheckList = std::vector<std::pair<CheckSignExt, unsigned>>; |
2514 | struct InstInfo { |
2515 | // Size in bytes that Inst loads from memory. |
2516 | uint8_t DataSize; |
2517 | |
2518 | // True when the target operand has to be duplicated because the opcode |
2519 | // expects a LHS operand. |
2520 | bool HasLHS; |
2521 | |
2522 | // List of checks and corresponding opcodes to be used. We try to use the |
2523 | // smallest possible immediate value when various sizes are available, |
2524 | // hence we may need to check whether a larger constant fits in a smaller |
2525 | // immediate. |
2526 | CheckList Checks; |
2527 | }; |
2528 | |
2529 | InstInfo I; |
2530 | |
2531 | switch (Inst.getOpcode()) { |
2532 | default: { |
2533 | switch (getPushSize(Inst)) { |
2534 | |
2535 | case 2: I = {2, false, {{CHECK8, X86::PUSH16i8}, {NOCHECK, X86::PUSH16i}}}; break; |
2536 | case 4: I = {4, false, {{CHECK8, X86::PUSH32i8}, {NOCHECK, X86::PUSH32i}}}; break; |
2537 | case 8: I = {8, false, {{CHECK8, X86::PUSH64i8}, |
2538 | {CHECK32, X86::PUSH64i32}, |
2539 | {NOCHECK, Inst.getOpcode()}}}; break; |
2540 | default: return false; |
2541 | } |
2542 | break; |
2543 | } |
2544 | |
2545 | // MOV |
2546 | case X86::MOV8rr: I = {1, false, {{NOCHECK, X86::MOV8ri}}}; break; |
2547 | case X86::MOV16rr: I = {2, false, {{NOCHECK, X86::MOV16ri}}}; break; |
2548 | case X86::MOV32rr: I = {4, false, {{NOCHECK, X86::MOV32ri}}}; break; |
2549 | case X86::MOV64rr: I = {8, false, {{CHECK32, X86::MOV64ri32}, |
2550 | {NOCHECK, X86::MOV64ri}}}; break; |
2551 | |
2552 | case X86::MOV8mr: I = {1, false, {{NOCHECK, X86::MOV8mi}}}; break; |
2553 | case X86::MOV16mr: I = {2, false, {{NOCHECK, X86::MOV16mi}}}; break; |
2554 | case X86::MOV32mr: I = {4, false, {{NOCHECK, X86::MOV32mi}}}; break; |
2555 | case X86::MOV64mr: I = {8, false, {{CHECK32, X86::MOV64mi32}, |
2556 | {NOCHECK, X86::MOV64mr}}}; break; |
2557 | |
2558 | // MOVZX |
2559 | case X86::MOVZX16rr8: I = {1, false, {{NOCHECK, X86::MOV16ri}}}; break; |
2560 | case X86::MOVZX32rr8: I = {1, false, {{NOCHECK, X86::MOV32ri}}}; break; |
2561 | case X86::MOVZX32rr16: I = {2, false, {{NOCHECK, X86::MOV32ri}}}; break; |
2562 | |
2563 | // CMP |
2564 | case X86::CMP8rr: I = {1, false, {{NOCHECK, X86::CMP8ri}}}; break; |
2565 | case X86::CMP16rr: I = {2, false, {{CHECK8, X86::CMP16ri8}, |
2566 | {NOCHECK, X86::CMP16ri}}}; break; |
2567 | case X86::CMP32rr: I = {4, false, {{CHECK8, X86::CMP32ri8}, |
2568 | {NOCHECK, X86::CMP32ri}}}; break; |
2569 | case X86::CMP64rr: I = {8, false, {{CHECK8, X86::CMP64ri8}, |
2570 | {CHECK32, X86::CMP64ri32}, |
2571 | {NOCHECK, X86::CMP64rr}}}; break; |
2572 | |
2573 | // TEST |
2574 | case X86::TEST8rr: I = {1, false, {{NOCHECK, X86::TEST8ri}}}; break; |
2575 | case X86::TEST16rr: I = {2, false, {{NOCHECK, X86::TEST16ri}}}; break; |
2576 | case X86::TEST32rr: I = {4, false, {{NOCHECK, X86::TEST32ri}}}; break; |
2577 | case X86::TEST64rr: I = {8, false, {{CHECK32, X86::TEST64ri32}, |
2578 | {NOCHECK, X86::TEST64rr}}}; break; |
2579 | |
2580 | // ADD |
2581 | case X86::ADD8rr: I = {1, true, {{NOCHECK, X86::ADD8ri}}}; break; |
2582 | case X86::ADD16rr: I = {2, true, {{CHECK8, X86::ADD16ri8}, |
2583 | {NOCHECK, X86::ADD16ri}}}; break; |
2584 | case X86::ADD32rr: I = {4, true, {{CHECK8, X86::ADD32ri8}, |
2585 | {NOCHECK, X86::ADD32ri}}}; break; |
2586 | case X86::ADD64rr: I = {8, true, {{CHECK8, X86::ADD64ri8}, |
2587 | {CHECK32, X86::ADD64ri32}, |
2588 | {NOCHECK, X86::ADD64rr}}}; break; |
2589 | |
2590 | // SUB |
2591 | case X86::SUB8rr: I = {1, true, {{NOCHECK, X86::SUB8ri}}}; break; |
2592 | case X86::SUB16rr: I = {2, true, {{CHECK8, X86::SUB16ri8}, |
2593 | {NOCHECK, X86::SUB16ri}}}; break; |
2594 | case X86::SUB32rr: I = {4, true, {{CHECK8, X86::SUB32ri8}, |
2595 | {NOCHECK, X86::SUB32ri}}}; break; |
2596 | case X86::SUB64rr: I = {8, true, {{CHECK8, X86::SUB64ri8}, |
2597 | {CHECK32, X86::SUB64ri32}, |
2598 | {NOCHECK, X86::SUB64rr}}}; break; |
2599 | |
2600 | // AND |
2601 | case X86::AND8rr: I = {1, true, {{NOCHECK, X86::AND8ri}}}; break; |
2602 | case X86::AND16rr: I = {2, true, {{CHECK8, X86::AND16ri8}, |
2603 | {NOCHECK, X86::AND16ri}}}; break; |
2604 | case X86::AND32rr: I = {4, true, {{CHECK8, X86::AND32ri8}, |
2605 | {NOCHECK, X86::AND32ri}}}; break; |
2606 | case X86::AND64rr: I = {8, true, {{CHECK8, X86::AND64ri8}, |
2607 | {CHECK32, X86::AND64ri32}, |
2608 | {NOCHECK, X86::AND64rr}}}; break; |
2609 | |
2610 | // OR |
2611 | case X86::OR8rr: I = {1, true, {{NOCHECK, X86::OR8ri}}}; break; |
2612 | case X86::OR16rr: I = {2, true, {{CHECK8, X86::OR16ri8}, |
2613 | {NOCHECK, X86::OR16ri}}}; break; |
2614 | case X86::OR32rr: I = {4, true, {{CHECK8, X86::OR32ri8}, |
2615 | {NOCHECK, X86::OR32ri}}}; break; |
2616 | case X86::OR64rr: I = {8, true, {{CHECK8, X86::OR64ri8}, |
2617 | {CHECK32, X86::OR64ri32}, |
2618 | {NOCHECK, X86::OR64rr}}}; break; |
2619 | |
2620 | // XOR |
2621 | case X86::XOR8rr: I = {1, true, {{NOCHECK, X86::XOR8ri}}}; break; |
2622 | case X86::XOR16rr: I = {2, true, {{CHECK8, X86::XOR16ri8}, |
2623 | {NOCHECK, X86::XOR16ri}}}; break; |
2624 | case X86::XOR32rr: I = {4, true, {{CHECK8, X86::XOR32ri8}, |
2625 | {NOCHECK, X86::XOR32ri}}}; break; |
2626 | case X86::XOR64rr: I = {8, true, {{CHECK8, X86::XOR64ri8}, |
2627 | {CHECK32, X86::XOR64ri32}, |
2628 | {NOCHECK, X86::XOR64rr}}}; break; |
2629 | } |
2630 | |
2631 | // Compute the new opcode. |
2632 | unsigned NewOpcode = 0; |
2633 | for (const std::pair<CheckSignExt, unsigned> &Check : I.Checks) { |
2634 | NewOpcode = Check.second; |
2635 | if (Check.first == NOCHECK) |
2636 | break; |
2637 | if (Check.first == CHECK8 && isInt<8>(Imm)) |
2638 | break; |
2639 | if (Check.first == CHECK32 && isInt<32>(Imm)) |
2640 | break; |
2641 | } |
2642 | if (NewOpcode == Inst.getOpcode()) |
2643 | return false; |
2644 | |
2645 | const MCInstrDesc &InstDesc = Info->get(Opcode: Inst.getOpcode()); |
2646 | |
2647 | unsigned NumFound = 0; |
2648 | for (unsigned Index = InstDesc.getNumDefs() + (I.HasLHS ? 1 : 0), |
2649 | E = InstDesc.getNumOperands(); |
2650 | Index != E; ++Index) |
2651 | if (Inst.getOperand(i: Index).isReg() && |
2652 | Inst.getOperand(i: Index).getReg() == Register) |
2653 | NumFound++; |
2654 | |
2655 | if (NumFound != 1) |
2656 | return false; |
2657 | |
2658 | MCOperand TargetOp = Inst.getOperand(i: 0); |
2659 | Inst.clear(); |
2660 | Inst.setOpcode(NewOpcode); |
2661 | Inst.addOperand(Op: TargetOp); |
2662 | if (I.HasLHS) |
2663 | Inst.addOperand(Op: TargetOp); |
2664 | Inst.addOperand(Op: MCOperand::createImm(Val: Imm)); |
2665 | |
2666 | return true; |
2667 | } |
2668 | |
2669 | bool replaceRegWithReg(MCInst &Inst, unsigned ToReplace, |
2670 | unsigned ReplaceWith) const override { |
2671 | |
2672 | // Get the HasLHS value so that iteration can be done |
2673 | bool HasLHS; |
2674 | if (X86::isAND(Inst.getOpcode()) || X86::isADD(Inst.getOpcode()) || |
2675 | X86::isSUB(Inst.getOpcode())) { |
2676 | HasLHS = true; |
2677 | } else if (isPop(Inst) || isPush(Inst) || X86::isCMP(Inst.getOpcode()) || |
2678 | X86::isTEST(Inst.getOpcode())) { |
2679 | HasLHS = false; |
2680 | } else { |
2681 | switch (Inst.getOpcode()) { |
2682 | case X86::MOV8rr: |
2683 | case X86::MOV8rm: |
2684 | case X86::MOV8mr: |
2685 | case X86::MOV8ri: |
2686 | case X86::MOV16rr: |
2687 | case X86::MOV16rm: |
2688 | case X86::MOV16mr: |
2689 | case X86::MOV16ri: |
2690 | case X86::MOV32rr: |
2691 | case X86::MOV32rm: |
2692 | case X86::MOV32mr: |
2693 | case X86::MOV32ri: |
2694 | case X86::MOV64rr: |
2695 | case X86::MOV64rm: |
2696 | case X86::MOV64mr: |
2697 | case X86::MOV64ri: |
2698 | case X86::MOVZX16rr8: |
2699 | case X86::MOVZX32rr8: |
2700 | case X86::MOVZX32rr16: |
2701 | case X86::MOVSX32rm8: |
2702 | case X86::MOVSX32rr8: |
2703 | case X86::MOVSX64rm32: |
2704 | case X86::LEA64r: |
2705 | HasLHS = false; |
2706 | break; |
2707 | default: |
2708 | return false; |
2709 | } |
2710 | } |
2711 | |
2712 | const MCInstrDesc &InstDesc = Info->get(Opcode: Inst.getOpcode()); |
2713 | |
2714 | bool FoundOne = false; |
2715 | |
2716 | // Iterate only through src operands that arent also dest operands |
2717 | for (unsigned Index = InstDesc.getNumDefs() + (HasLHS ? 1 : 0), |
2718 | E = InstDesc.getNumOperands(); |
2719 | Index != E; ++Index) { |
2720 | BitVector RegAliases = getAliases(Reg: ToReplace, OnlySmaller: true); |
2721 | if (!Inst.getOperand(i: Index).isReg() || |
2722 | !RegAliases.test(Idx: Inst.getOperand(i: Index).getReg())) |
2723 | continue; |
2724 | // Resize register if needed |
2725 | unsigned SizedReplaceWith = getAliasSized( |
2726 | Reg: ReplaceWith, Size: getRegSize(Reg: Inst.getOperand(i: Index).getReg())); |
2727 | MCOperand NewOperand = MCOperand::createReg(Reg: SizedReplaceWith); |
2728 | Inst.getOperand(i: Index) = NewOperand; |
2729 | FoundOne = true; |
2730 | } |
2731 | |
2732 | // Return true if at least one operand was replaced |
2733 | return FoundOne; |
2734 | } |
2735 | |
2736 | void createUncondBranch(MCInst &Inst, const MCSymbol *TBB, |
2737 | MCContext *Ctx) const override { |
2738 | Inst.clear(); |
2739 | Inst.setOpcode(X86::JMP_1); |
2740 | Inst.clear(); |
2741 | Inst.addOperand(Op: MCOperand::createExpr( |
2742 | Val: MCSymbolRefExpr::create(Symbol: TBB, Kind: MCSymbolRefExpr::VK_None, Ctx&: *Ctx))); |
2743 | } |
2744 | |
2745 | void createLongUncondBranch(MCInst &Inst, const MCSymbol *Target, |
2746 | MCContext *Ctx) const override { |
2747 | Inst.setOpcode(X86::JMP_4); |
2748 | Inst.clear(); |
2749 | Inst.addOperand(Op: MCOperand::createExpr( |
2750 | Val: MCSymbolRefExpr::create(Symbol: Target, Kind: MCSymbolRefExpr::VK_None, Ctx&: *Ctx))); |
2751 | } |
2752 | |
2753 | void createCall(MCInst &Inst, const MCSymbol *Target, |
2754 | MCContext *Ctx) override { |
2755 | Inst.setOpcode(X86::CALL64pcrel32); |
2756 | Inst.clear(); |
2757 | Inst.addOperand(Op: MCOperand::createExpr( |
2758 | Val: MCSymbolRefExpr::create(Symbol: Target, Kind: MCSymbolRefExpr::VK_None, Ctx&: *Ctx))); |
2759 | } |
2760 | |
2761 | void createTailCall(MCInst &Inst, const MCSymbol *Target, |
2762 | MCContext *Ctx) override { |
2763 | return createDirectCall(Inst, Target, Ctx, /*IsTailCall*/ true); |
2764 | } |
2765 | |
2766 | void createLongTailCall(InstructionListType &Seq, const MCSymbol *Target, |
2767 | MCContext *Ctx) override { |
2768 | Seq.clear(); |
2769 | Seq.emplace_back(); |
2770 | createDirectCall(Inst&: Seq.back(), Target, Ctx, /*IsTailCall*/ true); |
2771 | } |
2772 | |
2773 | void createTrap(MCInst &Inst) const override { |
2774 | Inst.clear(); |
2775 | Inst.setOpcode(X86::TRAP); |
2776 | } |
2777 | |
2778 | void createCondBranch(MCInst &Inst, const MCSymbol *Target, unsigned CC, |
2779 | MCContext *Ctx) const override { |
2780 | Inst.setOpcode(X86::JCC_1); |
2781 | Inst.clear(); |
2782 | Inst.addOperand(Op: MCOperand::createExpr( |
2783 | Val: MCSymbolRefExpr::create(Symbol: Target, Kind: MCSymbolRefExpr::VK_None, Ctx&: *Ctx))); |
2784 | Inst.addOperand(Op: MCOperand::createImm(Val: CC)); |
2785 | } |
2786 | |
2787 | void createLongCondBranch(MCInst &Inst, const MCSymbol *Target, unsigned CC, |
2788 | MCContext *Ctx) const override { |
2789 | Inst.setOpcode(X86::JCC_4); |
2790 | Inst.clear(); |
2791 | Inst.addOperand(Op: MCOperand::createExpr( |
2792 | Val: MCSymbolRefExpr::create(Symbol: Target, Kind: MCSymbolRefExpr::VK_None, Ctx&: *Ctx))); |
2793 | Inst.addOperand(Op: MCOperand::createImm(Val: CC)); |
2794 | } |
2795 | |
2796 | void reverseBranchCondition(MCInst &Inst, const MCSymbol *TBB, |
2797 | MCContext *Ctx) const override { |
2798 | unsigned InvCC = getInvertedCondCode(CC: getCondCode(Inst)); |
2799 | assert(InvCC != X86::COND_INVALID && "invalid branch instruction" ); |
2800 | Inst.getOperand(i: Info->get(Opcode: Inst.getOpcode()).NumOperands - 1).setImm(InvCC); |
2801 | Inst.getOperand(i: 0) = MCOperand::createExpr( |
2802 | Val: MCSymbolRefExpr::create(Symbol: TBB, Kind: MCSymbolRefExpr::VK_None, Ctx&: *Ctx)); |
2803 | } |
2804 | |
2805 | bool replaceBranchCondition(MCInst &Inst, const MCSymbol *TBB, MCContext *Ctx, |
2806 | unsigned CC) const override { |
2807 | if (CC == X86::COND_INVALID) |
2808 | return false; |
2809 | Inst.getOperand(i: Info->get(Opcode: Inst.getOpcode()).NumOperands - 1).setImm(CC); |
2810 | Inst.getOperand(i: 0) = MCOperand::createExpr( |
2811 | Val: MCSymbolRefExpr::create(Symbol: TBB, Kind: MCSymbolRefExpr::VK_None, Ctx&: *Ctx)); |
2812 | return true; |
2813 | } |
2814 | |
2815 | unsigned getCanonicalBranchCondCode(unsigned CC) const override { |
2816 | switch (CC) { |
2817 | default: return X86::COND_INVALID; |
2818 | |
2819 | case X86::COND_E: return X86::COND_E; |
2820 | case X86::COND_NE: return X86::COND_E; |
2821 | |
2822 | case X86::COND_L: return X86::COND_L; |
2823 | case X86::COND_GE: return X86::COND_L; |
2824 | |
2825 | case X86::COND_LE: return X86::COND_G; |
2826 | case X86::COND_G: return X86::COND_G; |
2827 | |
2828 | case X86::COND_B: return X86::COND_B; |
2829 | case X86::COND_AE: return X86::COND_B; |
2830 | |
2831 | case X86::COND_BE: return X86::COND_A; |
2832 | case X86::COND_A: return X86::COND_A; |
2833 | |
2834 | case X86::COND_S: return X86::COND_S; |
2835 | case X86::COND_NS: return X86::COND_S; |
2836 | |
2837 | case X86::COND_P: return X86::COND_P; |
2838 | case X86::COND_NP: return X86::COND_P; |
2839 | |
2840 | case X86::COND_O: return X86::COND_O; |
2841 | case X86::COND_NO: return X86::COND_O; |
2842 | } |
2843 | } |
2844 | |
2845 | void replaceBranchTarget(MCInst &Inst, const MCSymbol *TBB, |
2846 | MCContext *Ctx) const override { |
2847 | assert((isCall(Inst) || isBranch(Inst)) && !isIndirectBranch(Inst) && |
2848 | "Invalid instruction" ); |
2849 | Inst.getOperand(i: 0) = MCOperand::createExpr( |
2850 | Val: MCSymbolRefExpr::create(Symbol: TBB, Kind: MCSymbolRefExpr::VK_None, Ctx&: *Ctx)); |
2851 | } |
2852 | |
2853 | MCPhysReg getX86R11() const override { return X86::R11; } |
2854 | |
2855 | unsigned getShortBranchOpcode(unsigned Opcode) const override { |
2856 | switch (Opcode) { |
2857 | default: |
2858 | return Opcode; |
2859 | case X86::JMP_2: |
2860 | return X86::JMP_1; |
2861 | case X86::JMP_4: |
2862 | return X86::JMP_1; |
2863 | case X86::JCC_2: |
2864 | return X86::JCC_1; |
2865 | case X86::JCC_4: |
2866 | return X86::JCC_1; |
2867 | } |
2868 | } |
2869 | |
2870 | MCPhysReg getIntArgRegister(unsigned ArgNo) const override { |
2871 | // FIXME: this should depend on the calling convention. |
2872 | switch (ArgNo) { |
2873 | case 0: return X86::RDI; |
2874 | case 1: return X86::RSI; |
2875 | case 2: return X86::RDX; |
2876 | case 3: return X86::RCX; |
2877 | case 4: return X86::R8; |
2878 | case 5: return X86::R9; |
2879 | default: return getNoRegister(); |
2880 | } |
2881 | } |
2882 | |
2883 | void createPause(MCInst &Inst) const override { |
2884 | Inst.clear(); |
2885 | Inst.setOpcode(X86::PAUSE); |
2886 | } |
2887 | |
2888 | void createLfence(MCInst &Inst) const override { |
2889 | Inst.clear(); |
2890 | Inst.setOpcode(X86::LFENCE); |
2891 | } |
2892 | |
2893 | void createDirectCall(MCInst &Inst, const MCSymbol *Target, MCContext *Ctx, |
2894 | bool IsTailCall) override { |
2895 | Inst.clear(); |
2896 | Inst.setOpcode(IsTailCall ? X86::JMP_4 : X86::CALL64pcrel32); |
2897 | Inst.addOperand(Op: MCOperand::createExpr( |
2898 | Val: MCSymbolRefExpr::create(Symbol: Target, Kind: MCSymbolRefExpr::VK_None, Ctx&: *Ctx))); |
2899 | if (IsTailCall) |
2900 | setTailCall(Inst); |
2901 | } |
2902 | |
2903 | void createShortJmp(InstructionListType &Seq, const MCSymbol *Target, |
2904 | MCContext *Ctx, bool IsTailCall) override { |
2905 | Seq.clear(); |
2906 | MCInst Inst; |
2907 | Inst.setOpcode(X86::JMP_1); |
2908 | Inst.addOperand(Op: MCOperand::createExpr( |
2909 | Val: MCSymbolRefExpr::create(Symbol: Target, Kind: MCSymbolRefExpr::VK_None, Ctx&: *Ctx))); |
2910 | if (IsTailCall) |
2911 | setTailCall(Inst); |
2912 | Seq.emplace_back(Inst); |
2913 | } |
2914 | |
2915 | bool isConditionalMove(const MCInst &Inst) const override { |
2916 | unsigned OpCode = Inst.getOpcode(); |
2917 | return (OpCode == X86::CMOV16rr || OpCode == X86::CMOV32rr || |
2918 | OpCode == X86::CMOV64rr); |
2919 | } |
2920 | |
2921 | bool isBranchOnMem(const MCInst &Inst) const override { |
2922 | unsigned OpCode = Inst.getOpcode(); |
2923 | if (OpCode == X86::CALL64m || (OpCode == X86::JMP32m && isTailCall(Inst)) || |
2924 | OpCode == X86::JMP64m) |
2925 | return true; |
2926 | |
2927 | return false; |
2928 | } |
2929 | |
2930 | bool isBranchOnReg(const MCInst &Inst) const override { |
2931 | unsigned OpCode = Inst.getOpcode(); |
2932 | if (OpCode == X86::CALL64r || (OpCode == X86::JMP32r && isTailCall(Inst)) || |
2933 | OpCode == X86::JMP64r) |
2934 | return true; |
2935 | |
2936 | return false; |
2937 | } |
2938 | |
2939 | void createPushRegister(MCInst &Inst, MCPhysReg Reg, |
2940 | unsigned Size) const override { |
2941 | Inst.clear(); |
2942 | unsigned NewOpcode = 0; |
2943 | if (Reg == X86::EFLAGS) { |
2944 | switch (Size) { |
2945 | case 2: NewOpcode = X86::PUSHF16; break; |
2946 | case 4: NewOpcode = X86::PUSHF32; break; |
2947 | case 8: NewOpcode = X86::PUSHF64; break; |
2948 | default: |
2949 | llvm_unreachable("Unexpected size" ); |
2950 | } |
2951 | Inst.setOpcode(NewOpcode); |
2952 | return; |
2953 | } |
2954 | switch (Size) { |
2955 | case 2: NewOpcode = X86::PUSH16r; break; |
2956 | case 4: NewOpcode = X86::PUSH32r; break; |
2957 | case 8: NewOpcode = X86::PUSH64r; break; |
2958 | default: |
2959 | llvm_unreachable("Unexpected size" ); |
2960 | } |
2961 | Inst.setOpcode(NewOpcode); |
2962 | Inst.addOperand(Op: MCOperand::createReg(Reg)); |
2963 | } |
2964 | |
2965 | void createPopRegister(MCInst &Inst, MCPhysReg Reg, |
2966 | unsigned Size) const override { |
2967 | Inst.clear(); |
2968 | unsigned NewOpcode = 0; |
2969 | if (Reg == X86::EFLAGS) { |
2970 | switch (Size) { |
2971 | case 2: NewOpcode = X86::POPF16; break; |
2972 | case 4: NewOpcode = X86::POPF32; break; |
2973 | case 8: NewOpcode = X86::POPF64; break; |
2974 | default: |
2975 | llvm_unreachable("Unexpected size" ); |
2976 | } |
2977 | Inst.setOpcode(NewOpcode); |
2978 | return; |
2979 | } |
2980 | switch (Size) { |
2981 | case 2: NewOpcode = X86::POP16r; break; |
2982 | case 4: NewOpcode = X86::POP32r; break; |
2983 | case 8: NewOpcode = X86::POP64r; break; |
2984 | default: |
2985 | llvm_unreachable("Unexpected size" ); |
2986 | } |
2987 | Inst.setOpcode(NewOpcode); |
2988 | Inst.addOperand(Op: MCOperand::createReg(Reg)); |
2989 | } |
2990 | |
2991 | void createPushFlags(MCInst &Inst, unsigned Size) const override { |
2992 | return createPushRegister(Inst, X86::EFLAGS, Size); |
2993 | } |
2994 | |
2995 | void createPopFlags(MCInst &Inst, unsigned Size) const override { |
2996 | return createPopRegister(Inst, X86::EFLAGS, Size); |
2997 | } |
2998 | |
2999 | void createAddRegImm(MCInst &Inst, MCPhysReg Reg, int64_t Value, |
3000 | unsigned Size) const { |
3001 | unsigned int Opcode; |
3002 | switch (Size) { |
3003 | case 1: Opcode = X86::ADD8ri; break; |
3004 | case 2: Opcode = X86::ADD16ri; break; |
3005 | case 4: Opcode = X86::ADD32ri; break; |
3006 | default: |
3007 | llvm_unreachable("Unexpected size" ); |
3008 | } |
3009 | Inst.setOpcode(Opcode); |
3010 | Inst.clear(); |
3011 | Inst.addOperand(Op: MCOperand::createReg(Reg)); |
3012 | Inst.addOperand(Op: MCOperand::createReg(Reg)); |
3013 | Inst.addOperand(Op: MCOperand::createImm(Val: Value)); |
3014 | } |
3015 | |
3016 | void createClearRegWithNoEFlagsUpdate(MCInst &Inst, MCPhysReg Reg, |
3017 | unsigned Size) const { |
3018 | unsigned int Opcode; |
3019 | switch (Size) { |
3020 | case 1: Opcode = X86::MOV8ri; break; |
3021 | case 2: Opcode = X86::MOV16ri; break; |
3022 | case 4: Opcode = X86::MOV32ri; break; |
3023 | // Writing to a 32-bit register always zeros the upper 32 bits of the |
3024 | // full-width register |
3025 | case 8: |
3026 | Opcode = X86::MOV32ri; |
3027 | Reg = getAliasSized(Reg, Size: 4); |
3028 | break; |
3029 | default: |
3030 | llvm_unreachable("Unexpected size" ); |
3031 | } |
3032 | Inst.setOpcode(Opcode); |
3033 | Inst.clear(); |
3034 | Inst.addOperand(Op: MCOperand::createReg(Reg)); |
3035 | Inst.addOperand(Op: MCOperand::createImm(Val: 0)); |
3036 | } |
3037 | |
3038 | void createX86SaveOVFlagToRegister(MCInst &Inst, MCPhysReg Reg) const { |
3039 | Inst.setOpcode(X86::SETCCr); |
3040 | Inst.clear(); |
3041 | Inst.addOperand(Op: MCOperand::createReg(Reg)); |
3042 | Inst.addOperand(Op: MCOperand::createImm(Val: X86::COND_O)); |
3043 | } |
3044 | |
3045 | void createX86Lahf(MCInst &Inst) const { |
3046 | Inst.setOpcode(X86::LAHF); |
3047 | Inst.clear(); |
3048 | } |
3049 | |
3050 | void createX86Sahf(MCInst &Inst) const { |
3051 | Inst.setOpcode(X86::SAHF); |
3052 | Inst.clear(); |
3053 | } |
3054 | |
3055 | InstructionListType |
3056 | createInstrIncMemory(const MCSymbol *Target, MCContext *Ctx, bool IsLeaf, |
3057 | unsigned CodePointerSize) const override { |
3058 | InstructionListType Instrs(IsLeaf ? 13 : 11); |
3059 | unsigned int I = 0; |
3060 | |
3061 | // Don't clobber application red zone (ABI dependent) |
3062 | if (IsLeaf) |
3063 | createStackPointerIncrement(Inst&: Instrs[I++], Size: 128, |
3064 | /*NoFlagsClobber=*/true); |
3065 | |
3066 | // Performance improvements based on the optimization discussed at |
3067 | // https://reviews.llvm.org/D6629 |
3068 | // LAHF/SAHF are used instead of PUSHF/POPF |
3069 | // PUSHF |
3070 | createPushRegister(Instrs[I++], X86::RAX, 8); |
3071 | createClearRegWithNoEFlagsUpdate(Instrs[I++], X86::RAX, 8); |
3072 | createX86Lahf(Inst&: Instrs[I++]); |
3073 | createPushRegister(Instrs[I++], X86::RAX, 8); |
3074 | createClearRegWithNoEFlagsUpdate(Instrs[I++], X86::RAX, 8); |
3075 | createX86SaveOVFlagToRegister(Instrs[I++], X86::AL); |
3076 | // LOCK INC |
3077 | InstructionListType IncMem = createIncMemory(Target, Ctx); |
3078 | assert(IncMem.size() == 1 && "Invalid IncMem size" ); |
3079 | std::copy(IncMem.begin(), IncMem.end(), Instrs.begin() + I); |
3080 | I += IncMem.size(); |
3081 | // POPF |
3082 | createAddRegImm(Instrs[I++], X86::AL, 127, 1); |
3083 | createPopRegister(Instrs[I++], X86::RAX, 8); |
3084 | createX86Sahf(Inst&: Instrs[I++]); |
3085 | createPopRegister(Instrs[I++], X86::RAX, 8); |
3086 | |
3087 | if (IsLeaf) |
3088 | createStackPointerDecrement(Inst&: Instrs[I], Size: 128, |
3089 | /*NoFlagsClobber=*/true); |
3090 | return Instrs; |
3091 | } |
3092 | |
3093 | void createSwap(MCInst &Inst, MCPhysReg Source, MCPhysReg MemBaseReg, |
3094 | int64_t Disp) const { |
3095 | Inst.setOpcode(X86::XCHG64rm); |
3096 | Inst.clear(); |
3097 | Inst.addOperand(Op: MCOperand::createReg(Reg: Source)); |
3098 | Inst.addOperand(Op: MCOperand::createReg(Reg: Source)); |
3099 | Inst.addOperand(Op: MCOperand::createReg(Reg: MemBaseReg)); // BaseReg |
3100 | Inst.addOperand(Op: MCOperand::createImm(Val: 1)); // ScaleAmt |
3101 | Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // IndexReg |
3102 | Inst.addOperand(Op: MCOperand::createImm(Val: Disp)); // Displacement |
3103 | Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg |
3104 | } |
3105 | |
3106 | void createIndirectBranch(MCInst &Inst, MCPhysReg MemBaseReg, |
3107 | int64_t Disp) const { |
3108 | Inst.setOpcode(X86::JMP64m); |
3109 | Inst.clear(); |
3110 | Inst.addOperand(Op: MCOperand::createReg(Reg: MemBaseReg)); // BaseReg |
3111 | Inst.addOperand(Op: MCOperand::createImm(Val: 1)); // ScaleAmt |
3112 | Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // IndexReg |
3113 | Inst.addOperand(Op: MCOperand::createImm(Val: Disp)); // Displacement |
3114 | Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg |
3115 | } |
3116 | |
3117 | InstructionListType createInstrumentedIndirectCall(MCInst &&CallInst, |
3118 | MCSymbol *HandlerFuncAddr, |
3119 | int CallSiteID, |
3120 | MCContext *Ctx) override { |
3121 | // Check if the target address expression used in the original indirect call |
3122 | // uses the stack pointer, which we are going to clobber. |
3123 | static BitVector SPAliases(getAliases(X86::RSP)); |
3124 | bool UsesSP = any_of(useOperands(Inst&: CallInst), [&](const MCOperand &Op) { |
3125 | return Op.isReg() && SPAliases[Op.getReg()]; |
3126 | }); |
3127 | |
3128 | InstructionListType Insts; |
3129 | MCPhysReg TempReg = getIntArgRegister(ArgNo: 0); |
3130 | // Code sequence used to enter indirect call instrumentation helper: |
3131 | // push %rdi |
3132 | // add $8, %rsp ;; $rsp may be used in target, so fix it to prev val |
3133 | // movq target, %rdi ;; via convertIndirectCallTargetToLoad |
3134 | // sub $8, %rsp ;; restore correct stack value |
3135 | // push %rdi |
3136 | // movq $CallSiteID, %rdi |
3137 | // push %rdi |
3138 | // callq/jmp HandlerFuncAddr |
3139 | Insts.emplace_back(); |
3140 | createPushRegister(Inst&: Insts.back(), Reg: TempReg, Size: 8); |
3141 | if (UsesSP) { // Only adjust SP if we really need to |
3142 | Insts.emplace_back(); |
3143 | createStackPointerDecrement(Inst&: Insts.back(), Size: 8, /*NoFlagsClobber=*/false); |
3144 | } |
3145 | Insts.emplace_back(CallInst); |
3146 | // Insts.back() and CallInst now share the same annotation instruction. |
3147 | // Strip it from Insts.back(), only preserving tail call annotation. |
3148 | stripAnnotations(Inst&: Insts.back(), /*KeepTC=*/true); |
3149 | convertIndirectCallToLoad(Inst&: Insts.back(), Reg: TempReg); |
3150 | if (UsesSP) { |
3151 | Insts.emplace_back(); |
3152 | createStackPointerIncrement(Inst&: Insts.back(), Size: 8, /*NoFlagsClobber=*/false); |
3153 | } |
3154 | Insts.emplace_back(); |
3155 | createPushRegister(Inst&: Insts.back(), Reg: TempReg, Size: 8); |
3156 | InstructionListType LoadImm = createLoadImmediate(Dest: TempReg, Imm: CallSiteID); |
3157 | Insts.insert(Insts.end(), LoadImm.begin(), LoadImm.end()); |
3158 | Insts.emplace_back(); |
3159 | createPushRegister(Inst&: Insts.back(), Reg: TempReg, Size: 8); |
3160 | |
3161 | MCInst &NewCallInst = Insts.emplace_back(); |
3162 | createDirectCall(Inst&: NewCallInst, Target: HandlerFuncAddr, Ctx, IsTailCall: isTailCall(Inst: CallInst)); |
3163 | |
3164 | // Carry over metadata including tail call marker if present. |
3165 | stripAnnotations(Inst&: NewCallInst); |
3166 | moveAnnotations(SrcInst: std::move(CallInst), DstInst&: NewCallInst); |
3167 | |
3168 | return Insts; |
3169 | } |
3170 | |
3171 | InstructionListType createInstrumentedIndCallHandlerExitBB() const override { |
3172 | const MCPhysReg TempReg = getIntArgRegister(ArgNo: 0); |
3173 | // We just need to undo the sequence created for every ind call in |
3174 | // instrumentIndirectTarget(), which can be accomplished minimally with: |
3175 | // popfq |
3176 | // pop %rdi |
3177 | // add $16, %rsp |
3178 | // xchg (%rsp), %rdi |
3179 | // jmp *-8(%rsp) |
3180 | InstructionListType Insts(5); |
3181 | createPopFlags(Inst&: Insts[0], Size: 8); |
3182 | createPopRegister(Inst&: Insts[1], Reg: TempReg, Size: 8); |
3183 | createStackPointerDecrement(Inst&: Insts[2], Size: 16, /*NoFlagsClobber=*/false); |
3184 | createSwap(Insts[3], TempReg, X86::RSP, 0); |
3185 | createIndirectBranch(Insts[4], X86::RSP, -8); |
3186 | return Insts; |
3187 | } |
3188 | |
3189 | InstructionListType |
3190 | createInstrumentedIndTailCallHandlerExitBB() const override { |
3191 | const MCPhysReg TempReg = getIntArgRegister(ArgNo: 0); |
3192 | // Same thing as above, but for tail calls |
3193 | // popfq |
3194 | // add $16, %rsp |
3195 | // pop %rdi |
3196 | // jmp *-16(%rsp) |
3197 | InstructionListType Insts(4); |
3198 | createPopFlags(Inst&: Insts[0], Size: 8); |
3199 | createStackPointerDecrement(Inst&: Insts[1], Size: 16, /*NoFlagsClobber=*/false); |
3200 | createPopRegister(Inst&: Insts[2], Reg: TempReg, Size: 8); |
3201 | createIndirectBranch(Insts[3], X86::RSP, -16); |
3202 | return Insts; |
3203 | } |
3204 | |
3205 | InstructionListType |
3206 | createInstrumentedIndCallHandlerEntryBB(const MCSymbol *InstrTrampoline, |
3207 | const MCSymbol *IndCallHandler, |
3208 | MCContext *Ctx) override { |
3209 | const MCPhysReg TempReg = getIntArgRegister(ArgNo: 0); |
3210 | // Code sequence used to check whether InstrTampoline was initialized |
3211 | // and call it if so, returns via IndCallHandler. |
3212 | // pushfq |
3213 | // mov InstrTrampoline,%rdi |
3214 | // cmp $0x0,%rdi |
3215 | // je IndCallHandler |
3216 | // callq *%rdi |
3217 | // jmpq IndCallHandler |
3218 | InstructionListType Insts; |
3219 | Insts.emplace_back(); |
3220 | createPushFlags(Inst&: Insts.back(), Size: 8); |
3221 | Insts.emplace_back(); |
3222 | createMove(Inst&: Insts.back(), Src: InstrTrampoline, Reg: TempReg, Ctx); |
3223 | InstructionListType cmpJmp = createCmpJE(RegNo: TempReg, Imm: 0, Target: IndCallHandler, Ctx); |
3224 | Insts.insert(Insts.end(), cmpJmp.begin(), cmpJmp.end()); |
3225 | Insts.emplace_back(); |
3226 | Insts.back().setOpcode(X86::CALL64r); |
3227 | Insts.back().addOperand(Op: MCOperand::createReg(Reg: TempReg)); |
3228 | Insts.emplace_back(); |
3229 | createDirectCall(Inst&: Insts.back(), Target: IndCallHandler, Ctx, /*IsTailCall*/ true); |
3230 | return Insts; |
3231 | } |
3232 | |
3233 | InstructionListType createNumCountersGetter(MCContext *Ctx) const override { |
3234 | InstructionListType Insts(2); |
3235 | MCSymbol *NumLocs = Ctx->getOrCreateSymbol(Name: "__bolt_num_counters" ); |
3236 | createMove(Insts[0], NumLocs, X86::EAX, Ctx); |
3237 | createReturn(Inst&: Insts[1]); |
3238 | return Insts; |
3239 | } |
3240 | |
3241 | InstructionListType |
3242 | createInstrLocationsGetter(MCContext *Ctx) const override { |
3243 | InstructionListType Insts(2); |
3244 | MCSymbol *Locs = Ctx->getOrCreateSymbol(Name: "__bolt_instr_locations" ); |
3245 | createLea(Insts[0], Locs, X86::EAX, Ctx); |
3246 | createReturn(Inst&: Insts[1]); |
3247 | return Insts; |
3248 | } |
3249 | |
3250 | InstructionListType createInstrTablesGetter(MCContext *Ctx) const override { |
3251 | InstructionListType Insts(2); |
3252 | MCSymbol *Locs = Ctx->getOrCreateSymbol(Name: "__bolt_instr_tables" ); |
3253 | createLea(Insts[0], Locs, X86::EAX, Ctx); |
3254 | createReturn(Inst&: Insts[1]); |
3255 | return Insts; |
3256 | } |
3257 | |
3258 | InstructionListType createInstrNumFuncsGetter(MCContext *Ctx) const override { |
3259 | InstructionListType Insts(2); |
3260 | MCSymbol *NumFuncs = Ctx->getOrCreateSymbol(Name: "__bolt_instr_num_funcs" ); |
3261 | createMove(Insts[0], NumFuncs, X86::EAX, Ctx); |
3262 | createReturn(Inst&: Insts[1]); |
3263 | return Insts; |
3264 | } |
3265 | |
3266 | InstructionListType createSymbolTrampoline(const MCSymbol *TgtSym, |
3267 | MCContext *Ctx) override { |
3268 | InstructionListType Insts(1); |
3269 | createUncondBranch(Inst&: Insts[0], TBB: TgtSym, Ctx); |
3270 | return Insts; |
3271 | } |
3272 | |
3273 | BlocksVectorTy indirectCallPromotion( |
3274 | const MCInst &CallInst, |
3275 | const std::vector<std::pair<MCSymbol *, uint64_t>> &Targets, |
3276 | const std::vector<std::pair<MCSymbol *, uint64_t>> &VtableSyms, |
3277 | const std::vector<MCInst *> &MethodFetchInsns, |
3278 | const bool MinimizeCodeSize, MCContext *Ctx) override { |
3279 | const bool IsTailCall = isTailCall(Inst: CallInst); |
3280 | const bool IsJumpTable = getJumpTable(Inst: CallInst) != 0; |
3281 | BlocksVectorTy Results; |
3282 | |
3283 | // Label for the current code block. |
3284 | MCSymbol *NextTarget = nullptr; |
3285 | |
3286 | // The join block which contains all the instructions following CallInst. |
3287 | // MergeBlock remains null if CallInst is a tail call. |
3288 | MCSymbol *MergeBlock = nullptr; |
3289 | |
3290 | unsigned FuncAddrReg = X86::R10; |
3291 | |
3292 | const bool LoadElim = !VtableSyms.empty(); |
3293 | assert((!LoadElim || VtableSyms.size() == Targets.size()) && |
3294 | "There must be a vtable entry for every method " |
3295 | "in the targets vector." ); |
3296 | |
3297 | if (MinimizeCodeSize && !LoadElim) { |
3298 | std::set<unsigned> UsedRegs; |
3299 | |
3300 | for (unsigned int I = 0; I < MCPlus::getNumPrimeOperands(Inst: CallInst); ++I) { |
3301 | const MCOperand &Op = CallInst.getOperand(i: I); |
3302 | if (Op.isReg()) |
3303 | UsedRegs.insert(Op.getReg()); |
3304 | } |
3305 | |
3306 | if (UsedRegs.count(X86::R10) == 0) |
3307 | FuncAddrReg = X86::R10; |
3308 | else if (UsedRegs.count(X86::R11) == 0) |
3309 | FuncAddrReg = X86::R11; |
3310 | else |
3311 | return Results; |
3312 | } |
3313 | |
3314 | const auto jumpToMergeBlock = [&](InstructionListType &NewCall) { |
3315 | assert(MergeBlock); |
3316 | NewCall.push_back(x: CallInst); |
3317 | MCInst &Merge = NewCall.back(); |
3318 | Merge.clear(); |
3319 | createUncondBranch(Inst&: Merge, TBB: MergeBlock, Ctx); |
3320 | }; |
3321 | |
3322 | for (unsigned int i = 0; i < Targets.size(); ++i) { |
3323 | Results.emplace_back(NextTarget, InstructionListType()); |
3324 | InstructionListType *NewCall = &Results.back().second; |
3325 | |
3326 | if (MinimizeCodeSize && !LoadElim) { |
3327 | // Load the call target into FuncAddrReg. |
3328 | NewCall->push_back(x: CallInst); // Copy CallInst in order to get SMLoc |
3329 | MCInst &Target = NewCall->back(); |
3330 | Target.clear(); |
3331 | Target.setOpcode(X86::MOV64ri32); |
3332 | Target.addOperand(Op: MCOperand::createReg(Reg: FuncAddrReg)); |
3333 | if (Targets[i].first) { |
3334 | // Is this OK? |
3335 | Target.addOperand(Op: MCOperand::createExpr(Val: MCSymbolRefExpr::create( |
3336 | Targets[i].first, MCSymbolRefExpr::VK_None, *Ctx))); |
3337 | } else { |
3338 | const uint64_t Addr = Targets[i].second; |
3339 | // Immediate address is out of sign extended 32 bit range. |
3340 | if (int64_t(Addr) != int64_t(int32_t(Addr))) |
3341 | return BlocksVectorTy(); |
3342 | |
3343 | Target.addOperand(Op: MCOperand::createImm(Val: Addr)); |
3344 | } |
3345 | |
3346 | // Compare current call target to a specific address. |
3347 | NewCall->push_back(x: CallInst); |
3348 | MCInst &Compare = NewCall->back(); |
3349 | Compare.clear(); |
3350 | if (isBranchOnReg(CallInst)) |
3351 | Compare.setOpcode(X86::CMP64rr); |
3352 | else if (CallInst.getOpcode() == X86::CALL64pcrel32) |
3353 | Compare.setOpcode(X86::CMP64ri32); |
3354 | else |
3355 | Compare.setOpcode(X86::CMP64rm); |
3356 | |
3357 | Compare.addOperand(Op: MCOperand::createReg(Reg: FuncAddrReg)); |
3358 | |
3359 | // TODO: Would be preferable to only load this value once. |
3360 | for (unsigned i = 0; |
3361 | i < Info->get(Opcode: CallInst.getOpcode()).getNumOperands(); ++i) |
3362 | if (!CallInst.getOperand(i).isInst()) |
3363 | Compare.addOperand(Op: CallInst.getOperand(i)); |
3364 | } else { |
3365 | // Compare current call target to a specific address. |
3366 | NewCall->push_back(x: CallInst); |
3367 | MCInst &Compare = NewCall->back(); |
3368 | Compare.clear(); |
3369 | if (isBranchOnReg(CallInst)) |
3370 | Compare.setOpcode(X86::CMP64ri32); |
3371 | else |
3372 | Compare.setOpcode(X86::CMP64mi32); |
3373 | |
3374 | // Original call address. |
3375 | for (unsigned i = 0; |
3376 | i < Info->get(Opcode: CallInst.getOpcode()).getNumOperands(); ++i) |
3377 | if (!CallInst.getOperand(i).isInst()) |
3378 | Compare.addOperand(Op: CallInst.getOperand(i)); |
3379 | |
3380 | // Target address. |
3381 | if (Targets[i].first || LoadElim) { |
3382 | const MCSymbol *Sym = |
3383 | LoadElim ? VtableSyms[i].first : Targets[i].first; |
3384 | const uint64_t Addend = LoadElim ? VtableSyms[i].second : 0; |
3385 | const MCExpr *Expr = MCSymbolRefExpr::create(Symbol: Sym, Ctx&: *Ctx); |
3386 | if (Addend) |
3387 | Expr = MCBinaryExpr::createAdd( |
3388 | LHS: Expr, RHS: MCConstantExpr::create(Value: Addend, Ctx&: *Ctx), Ctx&: *Ctx); |
3389 | Compare.addOperand(Op: MCOperand::createExpr(Val: Expr)); |
3390 | } else { |
3391 | const uint64_t Addr = Targets[i].second; |
3392 | // Immediate address is out of sign extended 32 bit range. |
3393 | if (int64_t(Addr) != int64_t(int32_t(Addr))) |
3394 | return BlocksVectorTy(); |
3395 | |
3396 | Compare.addOperand(Op: MCOperand::createImm(Val: Addr)); |
3397 | } |
3398 | } |
3399 | |
3400 | // jump to next target compare. |
3401 | NextTarget = |
3402 | Ctx->createNamedTempSymbol(); // generate label for the next block |
3403 | NewCall->push_back(x: CallInst); |
3404 | |
3405 | if (IsJumpTable) { |
3406 | MCInst &Je = NewCall->back(); |
3407 | |
3408 | // Jump to next compare if target addresses don't match. |
3409 | Je.clear(); |
3410 | Je.setOpcode(X86::JCC_1); |
3411 | if (Targets[i].first) |
3412 | Je.addOperand(Op: MCOperand::createExpr(Val: MCSymbolRefExpr::create( |
3413 | Targets[i].first, MCSymbolRefExpr::VK_None, *Ctx))); |
3414 | else |
3415 | Je.addOperand(Op: MCOperand::createImm(Val: Targets[i].second)); |
3416 | |
3417 | Je.addOperand(Op: MCOperand::createImm(Val: X86::COND_E)); |
3418 | assert(!isInvoke(CallInst)); |
3419 | } else { |
3420 | MCInst &Jne = NewCall->back(); |
3421 | |
3422 | // Jump to next compare if target addresses don't match. |
3423 | Jne.clear(); |
3424 | Jne.setOpcode(X86::JCC_1); |
3425 | Jne.addOperand(Op: MCOperand::createExpr(Val: MCSymbolRefExpr::create( |
3426 | Symbol: NextTarget, Kind: MCSymbolRefExpr::VK_None, Ctx&: *Ctx))); |
3427 | Jne.addOperand(Op: MCOperand::createImm(Val: X86::COND_NE)); |
3428 | |
3429 | // Call specific target directly. |
3430 | Results.emplace_back(Ctx->createNamedTempSymbol(), |
3431 | InstructionListType()); |
3432 | NewCall = &Results.back().second; |
3433 | NewCall->push_back(x: CallInst); |
3434 | MCInst &CallOrJmp = NewCall->back(); |
3435 | |
3436 | CallOrJmp.clear(); |
3437 | |
3438 | if (MinimizeCodeSize && !LoadElim) { |
3439 | CallOrJmp.setOpcode(IsTailCall ? X86::JMP32r : X86::CALL64r); |
3440 | CallOrJmp.addOperand(Op: MCOperand::createReg(Reg: FuncAddrReg)); |
3441 | } else { |
3442 | CallOrJmp.setOpcode(IsTailCall ? X86::JMP_4 : X86::CALL64pcrel32); |
3443 | |
3444 | if (Targets[i].first) |
3445 | CallOrJmp.addOperand(Op: MCOperand::createExpr(Val: MCSymbolRefExpr::create( |
3446 | Targets[i].first, MCSymbolRefExpr::VK_None, *Ctx))); |
3447 | else |
3448 | CallOrJmp.addOperand(Op: MCOperand::createImm(Val: Targets[i].second)); |
3449 | } |
3450 | if (IsTailCall) |
3451 | setTailCall(CallOrJmp); |
3452 | |
3453 | if (CallOrJmp.getOpcode() == X86::CALL64r || |
3454 | CallOrJmp.getOpcode() == X86::CALL64pcrel32) { |
3455 | if (std::optional<uint32_t> Offset = getOffset(Inst: CallInst)) |
3456 | // Annotated as duplicated call |
3457 | setOffset(Inst&: CallOrJmp, Offset: *Offset); |
3458 | } |
3459 | |
3460 | if (isInvoke(Inst: CallInst) && !isInvoke(Inst: CallOrJmp)) { |
3461 | // Copy over any EH or GNU args size information from the original |
3462 | // call. |
3463 | std::optional<MCPlus::MCLandingPad> EHInfo = getEHInfo(CallInst); |
3464 | if (EHInfo) |
3465 | addEHInfo(Inst&: CallOrJmp, LP: *EHInfo); |
3466 | int64_t GnuArgsSize = getGnuArgsSize(Inst: CallInst); |
3467 | if (GnuArgsSize >= 0) |
3468 | addGnuArgsSize(Inst&: CallOrJmp, GnuArgsSize); |
3469 | } |
3470 | |
3471 | if (!IsTailCall) { |
3472 | // The fallthrough block for the most common target should be |
3473 | // the merge block. |
3474 | if (i == 0) { |
3475 | // Fallthrough to merge block. |
3476 | MergeBlock = Ctx->createNamedTempSymbol(); |
3477 | } else { |
3478 | // Insert jump to the merge block if we are not doing a fallthrough. |
3479 | jumpToMergeBlock(*NewCall); |
3480 | } |
3481 | } |
3482 | } |
3483 | } |
3484 | |
3485 | // Cold call block. |
3486 | Results.emplace_back(NextTarget, InstructionListType()); |
3487 | InstructionListType &NewCall = Results.back().second; |
3488 | for (const MCInst *Inst : MethodFetchInsns) |
3489 | if (Inst != &CallInst) |
3490 | NewCall.push_back(*Inst); |
3491 | NewCall.push_back(x: CallInst); |
3492 | |
3493 | // Jump to merge block from cold call block |
3494 | if (!IsTailCall && !IsJumpTable) { |
3495 | jumpToMergeBlock(NewCall); |
3496 | |
3497 | // Record merge block |
3498 | Results.emplace_back(MergeBlock, InstructionListType()); |
3499 | } |
3500 | |
3501 | return Results; |
3502 | } |
3503 | |
3504 | BlocksVectorTy jumpTablePromotion( |
3505 | const MCInst &IJmpInst, |
3506 | const std::vector<std::pair<MCSymbol *, uint64_t>> &Targets, |
3507 | const std::vector<MCInst *> &TargetFetchInsns, |
3508 | MCContext *Ctx) const override { |
3509 | assert(getJumpTable(IJmpInst) != 0); |
3510 | uint16_t IndexReg = getAnnotationAs<uint16_t>(IJmpInst, "JTIndexReg" ); |
3511 | if (IndexReg == 0) |
3512 | return BlocksVectorTy(); |
3513 | |
3514 | BlocksVectorTy Results; |
3515 | |
3516 | // Label for the current code block. |
3517 | MCSymbol *NextTarget = nullptr; |
3518 | |
3519 | for (unsigned int i = 0; i < Targets.size(); ++i) { |
3520 | Results.emplace_back(NextTarget, InstructionListType()); |
3521 | InstructionListType *CurBB = &Results.back().second; |
3522 | |
3523 | // Compare current index to a specific index. |
3524 | CurBB->emplace_back(MCInst()); |
3525 | MCInst &CompareInst = CurBB->back(); |
3526 | CompareInst.setLoc(IJmpInst.getLoc()); |
3527 | CompareInst.setOpcode(X86::CMP64ri32); |
3528 | CompareInst.addOperand(Op: MCOperand::createReg(Reg: IndexReg)); |
3529 | |
3530 | const uint64_t CaseIdx = Targets[i].second; |
3531 | // Immediate address is out of sign extended 32 bit range. |
3532 | if (int64_t(CaseIdx) != int64_t(int32_t(CaseIdx))) |
3533 | return BlocksVectorTy(); |
3534 | |
3535 | CompareInst.addOperand(Op: MCOperand::createImm(Val: CaseIdx)); |
3536 | shortenInstruction(Inst&: CompareInst, STI: *Ctx->getSubtargetInfo()); |
3537 | |
3538 | // jump to next target compare. |
3539 | NextTarget = |
3540 | Ctx->createNamedTempSymbol(); // generate label for the next block |
3541 | CurBB->push_back(x: MCInst()); |
3542 | |
3543 | MCInst &JEInst = CurBB->back(); |
3544 | JEInst.setLoc(IJmpInst.getLoc()); |
3545 | |
3546 | // Jump to target if indices match |
3547 | JEInst.setOpcode(X86::JCC_1); |
3548 | JEInst.addOperand(Op: MCOperand::createExpr(Val: MCSymbolRefExpr::create( |
3549 | Targets[i].first, MCSymbolRefExpr::VK_None, *Ctx))); |
3550 | JEInst.addOperand(Op: MCOperand::createImm(Val: X86::COND_E)); |
3551 | } |
3552 | |
3553 | // Cold call block. |
3554 | Results.emplace_back(NextTarget, InstructionListType()); |
3555 | InstructionListType &CurBB = Results.back().second; |
3556 | for (const MCInst *Inst : TargetFetchInsns) |
3557 | if (Inst != &IJmpInst) |
3558 | CurBB.push_back(*Inst); |
3559 | |
3560 | CurBB.push_back(x: IJmpInst); |
3561 | |
3562 | return Results; |
3563 | } |
3564 | |
3565 | private: |
3566 | void createMove(MCInst &Inst, const MCSymbol *Src, unsigned Reg, |
3567 | MCContext *Ctx) const { |
3568 | Inst.setOpcode(X86::MOV64rm); |
3569 | Inst.clear(); |
3570 | Inst.addOperand(Op: MCOperand::createReg(Reg)); |
3571 | Inst.addOperand(MCOperand::createReg(X86::RIP)); // BaseReg |
3572 | Inst.addOperand(Op: MCOperand::createImm(Val: 1)); // ScaleAmt |
3573 | Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // IndexReg |
3574 | Inst.addOperand(Op: MCOperand::createExpr( |
3575 | Val: MCSymbolRefExpr::create(Symbol: Src, Kind: MCSymbolRefExpr::VK_None, |
3576 | Ctx&: *Ctx))); // Displacement |
3577 | Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg |
3578 | } |
3579 | |
3580 | void createLea(MCInst &Inst, const MCSymbol *Src, unsigned Reg, |
3581 | MCContext *Ctx) const { |
3582 | Inst.setOpcode(X86::LEA64r); |
3583 | Inst.clear(); |
3584 | Inst.addOperand(Op: MCOperand::createReg(Reg)); |
3585 | Inst.addOperand(MCOperand::createReg(X86::RIP)); // BaseReg |
3586 | Inst.addOperand(Op: MCOperand::createImm(Val: 1)); // ScaleAmt |
3587 | Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // IndexReg |
3588 | Inst.addOperand(Op: MCOperand::createExpr( |
3589 | Val: MCSymbolRefExpr::create(Symbol: Src, Kind: MCSymbolRefExpr::VK_None, |
3590 | Ctx&: *Ctx))); // Displacement |
3591 | Inst.addOperand(MCOperand::createReg(X86::NoRegister)); // AddrSegmentReg |
3592 | } |
3593 | }; |
3594 | |
3595 | } // namespace |
3596 | |
3597 | namespace llvm { |
3598 | namespace bolt { |
3599 | |
3600 | MCPlusBuilder *createX86MCPlusBuilder(const MCInstrAnalysis *Analysis, |
3601 | const MCInstrInfo *Info, |
3602 | const MCRegisterInfo *RegInfo, |
3603 | const MCSubtargetInfo *STI) { |
3604 | return new X86MCPlusBuilder(Analysis, Info, RegInfo, STI); |
3605 | } |
3606 | |
3607 | } // namespace bolt |
3608 | } // namespace llvm |
3609 | |