@@ -162,6 +162,134 @@ static inline raw_ostream &operator<<(raw_ostream &OS,
162162  return  Ref.print (OS);
163163}
164164
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+ 
165293} //  namespace bolt
166294} //  namespace llvm
167295
0 commit comments