@@ -166,6 +166,134 @@ static inline raw_ostream &operator<<(raw_ostream &OS,
166
166
return Ref.print (OS);
167
167
}
168
168
169
+ // / Instruction-matching helpers operating on a single instruction at a time.
170
+ // /
171
+ // / Unlike MCPlusBuilder::MCInstMatcher, this matchInst() function focuses on
172
+ // / the cases where a precise control over the instruction order is important:
173
+ // /
174
+ // / // Bring the short names into the local scope:
175
+ // / using namespace MCInstMatcher;
176
+ // / // Declare the registers to capture:
177
+ // / Reg Xn, Xm;
178
+ // / // Capture the 0th and 1st operands, match the 2nd operand against the
179
+ // / // just captured Xm register, match the 3rd operand against literal 0:
180
+ // / if (!matchInst(MaybeAdd, AArch64::ADDXrs, Xm, Xn, Xm, Imm(0))
181
+ // / return AArch64::NoRegister;
182
+ // / // Match the 0th operand against Xm:
183
+ // / if (!matchInst(MaybeBr, AArch64::BR, Xm))
184
+ // / return AArch64::NoRegister;
185
+ // / // Return the matched register:
186
+ // / return Xm.get();
187
+ namespace MCInstMatcher {
188
+
189
+ // The base class to match an operand of type T.
190
+ //
191
+ // The subclasses of OpMatcher are intended to be allocated on the stack and
192
+ // to only be used by passing them to matchInst() and by calling their get()
193
+ // function, thus the peculiar `mutable` specifiers: to make the calling code
194
+ // compact and readable, the templated matchInst() function has to accept both
195
+ // long-lived Imm/Reg wrappers declared as local variables (intended to capture
196
+ // the first operand's value and match the subsequent operands, whether inside
197
+ // a single instruction or across multiple instructions), as well as temporary
198
+ // wrappers around literal values to match, f.e. Imm(42) or Reg(AArch64::XZR).
199
+ template <typename T> class OpMatcher {
200
+ mutable std::optional<T> Value;
201
+ mutable std::optional<T> SavedValue;
202
+
203
+ // Remember/restore the last Value - to be called by matchInst.
204
+ void remember () const { SavedValue = Value; }
205
+ void restore () const { Value = SavedValue; }
206
+
207
+ template <class ... OpMatchers>
208
+ friend bool matchInst (const MCInst &, unsigned , const OpMatchers &...);
209
+
210
+ protected:
211
+ OpMatcher (std::optional<T> ValueToMatch) : Value(ValueToMatch) {}
212
+
213
+ bool matchValue (T OpValue) const {
214
+ // Check that OpValue does not contradict the existing Value.
215
+ bool MatchResult = !Value || *Value == OpValue;
216
+ // If MatchResult is false, all matchers will be reset before returning from
217
+ // matchInst, including this one, thus no need to assign conditionally.
218
+ Value = OpValue;
219
+
220
+ return MatchResult;
221
+ }
222
+
223
+ public:
224
+ // / Returns the captured value.
225
+ T get () const {
226
+ assert (Value.has_value ());
227
+ return *Value;
228
+ }
229
+ };
230
+
231
+ class Reg : public OpMatcher <MCPhysReg> {
232
+ bool matches (const MCOperand &Op) const {
233
+ if (!Op.isReg ())
234
+ return false ;
235
+
236
+ return matchValue (Op.getReg ());
237
+ }
238
+
239
+ template <class ... OpMatchers>
240
+ friend bool matchInst (const MCInst &, unsigned , const OpMatchers &...);
241
+
242
+ public:
243
+ Reg (std::optional<MCPhysReg> RegToMatch = std::nullopt)
244
+ : OpMatcher<MCPhysReg>(RegToMatch) {}
245
+ };
246
+
247
+ class Imm : public OpMatcher <int64_t > {
248
+ bool matches (const MCOperand &Op) const {
249
+ if (!Op.isImm ())
250
+ return false ;
251
+
252
+ return matchValue (Op.getImm ());
253
+ }
254
+
255
+ template <class ... OpMatchers>
256
+ friend bool matchInst (const MCInst &, unsigned , const OpMatchers &...);
257
+
258
+ public:
259
+ Imm (std::optional<int64_t > ImmToMatch = std::nullopt)
260
+ : OpMatcher<int64_t >(ImmToMatch) {}
261
+ };
262
+
263
+ // / Tries to match Inst and updates Ops on success.
264
+ // /
265
+ // / If Inst has the specified Opcode and its operand list prefix matches Ops,
266
+ // / this function returns true and updates Ops, otherwise false is returned and
267
+ // / values of Ops are kept as before matchInst was called.
268
+ // /
269
+ // / Please note that while Ops are technically passed by a const reference to
270
+ // / make invocations like `matchInst(MI, Opcode, Imm(42))` possible, all their
271
+ // / fields are marked mutable.
272
+ template <class ... OpMatchers>
273
+ bool matchInst (const MCInst &Inst, unsigned Opcode, const OpMatchers &...Ops) {
274
+ if (Inst.getOpcode () != Opcode)
275
+ return false ;
276
+ assert (sizeof ...(Ops) <= Inst.getNumOperands () &&
277
+ " Too many operands are matched for the Opcode" );
278
+
279
+ // Ask each matcher to remember its current value in case of rollback.
280
+ (Ops.remember (), ...);
281
+
282
+ // Check if all matchers match the corresponding operands.
283
+ auto It = Inst.begin ();
284
+ auto AllMatched = (Ops.matches (*(It++)) && ... && true );
285
+
286
+ // If match failed, restore the original captured values.
287
+ if (!AllMatched) {
288
+ (Ops.restore (), ...);
289
+ return false ;
290
+ }
291
+
292
+ return true ;
293
+ }
294
+
295
+ } // namespace MCInstMatcher
296
+
169
297
} // namespace bolt
170
298
} // namespace llvm
171
299
0 commit comments