Skip to content

Commit 93bbb50

Browse files
author
MUSTAPHA BARKI
authored
Merge branch 'main' into Uncontrolled-data-used-in-path-expression
2 parents 0c74138 + ed1d954 commit 93bbb50

File tree

943 files changed

+23281
-16946
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

943 files changed

+23281
-16946
lines changed

bolt/include/bolt/Core/MCInstUtils.h

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define BOLT_CORE_MCINSTUTILS_H
1111

1212
#include "bolt/Core/BinaryBasicBlock.h"
13+
#include "bolt/Core/MCPlus.h"
1314
#include <map>
1415
#include <variant>
1516

@@ -175,6 +176,171 @@ static inline raw_ostream &operator<<(raw_ostream &OS,
175176
return Ref.print(OS);
176177
}
177178

179+
/// Instruction-matching helpers operating on a single instruction at a time.
180+
///
181+
/// The idea is to make low-level instruction matching as readable as possible.
182+
/// The classes contained in this namespace are intended to be used as a
183+
/// domain-specific language to match MCInst with the particular opcode and
184+
/// operands.
185+
///
186+
/// The goals of this DSL include
187+
/// * matching a single instruction against the template consisting of the
188+
/// particular target-specific opcode and a pattern of operands
189+
/// * matching operands against the known values (such as 42, AArch64::X1 or
190+
/// "the value of --brk-operand=N command line argument")
191+
/// * capturing operands of an instruction ("whatever is the destination
192+
/// register of AArch64::ADDXri instruction, store it to Xd variable to be
193+
/// queried later")
194+
/// * expressing repeated operands of a single matched instruction (such as
195+
/// "ADDXri Xd, Xd, 42, 0" for an arbitrary register Xd) as well as across
196+
/// multiple calls to matchInst(), which is naturally achieved by sequentially
197+
/// capturing the operands and matching operands against the known values
198+
/// * matching multi-instruction code patterns by sequentially calling
199+
/// matchInst() while passing around already matched operands
200+
///
201+
/// The non-goals (compared to MCPlusBuilder::MCInstMatcher) include
202+
/// * matching an arbitrary tree of instructions in a single matchInst() call
203+
/// * encapsulation of target-specific knowledge ("match an increment of Xm
204+
/// by 42")
205+
///
206+
/// Unlike MCPlusBuilder::MCInstMatcher, this DSL focuses on the use cases when
207+
/// the precise control over the instruction order is important. For example,
208+
/// let's consider a target-specific function that has to match two particular
209+
/// instructions against this pattern (for two different registers Xm and Xn)
210+
///
211+
/// ADDXrs Xm, Xn, Xm, #0
212+
/// BR Xm
213+
///
214+
/// and return the register holding the branch target. Assuming the instructions
215+
/// are available as MaybeAdd and MaybeBr, the following code can be used:
216+
///
217+
/// // Bring the short names into the local scope:
218+
/// using namespace LowLevelInstMatcherDSL;
219+
/// // Declare the registers to capture:
220+
/// Reg Xn, Xm;
221+
/// // Capture the 0th and 1st operands, match the 2nd operand against the
222+
/// // just captured Xm register, match the 3rd operand against literal 0:
223+
/// if (!matchInst(MaybeAdd, AArch64::ADDXrs, Xm, Xn, Xm, Imm(0))
224+
/// return AArch64::NoRegister;
225+
/// // Match the 0th operand against Xm:
226+
/// if (!matchInst(MaybeBr, AArch64::BR, Xm))
227+
/// return AArch64::NoRegister;
228+
/// // Manually check that Xm and Xn did not match the same register:
229+
/// if (Xm.get() == Xn.get())
230+
/// return AArch64::NoRegister;
231+
/// // Return the matched register:
232+
/// return Xm.get();
233+
///
234+
namespace LowLevelInstMatcherDSL {
235+
236+
// The base class to match an operand of type T.
237+
//
238+
// The subclasses of OpMatcher are intended to be allocated on the stack and
239+
// to only be used by passing them to matchInst() and by calling their get()
240+
// function, thus the peculiar `mutable` specifiers: to make the calling code
241+
// compact and readable, the templated matchInst() function has to accept both
242+
// long-lived Imm/Reg wrappers declared as local variables (intended to capture
243+
// the first operand's value and match the subsequent operands, whether inside
244+
// a single instruction or across multiple instructions), as well as temporary
245+
// wrappers around literal values to match, f.e. Imm(42) or Reg(AArch64::XZR).
246+
template <typename T> class OpMatcher {
247+
mutable std::optional<T> Value;
248+
mutable std::optional<T> SavedValue;
249+
250+
// Remember/restore the last Value - to be called by matchInst.
251+
void remember() const { SavedValue = Value; }
252+
void restore() const { Value = SavedValue; }
253+
254+
template <class... OpMatchers>
255+
friend bool matchInst(const MCInst &, unsigned, const OpMatchers &...);
256+
257+
protected:
258+
OpMatcher(std::optional<T> ValueToMatch) : Value(ValueToMatch) {}
259+
260+
bool matchValue(T OpValue) const {
261+
// Check that OpValue does not contradict the existing Value.
262+
bool MatchResult = !Value || *Value == OpValue;
263+
// If MatchResult is false, all matchers will be reset before returning from
264+
// matchInst, including this one, thus no need to assign conditionally.
265+
Value = OpValue;
266+
267+
return MatchResult;
268+
}
269+
270+
public:
271+
/// Returns the captured value.
272+
T get() const {
273+
assert(Value.has_value());
274+
return *Value;
275+
}
276+
};
277+
278+
class Reg : public OpMatcher<MCPhysReg> {
279+
bool matches(const MCOperand &Op) const {
280+
if (!Op.isReg())
281+
return false;
282+
283+
return matchValue(Op.getReg());
284+
}
285+
286+
template <class... OpMatchers>
287+
friend bool matchInst(const MCInst &, unsigned, const OpMatchers &...);
288+
289+
public:
290+
Reg(std::optional<MCPhysReg> RegToMatch = std::nullopt)
291+
: OpMatcher<MCPhysReg>(RegToMatch) {}
292+
};
293+
294+
class Imm : public OpMatcher<int64_t> {
295+
bool matches(const MCOperand &Op) const {
296+
if (!Op.isImm())
297+
return false;
298+
299+
return matchValue(Op.getImm());
300+
}
301+
302+
template <class... OpMatchers>
303+
friend bool matchInst(const MCInst &, unsigned, const OpMatchers &...);
304+
305+
public:
306+
Imm(std::optional<int64_t> ImmToMatch = std::nullopt)
307+
: OpMatcher<int64_t>(ImmToMatch) {}
308+
};
309+
310+
/// Tries to match Inst and updates Ops on success.
311+
///
312+
/// If Inst has the specified Opcode and its operand list prefix matches Ops,
313+
/// this function returns true and updates Ops, otherwise false is returned and
314+
/// values of Ops are kept as before matchInst was called.
315+
///
316+
/// Please note that while Ops are technically passed by a const reference to
317+
/// make invocations like `matchInst(MI, Opcode, Imm(42))` possible, all their
318+
/// fields are marked mutable.
319+
template <class... OpMatchers>
320+
bool matchInst(const MCInst &Inst, unsigned Opcode, const OpMatchers &...Ops) {
321+
if (Inst.getOpcode() != Opcode)
322+
return false;
323+
assert(sizeof...(Ops) <= MCPlus::getNumPrimeOperands(Inst) &&
324+
"Too many operands are matched for the Opcode");
325+
326+
// Ask each matcher to remember its current value in case of rollback.
327+
(Ops.remember(), ...);
328+
329+
// Check if all matchers match the corresponding operands.
330+
auto It = Inst.begin();
331+
auto AllMatched = (Ops.matches(*(It++)) && ... && true);
332+
333+
// If match failed, restore the original captured values.
334+
if (!AllMatched) {
335+
(Ops.restore(), ...);
336+
return false;
337+
}
338+
339+
return true;
340+
}
341+
342+
} // namespace LowLevelInstMatcherDSL
343+
178344
} // namespace bolt
179345
} // namespace llvm
180346

bolt/lib/Core/BinaryContext.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1662,7 +1662,7 @@ void BinaryContext::preprocessDWODebugInfo() {
16621662
"files.\n";
16631663
}
16641664
// Prevent failures when DWOName is already an absolute path.
1665-
sys::fs::make_absolute(DWOCompDir, AbsolutePath);
1665+
sys::path::make_absolute(DWOCompDir, AbsolutePath);
16661666
DWARFUnit *DWOCU =
16671667
DwarfUnit->getNonSkeletonUnitDIE(false, AbsolutePath).getDwarfUnit();
16681668
if (!DWOCU->isDWOUnit()) {

0 commit comments

Comments
 (0)