xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/M68k/M68kInstrInfo.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
104eeddc0SDimitry Andric //===-- M68kInstrInfo.h - M68k Instruction Information ----------*- C++ -*-===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric ///
9fe6060f1SDimitry Andric /// \file
10fe6060f1SDimitry Andric /// This file contains the M68k implementation of the TargetInstrInfo class.
11fe6060f1SDimitry Andric ///
12fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
13fe6060f1SDimitry Andric 
14fe6060f1SDimitry Andric #ifndef LLVM_LIB_TARGET_M68K_M68KINSTRINFO_H
15fe6060f1SDimitry Andric #define LLVM_LIB_TARGET_M68K_M68KINSTRINFO_H
16fe6060f1SDimitry Andric 
17fe6060f1SDimitry Andric #include "M68k.h"
18fe6060f1SDimitry Andric #include "M68kRegisterInfo.h"
19fe6060f1SDimitry Andric 
20fe6060f1SDimitry Andric #include "MCTargetDesc/M68kBaseInfo.h"
21fe6060f1SDimitry Andric 
22fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
23fe6060f1SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
24fe6060f1SDimitry Andric 
25fe6060f1SDimitry Andric #define GET_INSTRINFO_HEADER
26fe6060f1SDimitry Andric #include "M68kGenInstrInfo.inc"
27fe6060f1SDimitry Andric 
28fe6060f1SDimitry Andric namespace llvm {
29fe6060f1SDimitry Andric 
30fe6060f1SDimitry Andric class M68kSubtarget;
31fe6060f1SDimitry Andric 
32fe6060f1SDimitry Andric namespace M68k {
33fe6060f1SDimitry Andric // These MUST be kept in sync with codes definitions in M68kInstrInfo.td
34fe6060f1SDimitry Andric enum CondCode {
35fe6060f1SDimitry Andric   COND_T = 0,   // True
36fe6060f1SDimitry Andric   COND_F = 1,   // False
37fe6060f1SDimitry Andric   COND_HI = 2,  // High
38fe6060f1SDimitry Andric   COND_LS = 3,  // Less or Same
39fe6060f1SDimitry Andric   COND_CC = 4,  // Carry Clear
40fe6060f1SDimitry Andric   COND_CS = 5,  // Carry Set
41fe6060f1SDimitry Andric   COND_NE = 6,  // Not Equal
42fe6060f1SDimitry Andric   COND_EQ = 7,  // Equal
43fe6060f1SDimitry Andric   COND_VC = 8,  // Overflow Clear
44fe6060f1SDimitry Andric   COND_VS = 9,  // Overflow Set
45fe6060f1SDimitry Andric   COND_PL = 10, // Plus
46fe6060f1SDimitry Andric   COND_MI = 11, // Minus
47fe6060f1SDimitry Andric   COND_GE = 12, // Greater or Equal
48fe6060f1SDimitry Andric   COND_LT = 13, // Less Than
49fe6060f1SDimitry Andric   COND_GT = 14, // Greater Than
50fe6060f1SDimitry Andric   COND_LE = 15, // Less or Equal
51fe6060f1SDimitry Andric   LAST_VALID_COND = COND_LE,
52fe6060f1SDimitry Andric   COND_INVALID
53fe6060f1SDimitry Andric };
54fe6060f1SDimitry Andric 
55fe6060f1SDimitry Andric // FIXME would be nice tablegen to generate these predicates and converters
56fe6060f1SDimitry Andric // mb tag based
57fe6060f1SDimitry Andric 
58fe6060f1SDimitry Andric static inline M68k::CondCode GetOppositeBranchCondition(M68k::CondCode CC) {
59fe6060f1SDimitry Andric   switch (CC) {
60fe6060f1SDimitry Andric   default:
61fe6060f1SDimitry Andric     llvm_unreachable("Illegal condition code!");
62fe6060f1SDimitry Andric   case M68k::COND_T:
63fe6060f1SDimitry Andric     return M68k::COND_F;
64fe6060f1SDimitry Andric   case M68k::COND_F:
65fe6060f1SDimitry Andric     return M68k::COND_T;
66fe6060f1SDimitry Andric   case M68k::COND_HI:
67fe6060f1SDimitry Andric     return M68k::COND_LS;
68fe6060f1SDimitry Andric   case M68k::COND_LS:
69fe6060f1SDimitry Andric     return M68k::COND_HI;
70fe6060f1SDimitry Andric   case M68k::COND_CC:
71fe6060f1SDimitry Andric     return M68k::COND_CS;
72fe6060f1SDimitry Andric   case M68k::COND_CS:
73fe6060f1SDimitry Andric     return M68k::COND_CC;
74fe6060f1SDimitry Andric   case M68k::COND_NE:
75fe6060f1SDimitry Andric     return M68k::COND_EQ;
76fe6060f1SDimitry Andric   case M68k::COND_EQ:
77fe6060f1SDimitry Andric     return M68k::COND_NE;
78fe6060f1SDimitry Andric   case M68k::COND_VC:
79fe6060f1SDimitry Andric     return M68k::COND_VS;
80fe6060f1SDimitry Andric   case M68k::COND_VS:
81fe6060f1SDimitry Andric     return M68k::COND_VC;
82fe6060f1SDimitry Andric   case M68k::COND_PL:
83fe6060f1SDimitry Andric     return M68k::COND_MI;
84fe6060f1SDimitry Andric   case M68k::COND_MI:
85fe6060f1SDimitry Andric     return M68k::COND_PL;
86fe6060f1SDimitry Andric   case M68k::COND_GE:
87fe6060f1SDimitry Andric     return M68k::COND_LT;
88fe6060f1SDimitry Andric   case M68k::COND_LT:
89fe6060f1SDimitry Andric     return M68k::COND_GE;
90fe6060f1SDimitry Andric   case M68k::COND_GT:
91fe6060f1SDimitry Andric     return M68k::COND_LE;
92fe6060f1SDimitry Andric   case M68k::COND_LE:
93fe6060f1SDimitry Andric     return M68k::COND_GT;
94fe6060f1SDimitry Andric   }
95fe6060f1SDimitry Andric }
96fe6060f1SDimitry Andric 
97fe6060f1SDimitry Andric static inline unsigned GetCondBranchFromCond(M68k::CondCode CC) {
98fe6060f1SDimitry Andric   switch (CC) {
99fe6060f1SDimitry Andric   default:
100fe6060f1SDimitry Andric     llvm_unreachable("Illegal condition code!");
101fe6060f1SDimitry Andric   case M68k::COND_EQ:
102fe6060f1SDimitry Andric     return M68k::Beq8;
103fe6060f1SDimitry Andric   case M68k::COND_NE:
104fe6060f1SDimitry Andric     return M68k::Bne8;
105fe6060f1SDimitry Andric   case M68k::COND_LT:
106fe6060f1SDimitry Andric     return M68k::Blt8;
107fe6060f1SDimitry Andric   case M68k::COND_LE:
108fe6060f1SDimitry Andric     return M68k::Ble8;
109fe6060f1SDimitry Andric   case M68k::COND_GT:
110fe6060f1SDimitry Andric     return M68k::Bgt8;
111fe6060f1SDimitry Andric   case M68k::COND_GE:
112fe6060f1SDimitry Andric     return M68k::Bge8;
113fe6060f1SDimitry Andric   case M68k::COND_CS:
114fe6060f1SDimitry Andric     return M68k::Bcs8;
115fe6060f1SDimitry Andric   case M68k::COND_LS:
116fe6060f1SDimitry Andric     return M68k::Bls8;
117fe6060f1SDimitry Andric   case M68k::COND_HI:
118fe6060f1SDimitry Andric     return M68k::Bhi8;
119fe6060f1SDimitry Andric   case M68k::COND_CC:
120fe6060f1SDimitry Andric     return M68k::Bcc8;
121fe6060f1SDimitry Andric   case M68k::COND_MI:
122fe6060f1SDimitry Andric     return M68k::Bmi8;
123fe6060f1SDimitry Andric   case M68k::COND_PL:
124fe6060f1SDimitry Andric     return M68k::Bpl8;
125fe6060f1SDimitry Andric   case M68k::COND_VS:
126fe6060f1SDimitry Andric     return M68k::Bvs8;
127fe6060f1SDimitry Andric   case M68k::COND_VC:
128fe6060f1SDimitry Andric     return M68k::Bvc8;
129fe6060f1SDimitry Andric   }
130fe6060f1SDimitry Andric }
131fe6060f1SDimitry Andric 
132fe6060f1SDimitry Andric static inline M68k::CondCode GetCondFromBranchOpc(unsigned Opcode) {
133fe6060f1SDimitry Andric   switch (Opcode) {
134fe6060f1SDimitry Andric   default:
135fe6060f1SDimitry Andric     return M68k::COND_INVALID;
136fe6060f1SDimitry Andric   case M68k::Beq8:
137fe6060f1SDimitry Andric     return M68k::COND_EQ;
138fe6060f1SDimitry Andric   case M68k::Bne8:
139fe6060f1SDimitry Andric     return M68k::COND_NE;
140fe6060f1SDimitry Andric   case M68k::Blt8:
141fe6060f1SDimitry Andric     return M68k::COND_LT;
142fe6060f1SDimitry Andric   case M68k::Ble8:
143fe6060f1SDimitry Andric     return M68k::COND_LE;
144fe6060f1SDimitry Andric   case M68k::Bgt8:
145fe6060f1SDimitry Andric     return M68k::COND_GT;
146fe6060f1SDimitry Andric   case M68k::Bge8:
147fe6060f1SDimitry Andric     return M68k::COND_GE;
148fe6060f1SDimitry Andric   case M68k::Bcs8:
149fe6060f1SDimitry Andric     return M68k::COND_CS;
150fe6060f1SDimitry Andric   case M68k::Bls8:
151fe6060f1SDimitry Andric     return M68k::COND_LS;
152fe6060f1SDimitry Andric   case M68k::Bhi8:
153fe6060f1SDimitry Andric     return M68k::COND_HI;
154fe6060f1SDimitry Andric   case M68k::Bcc8:
155fe6060f1SDimitry Andric     return M68k::COND_CC;
156fe6060f1SDimitry Andric   case M68k::Bmi8:
157fe6060f1SDimitry Andric     return M68k::COND_MI;
158fe6060f1SDimitry Andric   case M68k::Bpl8:
159fe6060f1SDimitry Andric     return M68k::COND_PL;
160fe6060f1SDimitry Andric   case M68k::Bvs8:
161fe6060f1SDimitry Andric     return M68k::COND_VS;
162fe6060f1SDimitry Andric   case M68k::Bvc8:
163fe6060f1SDimitry Andric     return M68k::COND_VC;
164fe6060f1SDimitry Andric   }
165fe6060f1SDimitry Andric }
166fe6060f1SDimitry Andric 
167fe6060f1SDimitry Andric static inline unsigned IsCMP(unsigned Op) {
168fe6060f1SDimitry Andric   switch (Op) {
169fe6060f1SDimitry Andric   default:
170fe6060f1SDimitry Andric     return false;
171fe6060f1SDimitry Andric   case M68k::CMP8dd:
172fe6060f1SDimitry Andric   case M68k::CMP8df:
173fe6060f1SDimitry Andric   case M68k::CMP8di:
174fe6060f1SDimitry Andric   case M68k::CMP8dj:
175fe6060f1SDimitry Andric   case M68k::CMP8dp:
176349cc55cSDimitry Andric   case M68k::CMP16dr:
177fe6060f1SDimitry Andric   case M68k::CMP16df:
178fe6060f1SDimitry Andric   case M68k::CMP16di:
179fe6060f1SDimitry Andric   case M68k::CMP16dj:
180fe6060f1SDimitry Andric   case M68k::CMP16dp:
181fe6060f1SDimitry Andric     return true;
182fe6060f1SDimitry Andric   }
183fe6060f1SDimitry Andric }
184fe6060f1SDimitry Andric 
185fe6060f1SDimitry Andric static inline bool IsSETCC(unsigned SETCC) {
186fe6060f1SDimitry Andric   switch (SETCC) {
187fe6060f1SDimitry Andric   default:
188fe6060f1SDimitry Andric     return false;
189fe6060f1SDimitry Andric   case M68k::SETd8eq:
190fe6060f1SDimitry Andric   case M68k::SETd8ne:
191fe6060f1SDimitry Andric   case M68k::SETd8lt:
192fe6060f1SDimitry Andric   case M68k::SETd8ge:
193fe6060f1SDimitry Andric   case M68k::SETd8le:
194fe6060f1SDimitry Andric   case M68k::SETd8gt:
195fe6060f1SDimitry Andric   case M68k::SETd8cs:
196fe6060f1SDimitry Andric   case M68k::SETd8cc:
197fe6060f1SDimitry Andric   case M68k::SETd8ls:
198fe6060f1SDimitry Andric   case M68k::SETd8hi:
199fe6060f1SDimitry Andric   case M68k::SETd8pl:
200fe6060f1SDimitry Andric   case M68k::SETd8mi:
201fe6060f1SDimitry Andric   case M68k::SETd8vc:
202fe6060f1SDimitry Andric   case M68k::SETd8vs:
203fe6060f1SDimitry Andric   case M68k::SETj8eq:
204fe6060f1SDimitry Andric   case M68k::SETj8ne:
205fe6060f1SDimitry Andric   case M68k::SETj8lt:
206fe6060f1SDimitry Andric   case M68k::SETj8ge:
207fe6060f1SDimitry Andric   case M68k::SETj8le:
208fe6060f1SDimitry Andric   case M68k::SETj8gt:
209fe6060f1SDimitry Andric   case M68k::SETj8cs:
210fe6060f1SDimitry Andric   case M68k::SETj8cc:
211fe6060f1SDimitry Andric   case M68k::SETj8ls:
212fe6060f1SDimitry Andric   case M68k::SETj8hi:
213fe6060f1SDimitry Andric   case M68k::SETj8pl:
214fe6060f1SDimitry Andric   case M68k::SETj8mi:
215fe6060f1SDimitry Andric   case M68k::SETj8vc:
216fe6060f1SDimitry Andric   case M68k::SETj8vs:
217fe6060f1SDimitry Andric   case M68k::SETp8eq:
218fe6060f1SDimitry Andric   case M68k::SETp8ne:
219fe6060f1SDimitry Andric   case M68k::SETp8lt:
220fe6060f1SDimitry Andric   case M68k::SETp8ge:
221fe6060f1SDimitry Andric   case M68k::SETp8le:
222fe6060f1SDimitry Andric   case M68k::SETp8gt:
223fe6060f1SDimitry Andric   case M68k::SETp8cs:
224fe6060f1SDimitry Andric   case M68k::SETp8cc:
225fe6060f1SDimitry Andric   case M68k::SETp8ls:
226fe6060f1SDimitry Andric   case M68k::SETp8hi:
227fe6060f1SDimitry Andric   case M68k::SETp8pl:
228fe6060f1SDimitry Andric   case M68k::SETp8mi:
229fe6060f1SDimitry Andric   case M68k::SETp8vc:
230fe6060f1SDimitry Andric   case M68k::SETp8vs:
231fe6060f1SDimitry Andric     return true;
232fe6060f1SDimitry Andric   }
233fe6060f1SDimitry Andric }
234fe6060f1SDimitry Andric 
235fe6060f1SDimitry Andric } // namespace M68k
236fe6060f1SDimitry Andric 
237fe6060f1SDimitry Andric class M68kInstrInfo : public M68kGenInstrInfo {
238fe6060f1SDimitry Andric   virtual void anchor();
239fe6060f1SDimitry Andric 
240fe6060f1SDimitry Andric protected:
241fe6060f1SDimitry Andric   const M68kSubtarget &Subtarget;
242fe6060f1SDimitry Andric   const M68kRegisterInfo RI;
243fe6060f1SDimitry Andric 
244fe6060f1SDimitry Andric public:
245fe6060f1SDimitry Andric   explicit M68kInstrInfo(const M68kSubtarget &STI);
246fe6060f1SDimitry Andric 
247fe6060f1SDimitry Andric   static const M68kInstrInfo *create(M68kSubtarget &STI);
248fe6060f1SDimitry Andric 
249fe6060f1SDimitry Andric   /// TargetInstrInfo is a superset of MRegister info. As such, whenever a
250fe6060f1SDimitry Andric   /// client has an instance of instruction info, it should always be able to
251fe6060f1SDimitry Andric   /// get register info as well (through this method).
252fe6060f1SDimitry Andric   const M68kRegisterInfo &getRegisterInfo() const { return RI; };
253fe6060f1SDimitry Andric 
254fe6060f1SDimitry Andric   bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
255fe6060f1SDimitry Andric                      MachineBasicBlock *&FBB,
256fe6060f1SDimitry Andric                      SmallVectorImpl<MachineOperand> &Cond,
257fe6060f1SDimitry Andric                      bool AllowModify) const override;
258fe6060f1SDimitry Andric 
259fe6060f1SDimitry Andric   bool AnalyzeBranchImpl(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
260fe6060f1SDimitry Andric                          MachineBasicBlock *&FBB,
261fe6060f1SDimitry Andric                          SmallVectorImpl<MachineOperand> &Cond,
262fe6060f1SDimitry Andric                          bool AllowModify) const;
263fe6060f1SDimitry Andric 
264fe6060f1SDimitry Andric   unsigned removeBranch(MachineBasicBlock &MBB,
265fe6060f1SDimitry Andric                         int *BytesRemoved = nullptr) const override;
266fe6060f1SDimitry Andric 
267fe6060f1SDimitry Andric   unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
268fe6060f1SDimitry Andric                         MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
269fe6060f1SDimitry Andric                         const DebugLoc &DL,
270fe6060f1SDimitry Andric                         int *BytesAdded = nullptr) const override;
271fe6060f1SDimitry Andric 
272fe6060f1SDimitry Andric   void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
273fe6060f1SDimitry Andric                    const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg,
274fe6060f1SDimitry Andric                    bool KillSrc) const override;
275fe6060f1SDimitry Andric 
276fe6060f1SDimitry Andric   bool getStackSlotRange(const TargetRegisterClass *RC, unsigned SubIdx,
277fe6060f1SDimitry Andric                          unsigned &Size, unsigned &Offset,
278fe6060f1SDimitry Andric                          const MachineFunction &MF) const override;
279fe6060f1SDimitry Andric 
280fe6060f1SDimitry Andric   void storeRegToStackSlot(MachineBasicBlock &MBB,
281fe6060f1SDimitry Andric                            MachineBasicBlock::iterator MI, Register SrcReg,
282fe6060f1SDimitry Andric                            bool IsKill, int FrameIndex,
283fe6060f1SDimitry Andric                            const TargetRegisterClass *RC,
284bdd1243dSDimitry Andric                            const TargetRegisterInfo *TRI,
285bdd1243dSDimitry Andric                            Register VReg) const override;
286fe6060f1SDimitry Andric 
287fe6060f1SDimitry Andric   void loadRegFromStackSlot(MachineBasicBlock &MBB,
288fe6060f1SDimitry Andric                             MachineBasicBlock::iterator MI, Register DestReg,
289fe6060f1SDimitry Andric                             int FrameIndex, const TargetRegisterClass *RC,
290bdd1243dSDimitry Andric                             const TargetRegisterInfo *TRI,
291bdd1243dSDimitry Andric                             Register VReg) const override;
292fe6060f1SDimitry Andric 
293fe6060f1SDimitry Andric   bool expandPostRAPseudo(MachineInstr &MI) const override;
294fe6060f1SDimitry Andric 
295fe6060f1SDimitry Andric   bool isPCRelRegisterOperandLegal(const MachineOperand &MO) const override;
296fe6060f1SDimitry Andric 
297fe6060f1SDimitry Andric   /// Add appropriate SExt nodes
298fe6060f1SDimitry Andric   void AddSExt(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
299fe6060f1SDimitry Andric                DebugLoc DL, unsigned Reg, MVT From, MVT To) const;
300fe6060f1SDimitry Andric 
301fe6060f1SDimitry Andric   /// Add appropriate ZExt nodes
302fe6060f1SDimitry Andric   void AddZExt(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
303fe6060f1SDimitry Andric                DebugLoc DL, unsigned Reg, MVT From, MVT To) const;
304fe6060f1SDimitry Andric 
305*0fca6ea1SDimitry Andric   /// Move immediate to register
306*0fca6ea1SDimitry Andric   bool ExpandMOVI(MachineInstrBuilder &MIB, MVT MVTSize) const;
307*0fca6ea1SDimitry Andric 
308fe6060f1SDimitry Andric   /// Move across register classes without extension
309fe6060f1SDimitry Andric   bool ExpandMOVX_RR(MachineInstrBuilder &MIB, MVT MVTDst, MVT MVTSrc) const;
310fe6060f1SDimitry Andric 
311fe6060f1SDimitry Andric   /// Move from register and extend
312fe6060f1SDimitry Andric   bool ExpandMOVSZX_RR(MachineInstrBuilder &MIB, bool IsSigned, MVT MVTDst,
313fe6060f1SDimitry Andric                        MVT MVTSrc) const;
314fe6060f1SDimitry Andric 
315fe6060f1SDimitry Andric   /// Move from memory and extend
316fe6060f1SDimitry Andric   bool ExpandMOVSZX_RM(MachineInstrBuilder &MIB, bool IsSigned,
317fe6060f1SDimitry Andric                        const MCInstrDesc &Desc, MVT MVTDst, MVT MVTSrc) const;
318fe6060f1SDimitry Andric 
319fe6060f1SDimitry Andric   /// Push/Pop to/from stack
320fe6060f1SDimitry Andric   bool ExpandPUSH_POP(MachineInstrBuilder &MIB, const MCInstrDesc &Desc,
321fe6060f1SDimitry Andric                       bool IsPush) const;
322fe6060f1SDimitry Andric 
323fe6060f1SDimitry Andric   /// Moves to/from CCR
324fe6060f1SDimitry Andric   bool ExpandCCR(MachineInstrBuilder &MIB, bool IsToCCR) const;
325fe6060f1SDimitry Andric 
326fe6060f1SDimitry Andric   /// Expand all MOVEM pseudos into real MOVEMs
327fe6060f1SDimitry Andric   bool ExpandMOVEM(MachineInstrBuilder &MIB, const MCInstrDesc &Desc,
328fe6060f1SDimitry Andric                    bool IsRM) const;
329fe6060f1SDimitry Andric 
3305f757f3fSDimitry Andric   /// Return a virtual register initialized with the global base register
331fe6060f1SDimitry Andric   /// value. Output instructions required to initialize the register in the
332fe6060f1SDimitry Andric   /// function entry block, if necessary.
333fe6060f1SDimitry Andric   unsigned getGlobalBaseReg(MachineFunction *MF) const;
334fe6060f1SDimitry Andric 
335fe6060f1SDimitry Andric   std::pair<unsigned, unsigned>
336fe6060f1SDimitry Andric   decomposeMachineOperandsTargetFlags(unsigned TF) const override;
337fe6060f1SDimitry Andric 
338fe6060f1SDimitry Andric   ArrayRef<std::pair<unsigned, const char *>>
339fe6060f1SDimitry Andric   getSerializableDirectMachineOperandTargetFlags() const override;
340fe6060f1SDimitry Andric };
341fe6060f1SDimitry Andric 
342fe6060f1SDimitry Andric } // namespace llvm
343fe6060f1SDimitry Andric 
34404eeddc0SDimitry Andric #endif // LLVM_LIB_TARGET_M68K_M68KINSTRINFO_H
345