1//===- bolt/Core/MCPlusBuilder.cpp - Interface for MCPlus -----------------===//
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 implements the MCPlusBuilder class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "bolt/Core/MCPlusBuilder.h"
14#include "bolt/Core/MCPlus.h"
15#include "bolt/Utils/CommandLineOpts.h"
16#include "llvm/MC/MCContext.h"
17#include "llvm/MC/MCInst.h"
18#include "llvm/MC/MCInstrAnalysis.h"
19#include "llvm/MC/MCInstrDesc.h"
20#include "llvm/MC/MCInstrInfo.h"
21#include "llvm/MC/MCRegisterInfo.h"
22#include "llvm/Support/CommandLine.h"
23#include "llvm/Support/Debug.h"
24#include <cstdint>
25
26#define DEBUG_TYPE "mcplus"
27
28using namespace llvm;
29using namespace bolt;
30using namespace MCPlus;
31
32namespace opts {
33cl::opt<bool>
34 TerminalTrap("terminal-trap",
35 cl::desc("Assume that execution stops at trap instruction"),
36 cl::init(Val: true), cl::Hidden, cl::cat(BoltCategory));
37}
38
39bool MCPlusBuilder::equals(const MCInst &A, const MCInst &B,
40 CompFuncTy Comp) const {
41 if (A.getOpcode() != B.getOpcode())
42 return false;
43
44 unsigned NumOperands = MCPlus::getNumPrimeOperands(Inst: A);
45 if (NumOperands != MCPlus::getNumPrimeOperands(Inst: B))
46 return false;
47
48 for (unsigned Index = 0; Index < NumOperands; ++Index)
49 if (!equals(A: A.getOperand(i: Index), B: B.getOperand(i: Index), Comp))
50 return false;
51
52 return true;
53}
54
55bool MCPlusBuilder::equals(const MCOperand &A, const MCOperand &B,
56 CompFuncTy Comp) const {
57 if (A.isReg()) {
58 if (!B.isReg())
59 return false;
60 return A.getReg() == B.getReg();
61 } else if (A.isImm()) {
62 if (!B.isImm())
63 return false;
64 return A.getImm() == B.getImm();
65 } else if (A.isSFPImm()) {
66 if (!B.isSFPImm())
67 return false;
68 return A.getSFPImm() == B.getSFPImm();
69 } else if (A.isDFPImm()) {
70 if (!B.isDFPImm())
71 return false;
72 return A.getDFPImm() == B.getDFPImm();
73 } else if (A.isExpr()) {
74 if (!B.isExpr())
75 return false;
76 return equals(A: *A.getExpr(), B: *B.getExpr(), Comp);
77 } else {
78 llvm_unreachable("unexpected operand kind");
79 return false;
80 }
81}
82
83bool MCPlusBuilder::equals(const MCExpr &A, const MCExpr &B,
84 CompFuncTy Comp) const {
85 if (A.getKind() != B.getKind())
86 return false;
87
88 switch (A.getKind()) {
89 case MCExpr::Constant: {
90 const auto &ConstA = cast<MCConstantExpr>(Val: A);
91 const auto &ConstB = cast<MCConstantExpr>(Val: B);
92 return ConstA.getValue() == ConstB.getValue();
93 }
94
95 case MCExpr::SymbolRef: {
96 const MCSymbolRefExpr &SymbolA = cast<MCSymbolRefExpr>(Val: A);
97 const MCSymbolRefExpr &SymbolB = cast<MCSymbolRefExpr>(Val: B);
98 return SymbolA.getKind() == SymbolB.getKind() &&
99 Comp(&SymbolA.getSymbol(), &SymbolB.getSymbol());
100 }
101
102 case MCExpr::Unary: {
103 const auto &UnaryA = cast<MCUnaryExpr>(Val: A);
104 const auto &UnaryB = cast<MCUnaryExpr>(Val: B);
105 return UnaryA.getOpcode() == UnaryB.getOpcode() &&
106 equals(A: *UnaryA.getSubExpr(), B: *UnaryB.getSubExpr(), Comp);
107 }
108
109 case MCExpr::Binary: {
110 const auto &BinaryA = cast<MCBinaryExpr>(Val: A);
111 const auto &BinaryB = cast<MCBinaryExpr>(Val: B);
112 return BinaryA.getOpcode() == BinaryB.getOpcode() &&
113 equals(A: *BinaryA.getLHS(), B: *BinaryB.getLHS(), Comp) &&
114 equals(A: *BinaryA.getRHS(), B: *BinaryB.getRHS(), Comp);
115 }
116
117 case MCExpr::Specifier: {
118 const auto &TargetExprA = cast<MCSpecifierExpr>(Val: A);
119 const auto &TargetExprB = cast<MCSpecifierExpr>(Val: B);
120 return equals(A: TargetExprA, B: TargetExprB, Comp);
121 }
122 case MCExpr::Target:
123 llvm_unreachable("Not implemented");
124 }
125
126 llvm_unreachable("Invalid expression kind!");
127}
128
129bool MCPlusBuilder::equals(const MCSpecifierExpr &A, const MCSpecifierExpr &B,
130 CompFuncTy Comp) const {
131 llvm_unreachable("target-specific expressions are unsupported");
132}
133
134bool MCPlusBuilder::isTerminator(const MCInst &Inst) const {
135 return Analysis->isTerminator(Inst) ||
136 (opts::TerminalTrap && Info->get(Opcode: Inst.getOpcode()).isTrap());
137}
138
139void MCPlusBuilder::setTailCall(MCInst &Inst) const {
140 assert(!hasAnnotation(Inst, MCAnnotation::kTailCall));
141 setAnnotationOpValue(Inst, Index: MCAnnotation::kTailCall, Value: true);
142}
143
144bool MCPlusBuilder::isTailCall(const MCInst &Inst) const {
145 if (hasAnnotation(Inst, Index: MCAnnotation::kTailCall))
146 return true;
147 if (getConditionalTailCall(Inst))
148 return true;
149 return false;
150}
151
152std::optional<MCLandingPad> MCPlusBuilder::getEHInfo(const MCInst &Inst) const {
153 if (!isCall(Inst))
154 return std::nullopt;
155 std::optional<int64_t> LPSym =
156 getAnnotationOpValue(Inst, Index: MCAnnotation::kEHLandingPad);
157 if (!LPSym)
158 return std::nullopt;
159 std::optional<int64_t> Action =
160 getAnnotationOpValue(Inst, Index: MCAnnotation::kEHAction);
161 if (!Action)
162 return std::nullopt;
163
164 return std::make_pair(x: reinterpret_cast<const MCSymbol *>(*LPSym),
165 y: static_cast<uint64_t>(*Action));
166}
167
168void MCPlusBuilder::addEHInfo(MCInst &Inst, const MCLandingPad &LP) const {
169 if (isCall(Inst)) {
170 assert(!getEHInfo(Inst));
171 setAnnotationOpValue(Inst, Index: MCAnnotation::kEHLandingPad,
172 Value: reinterpret_cast<int64_t>(LP.first));
173 setAnnotationOpValue(Inst, Index: MCAnnotation::kEHAction,
174 Value: static_cast<int64_t>(LP.second));
175 }
176}
177
178bool MCPlusBuilder::updateEHInfo(MCInst &Inst, const MCLandingPad &LP) const {
179 if (!isInvoke(Inst))
180 return false;
181
182 setAnnotationOpValue(Inst, Index: MCAnnotation::kEHLandingPad,
183 Value: reinterpret_cast<int64_t>(LP.first));
184 setAnnotationOpValue(Inst, Index: MCAnnotation::kEHAction,
185 Value: static_cast<int64_t>(LP.second));
186 return true;
187}
188
189int64_t MCPlusBuilder::getGnuArgsSize(const MCInst &Inst) const {
190 std::optional<int64_t> Value =
191 getAnnotationOpValue(Inst, Index: MCAnnotation::kGnuArgsSize);
192 if (!Value)
193 return -1LL;
194 return *Value;
195}
196
197void MCPlusBuilder::addGnuArgsSize(MCInst &Inst, int64_t GnuArgsSize) const {
198 assert(GnuArgsSize >= 0 && "cannot set GNU_args_size to negative value");
199 assert(getGnuArgsSize(Inst) == -1LL && "GNU_args_size already set");
200 assert(isInvoke(Inst) && "GNU_args_size can only be set for invoke");
201
202 setAnnotationOpValue(Inst, Index: MCAnnotation::kGnuArgsSize, Value: GnuArgsSize);
203}
204
205uint64_t MCPlusBuilder::getJumpTable(const MCInst &Inst) const {
206 std::optional<int64_t> Value =
207 getAnnotationOpValue(Inst, Index: MCAnnotation::kJumpTable);
208 if (!Value)
209 return 0;
210 return *Value;
211}
212
213uint16_t MCPlusBuilder::getJumpTableIndexReg(const MCInst &Inst) const {
214 return getAnnotationAs<uint16_t>(Inst, Name: "JTIndexReg");
215}
216
217bool MCPlusBuilder::setJumpTable(MCInst &Inst, uint64_t Value,
218 uint16_t IndexReg, AllocatorIdTy AllocId) {
219 if (!isIndirectBranch(Inst))
220 return false;
221 setAnnotationOpValue(Inst, Index: MCAnnotation::kJumpTable, Value);
222 getOrCreateAnnotationAs<uint16_t>(Inst, Name: "JTIndexReg", AllocatorId: AllocId) = IndexReg;
223 return true;
224}
225
226bool MCPlusBuilder::unsetJumpTable(MCInst &Inst) const {
227 if (!getJumpTable(Inst))
228 return false;
229 removeAnnotation(Inst, Index: MCAnnotation::kJumpTable);
230 removeAnnotation(Inst, Name: "JTIndexReg");
231 return true;
232}
233
234std::optional<uint64_t>
235MCPlusBuilder::getConditionalTailCall(const MCInst &Inst) const {
236 std::optional<int64_t> Value =
237 getAnnotationOpValue(Inst, Index: MCAnnotation::kConditionalTailCall);
238 if (!Value)
239 return std::nullopt;
240 return static_cast<uint64_t>(*Value);
241}
242
243bool MCPlusBuilder::setConditionalTailCall(MCInst &Inst, uint64_t Dest) const {
244 if (!isConditionalBranch(Inst))
245 return false;
246
247 setAnnotationOpValue(Inst, Index: MCAnnotation::kConditionalTailCall, Value: Dest);
248 return true;
249}
250
251bool MCPlusBuilder::unsetConditionalTailCall(MCInst &Inst) const {
252 if (!getConditionalTailCall(Inst))
253 return false;
254 removeAnnotation(Inst, Index: MCAnnotation::kConditionalTailCall);
255 return true;
256}
257
258std::optional<uint32_t> MCPlusBuilder::getOffset(const MCInst &Inst) const {
259 std::optional<int64_t> Value =
260 getAnnotationOpValue(Inst, Index: MCAnnotation::kOffset);
261 if (!Value)
262 return std::nullopt;
263 return static_cast<uint32_t>(*Value);
264}
265
266uint32_t MCPlusBuilder::getOffsetWithDefault(const MCInst &Inst,
267 uint32_t Default) const {
268 if (std::optional<uint32_t> Offset = getOffset(Inst))
269 return *Offset;
270 return Default;
271}
272
273bool MCPlusBuilder::setOffset(MCInst &Inst, uint32_t Offset) const {
274 setAnnotationOpValue(Inst, Index: MCAnnotation::kOffset, Value: Offset);
275 return true;
276}
277
278bool MCPlusBuilder::clearOffset(MCInst &Inst) const {
279 if (!hasAnnotation(Inst, Index: MCAnnotation::kOffset))
280 return false;
281 removeAnnotation(Inst, Index: MCAnnotation::kOffset);
282 return true;
283}
284
285MCSymbol *MCPlusBuilder::getInstLabel(const MCInst &Inst) const {
286 if (std::optional<int64_t> Label =
287 getAnnotationOpValue(Inst, Index: MCAnnotation::kLabel))
288 return reinterpret_cast<MCSymbol *>(*Label);
289 return nullptr;
290}
291
292MCSymbol *MCPlusBuilder::getOrCreateInstLabel(MCInst &Inst, const Twine &Name,
293 MCContext *Ctx) const {
294 MCSymbol *Label = getInstLabel(Inst);
295 if (Label)
296 return Label;
297
298 Label = Ctx->createNamedTempSymbol(Name);
299 setAnnotationOpValue(Inst, Index: MCAnnotation::kLabel,
300 Value: reinterpret_cast<int64_t>(Label));
301 return Label;
302}
303
304void MCPlusBuilder::setInstLabel(MCInst &Inst, MCSymbol *Label) const {
305 assert(!getInstLabel(Inst) && "Instruction already has assigned label.");
306 setAnnotationOpValue(Inst, Index: MCAnnotation::kLabel,
307 Value: reinterpret_cast<int64_t>(Label));
308}
309
310std::optional<uint32_t> MCPlusBuilder::getSize(const MCInst &Inst) const {
311 if (std::optional<int64_t> Value =
312 getAnnotationOpValue(Inst, Index: MCAnnotation::kSize))
313 return static_cast<uint32_t>(*Value);
314 return std::nullopt;
315}
316
317void MCPlusBuilder::setSize(MCInst &Inst, uint32_t Size) const {
318 setAnnotationOpValue(Inst, Index: MCAnnotation::kSize, Value: Size);
319}
320
321bool MCPlusBuilder::isDynamicBranch(const MCInst &Inst) const {
322 if (!hasAnnotation(Inst, Index: MCAnnotation::kDynamicBranch))
323 return false;
324 assert(isBranch(Inst) && "Branch expected.");
325 return true;
326}
327
328std::optional<uint32_t>
329MCPlusBuilder::getDynamicBranchID(const MCInst &Inst) const {
330 if (std::optional<int64_t> Value =
331 getAnnotationOpValue(Inst, Index: MCAnnotation::kDynamicBranch)) {
332 assert(isBranch(Inst) && "Branch expected.");
333 return static_cast<uint32_t>(*Value);
334 }
335 return std::nullopt;
336}
337
338void MCPlusBuilder::setDynamicBranch(MCInst &Inst, uint32_t ID) const {
339 assert(isBranch(Inst) && "Branch expected.");
340 setAnnotationOpValue(Inst, Index: MCAnnotation::kDynamicBranch, Value: ID);
341}
342
343bool MCPlusBuilder::hasAnnotation(const MCInst &Inst, unsigned Index) const {
344 return (bool)getAnnotationOpValue(Inst, Index);
345}
346
347bool MCPlusBuilder::removeAnnotation(MCInst &Inst, unsigned Index) const {
348 std::optional<unsigned> FirstAnnotationOp = getFirstAnnotationOpIndex(Inst);
349 if (!FirstAnnotationOp)
350 return false;
351
352 for (unsigned I = Inst.getNumOperands() - 1; I >= *FirstAnnotationOp; --I) {
353 const int64_t ImmValue = Inst.getOperand(i: I).getImm();
354 if (extractAnnotationIndex(ImmValue) == Index) {
355 Inst.erase(I: Inst.begin() + I);
356 return true;
357 }
358 }
359 return false;
360}
361
362void MCPlusBuilder::stripAnnotations(MCInst &Inst, bool KeepTC) const {
363 KeepTC &= hasAnnotation(Inst, Index: MCAnnotation::kTailCall);
364
365 removeAnnotations(Inst);
366
367 if (KeepTC)
368 setTailCall(Inst);
369}
370
371void MCPlusBuilder::printAnnotations(const MCInst &Inst,
372 raw_ostream &OS) const {
373 std::optional<unsigned> FirstAnnotationOp = getFirstAnnotationOpIndex(Inst);
374 if (!FirstAnnotationOp)
375 return;
376
377 for (unsigned I = *FirstAnnotationOp; I < Inst.getNumOperands(); ++I) {
378 const int64_t Imm = Inst.getOperand(i: I).getImm();
379 const unsigned Index = extractAnnotationIndex(ImmValue: Imm);
380 const int64_t Value = extractAnnotationValue(ImmValue: Imm);
381 const auto *Annotation = reinterpret_cast<const MCAnnotation *>(Value);
382 if (Index >= MCAnnotation::kGeneric) {
383 OS << " # " << AnnotationNames[Index - MCAnnotation::kGeneric] << ": ";
384 Annotation->print(OS);
385 }
386 }
387}
388
389void MCPlusBuilder::getClobberedRegs(const MCInst &Inst,
390 BitVector &Regs) const {
391 if (isPrefix(Inst) || isCFI(Inst))
392 return;
393
394 const MCInstrDesc &InstInfo = Info->get(Opcode: Inst.getOpcode());
395
396 for (MCPhysReg ImplicitDef : InstInfo.implicit_defs())
397 Regs |= getAliases(Reg: ImplicitDef, /*OnlySmaller=*/false);
398
399 for (const MCOperand &Operand : defOperands(Inst)) {
400 assert(Operand.isReg());
401 Regs |= getAliases(Reg: Operand.getReg(), /*OnlySmaller=*/false);
402 }
403}
404
405void MCPlusBuilder::getTouchedRegs(const MCInst &Inst, BitVector &Regs) const {
406 if (isPrefix(Inst) || isCFI(Inst))
407 return;
408
409 const MCInstrDesc &InstInfo = Info->get(Opcode: Inst.getOpcode());
410
411 for (MCPhysReg ImplicitDef : InstInfo.implicit_defs())
412 Regs |= getAliases(Reg: ImplicitDef, /*OnlySmaller=*/false);
413 for (MCPhysReg ImplicitUse : InstInfo.implicit_uses())
414 Regs |= getAliases(Reg: ImplicitUse, /*OnlySmaller=*/false);
415
416 for (unsigned I = 0, E = Inst.getNumOperands(); I != E; ++I) {
417 if (!Inst.getOperand(i: I).isReg())
418 continue;
419 Regs |= getAliases(Reg: Inst.getOperand(i: I).getReg(), /*OnlySmaller=*/false);
420 }
421}
422
423void MCPlusBuilder::getWrittenRegs(const MCInst &Inst, BitVector &Regs) const {
424 if (isPrefix(Inst) || isCFI(Inst))
425 return;
426
427 const MCInstrDesc &InstInfo = Info->get(Opcode: Inst.getOpcode());
428
429 for (MCPhysReg ImplicitDef : InstInfo.implicit_defs())
430 Regs |= getAliases(Reg: ImplicitDef, /*OnlySmaller=*/true);
431
432 for (const MCOperand &Operand : defOperands(Inst)) {
433 assert(Operand.isReg());
434 Regs |= getAliases(Reg: Operand.getReg(), /*OnlySmaller=*/true);
435 }
436}
437
438void MCPlusBuilder::getUsedRegs(const MCInst &Inst, BitVector &Regs) const {
439 if (isPrefix(Inst) || isCFI(Inst))
440 return;
441
442 const MCInstrDesc &InstInfo = Info->get(Opcode: Inst.getOpcode());
443
444 for (MCPhysReg ImplicitUse : InstInfo.implicit_uses())
445 Regs |= getAliases(Reg: ImplicitUse, /*OnlySmaller=*/true);
446
447 for (const MCOperand &Operand : useOperands(Inst)) {
448 if (!Operand.isReg())
449 continue;
450 Regs |= getAliases(Reg: Operand.getReg(), /*OnlySmaller=*/true);
451 }
452}
453
454void MCPlusBuilder::getSrcRegs(const MCInst &Inst, BitVector &Regs) const {
455 if (isPrefix(Inst) || isCFI(Inst))
456 return;
457
458 if (isCall(Inst)) {
459 BitVector CallRegs = BitVector(Regs.size(), false);
460 getCalleeSavedRegs(Regs&: CallRegs);
461 CallRegs.flip();
462 Regs |= CallRegs;
463 return;
464 }
465
466 if (isReturn(Inst)) {
467 getDefaultLiveOut(Regs);
468 return;
469 }
470
471 if (isRep(Inst))
472 getRepRegs(Regs);
473
474 const MCInstrDesc &InstInfo = Info->get(Opcode: Inst.getOpcode());
475
476 for (MCPhysReg ImplicitUse : InstInfo.implicit_uses())
477 Regs |= getAliases(Reg: ImplicitUse, /*OnlySmaller=*/true);
478
479 for (const MCOperand &Operand : useOperands(Inst))
480 if (Operand.isReg())
481 Regs |= getAliases(Reg: Operand.getReg(), /*OnlySmaller=*/true);
482}
483
484bool MCPlusBuilder::hasDefOfPhysReg(const MCInst &MI, unsigned Reg) const {
485 const MCInstrDesc &InstInfo = Info->get(Opcode: MI.getOpcode());
486 return InstInfo.hasDefOfPhysReg(MI, Reg, RI: *RegInfo);
487}
488
489bool MCPlusBuilder::hasUseOfPhysReg(const MCInst &MI, unsigned Reg) const {
490 const MCInstrDesc &InstInfo = Info->get(Opcode: MI.getOpcode());
491 for (int I = InstInfo.NumDefs; I < InstInfo.NumOperands; ++I)
492 if (MI.getOperand(i: I).isReg() && MI.getOperand(i: I).getReg() &&
493 RegInfo->isSubRegisterEq(RegA: Reg, RegB: MI.getOperand(i: I).getReg()))
494 return true;
495 for (MCPhysReg ImplicitUse : InstInfo.implicit_uses()) {
496 if (ImplicitUse == Reg || RegInfo->isSubRegister(RegA: Reg, RegB: ImplicitUse))
497 return true;
498 }
499 return false;
500}
501
502const BitVector &MCPlusBuilder::getAliases(MCPhysReg Reg,
503 bool OnlySmaller) const {
504 if (OnlySmaller)
505 return SmallerAliasMap[Reg];
506 return AliasMap[Reg];
507}
508
509void MCPlusBuilder::initAliases() {
510 assert(AliasMap.size() == 0 && SmallerAliasMap.size() == 0);
511 // Build alias map
512 for (MCPhysReg I = 0, E = RegInfo->getNumRegs(); I != E; ++I) {
513 BitVector BV(RegInfo->getNumRegs(), false);
514 BV.set(I);
515 AliasMap.emplace_back(args&: BV);
516 SmallerAliasMap.emplace_back(args&: BV);
517 }
518
519 // Cache all aliases for each register
520 for (MCPhysReg I = 1, E = RegInfo->getNumRegs(); I != E; ++I) {
521 for (MCRegAliasIterator AI(I, RegInfo, true); AI.isValid(); ++AI)
522 AliasMap[I].set(*AI);
523 }
524
525 // Propagate smaller alias info upwards. Skip reg 0 (mapped to NoRegister)
526 for (MCPhysReg I = 1, E = RegInfo->getNumRegs(); I < E; ++I)
527 for (MCSubRegIterator SI(I, RegInfo); SI.isValid(); ++SI)
528 SmallerAliasMap[I] |= SmallerAliasMap[*SI];
529
530 LLVM_DEBUG({
531 dbgs() << "Dumping reg alias table:\n";
532 for (MCPhysReg I = 0, E = RegInfo->getNumRegs(); I != E; ++I) {
533 dbgs() << "Reg " << I << ": ";
534 const BitVector &BV = AliasMap[I];
535 int Idx = BV.find_first();
536 while (Idx != -1) {
537 dbgs() << Idx << " ";
538 Idx = BV.find_next(Idx);
539 }
540 dbgs() << "\n";
541 }
542 });
543}
544
545void MCPlusBuilder::initSizeMap() {
546 SizeMap.resize(new_size: RegInfo->getNumRegs());
547 // Build size map
548 for (auto RC : RegInfo->regclasses())
549 for (MCPhysReg Reg : RC)
550 SizeMap[Reg] = RC.getSizeInBits() / 8;
551}
552
553bool MCPlusBuilder::setOperandToSymbolRef(MCInst &Inst, int OpNum,
554 const MCSymbol *Symbol,
555 int64_t Addend, MCContext *Ctx,
556 uint32_t RelType) const {
557 MCOperand Operand;
558 if (!Addend) {
559 Operand = MCOperand::createExpr(Val: getTargetExprFor(
560 Inst, Expr: MCSymbolRefExpr::create(Symbol, Ctx&: *Ctx), Ctx&: *Ctx, RelType));
561 } else {
562 Operand = MCOperand::createExpr(Val: getTargetExprFor(
563 Inst,
564 Expr: MCBinaryExpr::createAdd(LHS: MCSymbolRefExpr::create(Symbol, Ctx&: *Ctx),
565 RHS: MCConstantExpr::create(Value: Addend, Ctx&: *Ctx), Ctx&: *Ctx),
566 Ctx&: *Ctx, RelType));
567 }
568 Inst.getOperand(i: OpNum) = Operand;
569 return true;
570}
571

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of bolt/lib/Core/MCPlusBuilder.cpp