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