Skip to content

Commit 74e0a26

Browse files
authored
[BOLT] Modify MCPlus annotation internals. NFCI. (#70412)
When annotating MCInst instructions, attach extra annotation operands directly to the annotated instruction, instead of attaching them to an instruction pointed to by a special kInst operand. With this change, it's no longer necessary to allocate MCInst and most of the first-class annotations come with free memory as currently MCInst is declared with: SmallVector<MCOperand, 10> Operands; i.e. more operands than are normally being used. We still create a kInst operand with a nullptr instruction value to designate the beginning of annotation operands. However, this special operand might not be needed if we can rely on MCInstrDesc::NumOperands.
1 parent cc05b47 commit 74e0a26

File tree

4 files changed

+106
-114
lines changed

4 files changed

+106
-114
lines changed

bolt/include/bolt/Core/MCPlus.h

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,16 @@ namespace MCPlus {
3232
/// pad and the uint64_t represents the action.
3333
using MCLandingPad = std::pair<const MCSymbol *, uint64_t>;
3434

35-
/// An extension to MCInst is provided via an extra operand of type MCInst with
36-
/// ANNOTATION_LABEL opcode (i.e. we are tying an annotation instruction to an
37-
/// existing one). The annotation instruction contains a list of Immediate
38-
/// operands. Each operand either contains a value, or is a pointer to
39-
/// an instance of class MCAnnotation.
35+
/// An extension to MCInst is provided via extra operands, i.e. operands that
36+
/// are not used in the instruction assembly. Any kind of metadata can be
37+
/// attached to MCInst with this "annotation" extension using MCPlusBuilder
38+
/// interface.
39+
//
40+
/// The first extra operand must be of type kInst with an empty (nullptr)
41+
/// value. The kInst operand type is unused on most non-VLIW architectures.
42+
/// We use it to mark the beginning of annotations operands. The rest of the
43+
/// operands are of Immediate type with annotation info encoded into the value
44+
/// of the immediate.
4045
///
4146
/// There are 2 distinct groups of annotations. The first group is a first-class
4247
/// annotation that affects semantics of the instruction, such as an
@@ -55,7 +60,7 @@ using MCLandingPad = std::pair<const MCSymbol *, uint64_t>;
5560
/// of their corresponding operand.
5661
///
5762
/// Annotations in the second group could be addressed either by name, or by
58-
/// by and index which could be queried by providing a name.
63+
/// by index which could be queried by providing the name.
5964
class MCAnnotation {
6065
public:
6166
enum Kind {
@@ -106,10 +111,11 @@ template <typename ValueType> class MCSimpleAnnotation : public MCAnnotation {
106111
/// Return a number of operands in \Inst excluding operands representing
107112
/// annotations.
108113
inline unsigned getNumPrimeOperands(const MCInst &Inst) {
109-
if (Inst.getNumOperands() > 0 && std::prev(Inst.end())->isInst()) {
110-
assert(std::prev(Inst.end())->getInst()->getOpcode() ==
111-
TargetOpcode::ANNOTATION_LABEL);
112-
return Inst.getNumOperands() - 1;
114+
for (signed I = Inst.getNumOperands() - 1; I >= 0; --I) {
115+
if (Inst.getOperand(I).isInst())
116+
return I;
117+
if (!Inst.getOperand(I).isImm())
118+
return Inst.getNumOperands();
113119
}
114120
return Inst.getNumOperands();
115121
}

bolt/include/bolt/Core/MCPlusBuilder.h

Lines changed: 54 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ class MCPlusBuilder {
6565
private:
6666
/// A struct that represents a single annotation allocator
6767
struct AnnotationAllocator {
68-
SpecificBumpPtrAllocator<MCInst> MCInstAllocator;
6968
BumpPtrAllocator ValueAllocator;
7069
std::unordered_set<MCPlus::MCAnnotation *> AnnotationPool;
7170
};
@@ -97,60 +96,62 @@ class MCPlusBuilder {
9796
return SignExtend64<56>(ImmValue & 0xff'ffff'ffff'ffffULL);
9897
}
9998

100-
MCInst *getAnnotationInst(const MCInst &Inst) const {
101-
if (Inst.getNumOperands() == 0)
102-
return nullptr;
99+
std::optional<unsigned> getFirstAnnotationOpIndex(const MCInst &Inst) const {
100+
const unsigned NumPrimeOperands = MCPlus::getNumPrimeOperands(Inst);
101+
if (Inst.getNumOperands() == NumPrimeOperands)
102+
return std::nullopt;
103103

104-
const MCOperand &LastOp = Inst.getOperand(Inst.getNumOperands() - 1);
105-
if (!LastOp.isInst())
106-
return nullptr;
104+
assert(Inst.getOperand(NumPrimeOperands).getInst() == nullptr &&
105+
"Empty instruction expected.");
107106

108-
MCInst *AnnotationInst = const_cast<MCInst *>(LastOp.getInst());
109-
assert(AnnotationInst->getOpcode() == TargetOpcode::ANNOTATION_LABEL);
107+
return NumPrimeOperands + 1;
108+
}
110109

111-
return AnnotationInst;
110+
MCInst::iterator getAnnotationInstOp(MCInst &Inst) const {
111+
for (MCInst::iterator Iter = Inst.begin(); Iter != Inst.end(); ++Iter) {
112+
if (Iter->isInst()) {
113+
assert(Iter->getInst() == nullptr && "Empty instruction expected.");
114+
return Iter;
115+
}
116+
}
117+
return Inst.end();
112118
}
113119

114-
void removeAnnotationInst(MCInst &Inst) const {
115-
assert(getAnnotationInst(Inst) && "Expected annotation instruction.");
116-
Inst.erase(std::prev(Inst.end()));
117-
assert(!getAnnotationInst(Inst) &&
118-
"More than one annotation instruction detected.");
120+
void removeAnnotations(MCInst &Inst) const {
121+
Inst.erase(getAnnotationInstOp(Inst), Inst.end());
119122
}
120123

121-
void setAnnotationOpValue(MCInst &Inst, unsigned Index, int64_t Value,
122-
AllocatorIdTy AllocatorId = 0) {
123-
MCInst *AnnotationInst = getAnnotationInst(Inst);
124-
if (!AnnotationInst) {
125-
AnnotationAllocator &Allocator = getAnnotationAllocator(AllocatorId);
126-
AnnotationInst = new (Allocator.MCInstAllocator.Allocate()) MCInst();
127-
AnnotationInst->setOpcode(TargetOpcode::ANNOTATION_LABEL);
128-
Inst.addOperand(MCOperand::createInst(AnnotationInst));
124+
void setAnnotationOpValue(MCInst &Inst, unsigned Index, int64_t Value) const {
125+
const int64_t AnnotationValue = encodeAnnotationImm(Index, Value);
126+
const std::optional<unsigned> FirstAnnotationOp =
127+
getFirstAnnotationOpIndex(Inst);
128+
if (!FirstAnnotationOp) {
129+
Inst.addOperand(MCOperand::createInst(nullptr));
130+
Inst.addOperand(MCOperand::createImm(AnnotationValue));
131+
return;
129132
}
130133

131-
const int64_t AnnotationValue = encodeAnnotationImm(Index, Value);
132-
for (int I = AnnotationInst->getNumOperands() - 1; I >= 0; --I) {
133-
int64_t ImmValue = AnnotationInst->getOperand(I).getImm();
134+
for (unsigned I = *FirstAnnotationOp; I < Inst.getNumOperands(); ++I) {
135+
const int64_t ImmValue = Inst.getOperand(I).getImm();
134136
if (extractAnnotationIndex(ImmValue) == Index) {
135-
AnnotationInst->getOperand(I).setImm(AnnotationValue);
137+
Inst.getOperand(I).setImm(AnnotationValue);
136138
return;
137139
}
138140
}
139141

140-
AnnotationInst->addOperand(MCOperand::createImm(AnnotationValue));
142+
Inst.addOperand(MCOperand::createImm(AnnotationValue));
141143
}
142144

143145
std::optional<int64_t> getAnnotationOpValue(const MCInst &Inst,
144146
unsigned Index) const {
145-
const MCInst *AnnotationInst = getAnnotationInst(Inst);
146-
if (!AnnotationInst)
147+
std::optional<unsigned> FirstAnnotationOp = getFirstAnnotationOpIndex(Inst);
148+
if (!FirstAnnotationOp)
147149
return std::nullopt;
148150

149-
for (int I = AnnotationInst->getNumOperands() - 1; I >= 0; --I) {
150-
int64_t ImmValue = AnnotationInst->getOperand(I).getImm();
151-
if (extractAnnotationIndex(ImmValue) == Index) {
151+
for (unsigned I = *FirstAnnotationOp; I < Inst.getNumOperands(); ++I) {
152+
const int64_t ImmValue = Inst.getOperand(I).getImm();
153+
if (extractAnnotationIndex(ImmValue) == Index)
152154
return extractAnnotationValue(ImmValue);
153-
}
154155
}
155156

156157
return std::nullopt;
@@ -172,21 +173,18 @@ class MCPlusBuilder {
172173
/// AnnotationNameIndexMap and AnnotationsNames.
173174
mutable llvm::sys::RWMutex AnnotationNameMutex;
174175

175-
/// Allocate the TailCall annotation value. Clients of the target-specific
176+
/// Set TailCall annotation value to true. Clients of the target-specific
176177
/// MCPlusBuilder classes must use convert/lower/create* interfaces instead.
177-
void setTailCall(MCInst &Inst);
178+
void setTailCall(MCInst &Inst) const;
178179

179180
public:
180181
/// Transfer annotations from \p SrcInst to \p DstInst.
181182
void moveAnnotations(MCInst &&SrcInst, MCInst &DstInst) const {
182-
assert(!getAnnotationInst(DstInst) &&
183-
"Destination instruction should not have annotations.");
184-
const MCInst *AnnotationInst = getAnnotationInst(SrcInst);
185-
if (!AnnotationInst)
186-
return;
183+
MCInst::iterator AnnotationOp = getAnnotationInstOp(SrcInst);
184+
for (MCInst::iterator Iter = AnnotationOp; Iter != SrcInst.end(); ++Iter)
185+
DstInst.addOperand(*Iter);
187186

188-
DstInst.addOperand(MCOperand::createInst(AnnotationInst));
189-
removeAnnotationInst(SrcInst);
187+
SrcInst.erase(AnnotationOp, SrcInst.end());
190188
}
191189

192190
/// Return iterator range covering def operands.
@@ -390,7 +388,6 @@ class MCPlusBuilder {
390388

391389
Allocator.AnnotationPool.clear();
392390
Allocator.ValueAllocator.Reset();
393-
Allocator.MCInstAllocator.DestroyAll();
394391
}
395392
}
396393

@@ -1128,20 +1125,19 @@ class MCPlusBuilder {
11281125
std::optional<MCPlus::MCLandingPad> getEHInfo(const MCInst &Inst) const;
11291126

11301127
/// Add handler and action info for call instruction.
1131-
void addEHInfo(MCInst &Inst, const MCPlus::MCLandingPad &LP);
1128+
void addEHInfo(MCInst &Inst, const MCPlus::MCLandingPad &LP) const;
11321129

11331130
/// Update exception-handling info for the invoke instruction \p Inst.
11341131
/// Return true on success and false otherwise, e.g. if the instruction is
11351132
/// not an invoke.
1136-
bool updateEHInfo(MCInst &Inst, const MCPlus::MCLandingPad &LP);
1133+
bool updateEHInfo(MCInst &Inst, const MCPlus::MCLandingPad &LP) const;
11371134

11381135
/// Return non-negative GNU_args_size associated with the instruction
11391136
/// or -1 if there's no associated info.
11401137
int64_t getGnuArgsSize(const MCInst &Inst) const;
11411138

11421139
/// Add the value of GNU_args_size to Inst if it already has EH info.
1143-
void addGnuArgsSize(MCInst &Inst, int64_t GnuArgsSize,
1144-
AllocatorIdTy AllocId = 0);
1140+
void addGnuArgsSize(MCInst &Inst, int64_t GnuArgsSize) const;
11451141

11461142
/// Return jump table addressed by this instruction.
11471143
uint64_t getJumpTable(const MCInst &Inst) const;
@@ -1154,19 +1150,19 @@ class MCPlusBuilder {
11541150
AllocatorIdTy AllocId = 0);
11551151

11561152
/// Disassociate instruction with a jump table.
1157-
bool unsetJumpTable(MCInst &Inst);
1153+
bool unsetJumpTable(MCInst &Inst) const;
11581154

11591155
/// Return destination of conditional tail call instruction if \p Inst is one.
11601156
std::optional<uint64_t> getConditionalTailCall(const MCInst &Inst) const;
11611157

11621158
/// Mark the \p Instruction as a conditional tail call, and set its
11631159
/// destination address if it is known. If \p Instruction was already marked,
11641160
/// update its destination with \p Dest.
1165-
bool setConditionalTailCall(MCInst &Inst, uint64_t Dest = 0);
1161+
bool setConditionalTailCall(MCInst &Inst, uint64_t Dest = 0) const;
11661162

11671163
/// If \p Inst was marked as a conditional tail call convert it to a regular
11681164
/// branch. Return true if the instruction was converted.
1169-
bool unsetConditionalTailCall(MCInst &Inst);
1165+
bool unsetConditionalTailCall(MCInst &Inst) const;
11701166

11711167
/// Return offset of \p Inst in the original function, if available.
11721168
std::optional<uint32_t> getOffset(const MCInst &Inst) const;
@@ -1175,10 +1171,10 @@ class MCPlusBuilder {
11751171
uint32_t getOffsetWithDefault(const MCInst &Inst, uint32_t Default) const;
11761172

11771173
/// Set offset of \p Inst in the original function.
1178-
bool setOffset(MCInst &Inst, uint32_t Offset, AllocatorIdTy AllocatorId = 0);
1174+
bool setOffset(MCInst &Inst, uint32_t Offset) const;
11791175

11801176
/// Remove offset annotation.
1181-
bool clearOffset(MCInst &Inst);
1177+
bool clearOffset(MCInst &Inst) const;
11821178

11831179
/// Return the label of \p Inst, if available.
11841180
MCSymbol *getLabel(const MCInst &Inst) const;
@@ -1827,8 +1823,7 @@ class MCPlusBuilder {
18271823

18281824
if (!std::is_trivial<ValueType>::value)
18291825
Allocator.AnnotationPool.insert(A);
1830-
setAnnotationOpValue(Inst, Index, reinterpret_cast<int64_t>(A),
1831-
AllocatorId);
1826+
setAnnotationOpValue(Inst, Index, reinterpret_cast<int64_t>(A));
18321827
return A->getValue();
18331828
}
18341829

@@ -1961,21 +1956,21 @@ class MCPlusBuilder {
19611956
///
19621957
/// Return true if the annotation was removed, false if the annotation
19631958
/// was not present.
1964-
bool removeAnnotation(MCInst &Inst, unsigned Index);
1959+
bool removeAnnotation(MCInst &Inst, unsigned Index) const;
19651960

19661961
/// Remove annotation associated with \p Name.
19671962
///
19681963
/// Return true if the annotation was removed, false if the annotation
19691964
/// was not present.
1970-
bool removeAnnotation(MCInst &Inst, StringRef Name) {
1965+
bool removeAnnotation(MCInst &Inst, StringRef Name) const {
19711966
const auto Index = getAnnotationIndex(Name);
19721967
if (!Index)
19731968
return false;
19741969
return removeAnnotation(Inst, *Index);
19751970
}
19761971

1977-
/// Remove meta-data, but don't destroy it.
1978-
void stripAnnotations(MCInst &Inst, bool KeepTC = false);
1972+
/// Remove meta-data from the instruction, but don't destroy it.
1973+
void stripAnnotations(MCInst &Inst, bool KeepTC = false) const;
19791974

19801975
virtual InstructionListType
19811976
createInstrumentedIndirectCall(MCInst &&CallInst, MCSymbol *HandlerFuncAddr,

bolt/lib/Core/BinaryFunction.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,7 +1999,7 @@ bool BinaryFunction::buildCFG(MCPlusBuilder::AllocatorIdTy AllocatorId) {
19991999
}
20002000
}
20012001
if (LastNonNop && !MIB->getOffset(*LastNonNop))
2002-
MIB->setOffset(*LastNonNop, static_cast<uint32_t>(Offset), AllocatorId);
2002+
MIB->setOffset(*LastNonNop, static_cast<uint32_t>(Offset));
20032003
};
20042004

20052005
for (auto I = Instructions.begin(), E = Instructions.end(); I != E; ++I) {
@@ -2022,7 +2022,7 @@ bool BinaryFunction::buildCFG(MCPlusBuilder::AllocatorIdTy AllocatorId) {
20222022
if (MIB->isNoop(Instr) && !MIB->getOffset(Instr)) {
20232023
// If "Offset" annotation is not present, set it and mark the nop for
20242024
// deletion.
2025-
MIB->setOffset(Instr, static_cast<uint32_t>(Offset), AllocatorId);
2025+
MIB->setOffset(Instr, static_cast<uint32_t>(Offset));
20262026
// Annotate ordinary nops, so we can safely delete them if required.
20272027
MIB->addAnnotation(Instr, "NOP", static_cast<uint32_t>(1), AllocatorId);
20282028
}
@@ -2303,6 +2303,13 @@ void BinaryFunction::removeConditionalTailCalls() {
23032303
assert(CTCTargetLabel && "symbol expected for conditional tail call");
23042304
MCInst TailCallInstr;
23052305
BC.MIB->createTailCall(TailCallInstr, CTCTargetLabel, BC.Ctx.get());
2306+
2307+
// Move offset from CTCInstr to TailCallInstr.
2308+
if (const std::optional<uint32_t> Offset = BC.MIB->getOffset(*CTCInstr)) {
2309+
BC.MIB->setOffset(TailCallInstr, *Offset);
2310+
BC.MIB->clearOffset(*CTCInstr);
2311+
}
2312+
23062313
// Link new BBs to the original input offset of the BB where the CTC
23072314
// is, so we can map samples recorded in new BBs back to the original BB
23082315
// seem in the input binary (if using BAT)
@@ -2331,12 +2338,6 @@ void BinaryFunction::removeConditionalTailCalls() {
23312338

23322339
// This branch is no longer a conditional tail call.
23332340
BC.MIB->unsetConditionalTailCall(*CTCInstr);
2334-
2335-
// Move offset from CTCInstr to TailCallInstr.
2336-
if (std::optional<uint32_t> Offset = BC.MIB->getOffset(*CTCInstr)) {
2337-
BC.MIB->setOffset(TailCallInstr, *Offset);
2338-
BC.MIB->clearOffset(*CTCInstr);
2339-
}
23402341
}
23412342

23422343
insertBasicBlocks(std::prev(end()), std::move(NewBlocks),
@@ -3373,7 +3374,7 @@ void BinaryFunction::propagateGnuArgsSizeInfo(
33733374
}
33743375
} else if (BC.MIB->isInvoke(Instr)) {
33753376
// Add the value of GNU_args_size as an extra operand to invokes.
3376-
BC.MIB->addGnuArgsSize(Instr, CurrentGnuArgsSize, AllocId);
3377+
BC.MIB->addGnuArgsSize(Instr, CurrentGnuArgsSize);
33773378
}
33783379
++II;
33793380
}

0 commit comments

Comments
 (0)