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

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