1 //===-- llvm/Operator.h - Operator utility subclass -------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines various classes for working with Instructions and
10 // ConstantExprs.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_IR_OPERATOR_H
15 #define LLVM_IR_OPERATOR_H
16 
17 #include "llvm/ADT/MapVector.h"
18 #include "llvm/ADT/None.h"
19 #include "llvm/ADT/Optional.h"
20 #include "llvm/IR/Constants.h"
21 #include "llvm/IR/Instruction.h"
22 #include "llvm/IR/Type.h"
23 #include "llvm/IR/Value.h"
24 #include "llvm/Support/Casting.h"
25 #include <cstddef>
26 
27 namespace llvm {
28 
29 /// This is a utility class that provides an abstraction for the common
30 /// functionality between Instructions and ConstantExprs.
31 class Operator : public User {
32 public:
33   // The Operator class is intended to be used as a utility, and is never itself
34   // instantiated.
35   Operator() = delete;
36   ~Operator() = delete;
37 
38   void *operator new(size_t s) = delete;
39 
40   /// Return the opcode for this Instruction or ConstantExpr.
41   unsigned getOpcode() const {
42     if (const Instruction *I = dyn_cast<Instruction>(this))
43       return I->getOpcode();
44     return cast<ConstantExpr>(this)->getOpcode();
45   }
46 
47   /// If V is an Instruction or ConstantExpr, return its opcode.
48   /// Otherwise return UserOp1.
49   static unsigned getOpcode(const Value *V) {
50     if (const Instruction *I = dyn_cast<Instruction>(V))
51       return I->getOpcode();
52     if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(V))
53       return CE->getOpcode();
54     return Instruction::UserOp1;
55   }
56 
57   static bool classof(const Instruction *) { return true; }
58   static bool classof(const ConstantExpr *) { return true; }
59   static bool classof(const Value *V) {
60     return isa<Instruction>(V) || isa<ConstantExpr>(V);
61   }
62 
63   /// Return true if this operator has flags which may cause this operator
64   /// to evaluate to poison despite having non-poison inputs.
65   bool hasPoisonGeneratingFlags() const;
66 };
67 
68 /// Utility class for integer operators which may exhibit overflow - Add, Sub,
69 /// Mul, and Shl. It does not include SDiv, despite that operator having the
70 /// potential for overflow.
71 class OverflowingBinaryOperator : public Operator {
72 public:
73   enum {
74     AnyWrap        = 0,
75     NoUnsignedWrap = (1 << 0),
76     NoSignedWrap   = (1 << 1)
77   };
78 
79 private:
80   friend class Instruction;
81   friend class ConstantExpr;
82 
83   void setHasNoUnsignedWrap(bool B) {
84     SubclassOptionalData =
85       (SubclassOptionalData & ~NoUnsignedWrap) | (B * NoUnsignedWrap);
86   }
87   void setHasNoSignedWrap(bool B) {
88     SubclassOptionalData =
89       (SubclassOptionalData & ~NoSignedWrap) | (B * NoSignedWrap);
90   }
91 
92 public:
93   /// Test whether this operation is known to never
94   /// undergo unsigned overflow, aka the nuw property.
95   bool hasNoUnsignedWrap() const {
96     return SubclassOptionalData & NoUnsignedWrap;
97   }
98 
99   /// Test whether this operation is known to never
100   /// undergo signed overflow, aka the nsw property.
101   bool hasNoSignedWrap() const {
102     return (SubclassOptionalData & NoSignedWrap) != 0;
103   }
104 
105   static bool classof(const Instruction *I) {
106     return I->getOpcode() == Instruction::Add ||
107            I->getOpcode() == Instruction::Sub ||
108            I->getOpcode() == Instruction::Mul ||
109            I->getOpcode() == Instruction::Shl;
110   }
111   static bool classof(const ConstantExpr *CE) {
112     return CE->getOpcode() == Instruction::Add ||
113            CE->getOpcode() == Instruction::Sub ||
114            CE->getOpcode() == Instruction::Mul ||
115            CE->getOpcode() == Instruction::Shl;
116   }
117   static bool classof(const Value *V) {
118     return (isa<Instruction>(V) && classof(cast<Instruction>(V))) ||
119            (isa<ConstantExpr>(V) && classof(cast<ConstantExpr>(V)));
120   }
121 };
122 
123 /// A udiv or sdiv instruction, which can be marked as "exact",
124 /// indicating that no bits are destroyed.
125 class PossiblyExactOperator : public Operator {
126 public:
127   enum {
128     IsExact = (1 << 0)
129   };
130 
131 private:
132   friend class Instruction;
133   friend class ConstantExpr;
134 
135   void setIsExact(bool B) {
136     SubclassOptionalData = (SubclassOptionalData & ~IsExact) | (B * IsExact);
137   }
138 
139 public:
140   /// Test whether this division is known to be exact, with zero remainder.
141   bool isExact() const {
142     return SubclassOptionalData & IsExact;
143   }
144 
145   static bool isPossiblyExactOpcode(unsigned OpC) {
146     return OpC == Instruction::SDiv ||
147            OpC == Instruction::UDiv ||
148            OpC == Instruction::AShr ||
149            OpC == Instruction::LShr;
150   }
151 
152   static bool classof(const ConstantExpr *CE) {
153     return isPossiblyExactOpcode(CE->getOpcode());
154   }
155   static bool classof(const Instruction *I) {
156     return isPossiblyExactOpcode(I->getOpcode());
157   }
158   static bool classof(const Value *V) {
159     return (isa<Instruction>(V) && classof(cast<Instruction>(V))) ||
160            (isa<ConstantExpr>(V) && classof(cast<ConstantExpr>(V)));
161   }
162 };
163 
164 /// Convenience struct for specifying and reasoning about fast-math flags.
165 class FastMathFlags {
166 private:
167   friend class FPMathOperator;
168 
169   unsigned Flags = 0;
170 
171   FastMathFlags(unsigned F) {
172     // If all 7 bits are set, turn this into -1. If the number of bits grows,
173     // this must be updated. This is intended to provide some forward binary
174     // compatibility insurance for the meaning of 'fast' in case bits are added.
175     if (F == 0x7F) Flags = ~0U;
176     else Flags = F;
177   }
178 
179 public:
180   // This is how the bits are used in Value::SubclassOptionalData so they
181   // should fit there too.
182   // WARNING: We're out of space. SubclassOptionalData only has 7 bits. New
183   // functionality will require a change in how this information is stored.
184   enum {
185     AllowReassoc    = (1 << 0),
186     NoNaNs          = (1 << 1),
187     NoInfs          = (1 << 2),
188     NoSignedZeros   = (1 << 3),
189     AllowReciprocal = (1 << 4),
190     AllowContract   = (1 << 5),
191     ApproxFunc      = (1 << 6)
192   };
193 
194   FastMathFlags() = default;
195 
196   static FastMathFlags getFast() {
197     FastMathFlags FMF;
198     FMF.setFast();
199     return FMF;
200   }
201 
202   bool any() const { return Flags != 0; }
203   bool none() const { return Flags == 0; }
204   bool all() const { return Flags == ~0U; }
205 
206   void clear() { Flags = 0; }
207   void set()   { Flags = ~0U; }
208 
209   /// Flag queries
210   bool allowReassoc() const    { return 0 != (Flags & AllowReassoc); }
211   bool noNaNs() const          { return 0 != (Flags & NoNaNs); }
212   bool noInfs() const          { return 0 != (Flags & NoInfs); }
213   bool noSignedZeros() const   { return 0 != (Flags & NoSignedZeros); }
214   bool allowReciprocal() const { return 0 != (Flags & AllowReciprocal); }
215   bool allowContract() const   { return 0 != (Flags & AllowContract); }
216   bool approxFunc() const      { return 0 != (Flags & ApproxFunc); }
217   /// 'Fast' means all bits are set.
218   bool isFast() const          { return all(); }
219 
220   /// Flag setters
221   void setAllowReassoc(bool B = true) {
222     Flags = (Flags & ~AllowReassoc) | B * AllowReassoc;
223   }
224   void setNoNaNs(bool B = true) {
225     Flags = (Flags & ~NoNaNs) | B * NoNaNs;
226   }
227   void setNoInfs(bool B = true) {
228     Flags = (Flags & ~NoInfs) | B * NoInfs;
229   }
230   void setNoSignedZeros(bool B = true) {
231     Flags = (Flags & ~NoSignedZeros) | B * NoSignedZeros;
232   }
233   void setAllowReciprocal(bool B = true) {
234     Flags = (Flags & ~AllowReciprocal) | B * AllowReciprocal;
235   }
236   void setAllowContract(bool B = true) {
237     Flags = (Flags & ~AllowContract) | B * AllowContract;
238   }
239   void setApproxFunc(bool B = true) {
240     Flags = (Flags & ~ApproxFunc) | B * ApproxFunc;
241   }
242   void setFast(bool B = true) { B ? set() : clear(); }
243 
244   void operator&=(const FastMathFlags &OtherFlags) {
245     Flags &= OtherFlags.Flags;
246   }
247   void operator|=(const FastMathFlags &OtherFlags) {
248     Flags |= OtherFlags.Flags;
249   }
250   bool operator!=(const FastMathFlags &OtherFlags) const {
251     return Flags != OtherFlags.Flags;
252   }
253 
254   /// Print fast-math flags to \p O.
255   void print(raw_ostream &O) const;
256 };
257 
258 inline raw_ostream &operator<<(raw_ostream &O, FastMathFlags FMF) {
259   FMF.print(O);
260   return O;
261 }
262 
263 /// Utility class for floating point operations which can have
264 /// information about relaxed accuracy requirements attached to them.
265 class FPMathOperator : public Operator {
266 private:
267   friend class Instruction;
268 
269   /// 'Fast' means all bits are set.
270   void setFast(bool B) {
271     setHasAllowReassoc(B);
272     setHasNoNaNs(B);
273     setHasNoInfs(B);
274     setHasNoSignedZeros(B);
275     setHasAllowReciprocal(B);
276     setHasAllowContract(B);
277     setHasApproxFunc(B);
278   }
279 
280   void setHasAllowReassoc(bool B) {
281     SubclassOptionalData =
282     (SubclassOptionalData & ~FastMathFlags::AllowReassoc) |
283     (B * FastMathFlags::AllowReassoc);
284   }
285 
286   void setHasNoNaNs(bool B) {
287     SubclassOptionalData =
288       (SubclassOptionalData & ~FastMathFlags::NoNaNs) |
289       (B * FastMathFlags::NoNaNs);
290   }
291 
292   void setHasNoInfs(bool B) {
293     SubclassOptionalData =
294       (SubclassOptionalData & ~FastMathFlags::NoInfs) |
295       (B * FastMathFlags::NoInfs);
296   }
297 
298   void setHasNoSignedZeros(bool B) {
299     SubclassOptionalData =
300       (SubclassOptionalData & ~FastMathFlags::NoSignedZeros) |
301       (B * FastMathFlags::NoSignedZeros);
302   }
303 
304   void setHasAllowReciprocal(bool B) {
305     SubclassOptionalData =
306       (SubclassOptionalData & ~FastMathFlags::AllowReciprocal) |
307       (B * FastMathFlags::AllowReciprocal);
308   }
309 
310   void setHasAllowContract(bool B) {
311     SubclassOptionalData =
312         (SubclassOptionalData & ~FastMathFlags::AllowContract) |
313         (B * FastMathFlags::AllowContract);
314   }
315 
316   void setHasApproxFunc(bool B) {
317     SubclassOptionalData =
318         (SubclassOptionalData & ~FastMathFlags::ApproxFunc) |
319         (B * FastMathFlags::ApproxFunc);
320   }
321 
322   /// Convenience function for setting multiple fast-math flags.
323   /// FMF is a mask of the bits to set.
324   void setFastMathFlags(FastMathFlags FMF) {
325     SubclassOptionalData |= FMF.Flags;
326   }
327 
328   /// Convenience function for copying all fast-math flags.
329   /// All values in FMF are transferred to this operator.
330   void copyFastMathFlags(FastMathFlags FMF) {
331     SubclassOptionalData = FMF.Flags;
332   }
333 
334 public:
335   /// Test if this operation allows all non-strict floating-point transforms.
336   bool isFast() const {
337     return ((SubclassOptionalData & FastMathFlags::AllowReassoc) != 0 &&
338             (SubclassOptionalData & FastMathFlags::NoNaNs) != 0 &&
339             (SubclassOptionalData & FastMathFlags::NoInfs) != 0 &&
340             (SubclassOptionalData & FastMathFlags::NoSignedZeros) != 0 &&
341             (SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0 &&
342             (SubclassOptionalData & FastMathFlags::AllowContract) != 0 &&
343             (SubclassOptionalData & FastMathFlags::ApproxFunc) != 0);
344   }
345 
346   /// Test if this operation may be simplified with reassociative transforms.
347   bool hasAllowReassoc() const {
348     return (SubclassOptionalData & FastMathFlags::AllowReassoc) != 0;
349   }
350 
351   /// Test if this operation's arguments and results are assumed not-NaN.
352   bool hasNoNaNs() const {
353     return (SubclassOptionalData & FastMathFlags::NoNaNs) != 0;
354   }
355 
356   /// Test if this operation's arguments and results are assumed not-infinite.
357   bool hasNoInfs() const {
358     return (SubclassOptionalData & FastMathFlags::NoInfs) != 0;
359   }
360 
361   /// Test if this operation can ignore the sign of zero.
362   bool hasNoSignedZeros() const {
363     return (SubclassOptionalData & FastMathFlags::NoSignedZeros) != 0;
364   }
365 
366   /// Test if this operation can use reciprocal multiply instead of division.
367   bool hasAllowReciprocal() const {
368     return (SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0;
369   }
370 
371   /// Test if this operation can be floating-point contracted (FMA).
372   bool hasAllowContract() const {
373     return (SubclassOptionalData & FastMathFlags::AllowContract) != 0;
374   }
375 
376   /// Test if this operation allows approximations of math library functions or
377   /// intrinsics.
378   bool hasApproxFunc() const {
379     return (SubclassOptionalData & FastMathFlags::ApproxFunc) != 0;
380   }
381 
382   /// Convenience function for getting all the fast-math flags
383   FastMathFlags getFastMathFlags() const {
384     return FastMathFlags(SubclassOptionalData);
385   }
386 
387   /// Get the maximum error permitted by this operation in ULPs. An accuracy of
388   /// 0.0 means that the operation should be performed with the default
389   /// precision.
390   float getFPAccuracy() const;
391 
392   static bool classof(const Value *V) {
393     unsigned Opcode;
394     if (auto *I = dyn_cast<Instruction>(V))
395       Opcode = I->getOpcode();
396     else if (auto *CE = dyn_cast<ConstantExpr>(V))
397       Opcode = CE->getOpcode();
398     else
399       return false;
400 
401     switch (Opcode) {
402     case Instruction::FNeg:
403     case Instruction::FAdd:
404     case Instruction::FSub:
405     case Instruction::FMul:
406     case Instruction::FDiv:
407     case Instruction::FRem:
408     // FIXME: To clean up and correct the semantics of fast-math-flags, FCmp
409     //        should not be treated as a math op, but the other opcodes should.
410     //        This would make things consistent with Select/PHI (FP value type
411     //        determines whether they are math ops and, therefore, capable of
412     //        having fast-math-flags).
413     case Instruction::FCmp:
414       return true;
415     case Instruction::PHI:
416     case Instruction::Select:
417     case Instruction::Call: {
418       Type *Ty = V->getType();
419       while (ArrayType *ArrTy = dyn_cast<ArrayType>(Ty))
420         Ty = ArrTy->getElementType();
421       return Ty->isFPOrFPVectorTy();
422     }
423     default:
424       return false;
425     }
426   }
427 };
428 
429 /// A helper template for defining operators for individual opcodes.
430 template<typename SuperClass, unsigned Opc>
431 class ConcreteOperator : public SuperClass {
432 public:
433   static bool classof(const Instruction *I) {
434     return I->getOpcode() == Opc;
435   }
436   static bool classof(const ConstantExpr *CE) {
437     return CE->getOpcode() == Opc;
438   }
439   static bool classof(const Value *V) {
440     return (isa<Instruction>(V) && classof(cast<Instruction>(V))) ||
441            (isa<ConstantExpr>(V) && classof(cast<ConstantExpr>(V)));
442   }
443 };
444 
445 class AddOperator
446   : public ConcreteOperator<OverflowingBinaryOperator, Instruction::Add> {
447 };
448 class SubOperator
449   : public ConcreteOperator<OverflowingBinaryOperator, Instruction::Sub> {
450 };
451 class MulOperator
452   : public ConcreteOperator<OverflowingBinaryOperator, Instruction::Mul> {
453 };
454 class ShlOperator
455   : public ConcreteOperator<OverflowingBinaryOperator, Instruction::Shl> {
456 };
457 
458 class SDivOperator
459   : public ConcreteOperator<PossiblyExactOperator, Instruction::SDiv> {
460 };
461 class UDivOperator
462   : public ConcreteOperator<PossiblyExactOperator, Instruction::UDiv> {
463 };
464 class AShrOperator
465   : public ConcreteOperator<PossiblyExactOperator, Instruction::AShr> {
466 };
467 class LShrOperator
468   : public ConcreteOperator<PossiblyExactOperator, Instruction::LShr> {
469 };
470 
471 class ZExtOperator : public ConcreteOperator<Operator, Instruction::ZExt> {};
472 
473 class GEPOperator
474   : public ConcreteOperator<Operator, Instruction::GetElementPtr> {
475   friend class GetElementPtrInst;
476   friend class ConstantExpr;
477 
478   enum {
479     IsInBounds = (1 << 0),
480     // InRangeIndex: bits 1-6
481   };
482 
483   void setIsInBounds(bool B) {
484     SubclassOptionalData =
485       (SubclassOptionalData & ~IsInBounds) | (B * IsInBounds);
486   }
487 
488 public:
489   /// Test whether this is an inbounds GEP, as defined by LangRef.html.
490   bool isInBounds() const {
491     return SubclassOptionalData & IsInBounds;
492   }
493 
494   /// Returns the offset of the index with an inrange attachment, or None if
495   /// none.
496   Optional<unsigned> getInRangeIndex() const {
497     if (SubclassOptionalData >> 1 == 0) return None;
498     return (SubclassOptionalData >> 1) - 1;
499   }
500 
501   inline op_iterator       idx_begin()       { return op_begin()+1; }
502   inline const_op_iterator idx_begin() const { return op_begin()+1; }
503   inline op_iterator       idx_end()         { return op_end(); }
504   inline const_op_iterator idx_end()   const { return op_end(); }
505 
506   inline iterator_range<op_iterator> indices() {
507     return make_range(idx_begin(), idx_end());
508   }
509 
510   inline iterator_range<const_op_iterator> indices() const {
511     return make_range(idx_begin(), idx_end());
512   }
513 
514   Value *getPointerOperand() {
515     return getOperand(0);
516   }
517   const Value *getPointerOperand() const {
518     return getOperand(0);
519   }
520   static unsigned getPointerOperandIndex() {
521     return 0U;                      // get index for modifying correct operand
522   }
523 
524   /// Method to return the pointer operand as a PointerType.
525   Type *getPointerOperandType() const {
526     return getPointerOperand()->getType();
527   }
528 
529   Type *getSourceElementType() const;
530   Type *getResultElementType() const;
531 
532   /// Method to return the address space of the pointer operand.
533   unsigned getPointerAddressSpace() const {
534     return getPointerOperandType()->getPointerAddressSpace();
535   }
536 
537   unsigned getNumIndices() const {  // Note: always non-negative
538     return getNumOperands() - 1;
539   }
540 
541   bool hasIndices() const {
542     return getNumOperands() > 1;
543   }
544 
545   /// Return true if all of the indices of this GEP are zeros.
546   /// If so, the result pointer and the first operand have the same
547   /// value, just potentially different types.
548   bool hasAllZeroIndices() const {
549     for (const_op_iterator I = idx_begin(), E = idx_end(); I != E; ++I) {
550       if (ConstantInt *C = dyn_cast<ConstantInt>(I))
551         if (C->isZero())
552           continue;
553       return false;
554     }
555     return true;
556   }
557 
558   /// Return true if all of the indices of this GEP are constant integers.
559   /// If so, the result pointer and the first operand have
560   /// a constant offset between them.
561   bool hasAllConstantIndices() const {
562     for (const_op_iterator I = idx_begin(), E = idx_end(); I != E; ++I) {
563       if (!isa<ConstantInt>(I))
564         return false;
565     }
566     return true;
567   }
568 
569   unsigned countNonConstantIndices() const {
570     return count_if(indices(), [](const Use& use) {
571         return !isa<ConstantInt>(*use);
572       });
573   }
574 
575   /// Compute the maximum alignment that this GEP is garranteed to preserve.
576   Align getMaxPreservedAlignment(const DataLayout &DL) const;
577 
578   /// Accumulate the constant address offset of this GEP if possible.
579   ///
580   /// This routine accepts an APInt into which it will try to accumulate the
581   /// constant offset of this GEP.
582   ///
583   /// If \p ExternalAnalysis is provided it will be used to calculate a offset
584   /// when a operand of GEP is not constant.
585   /// For example, for a value \p ExternalAnalysis might try to calculate a
586   /// lower bound. If \p ExternalAnalysis is successful, it should return true.
587   ///
588   /// If the \p ExternalAnalysis returns false or the value returned by \p
589   /// ExternalAnalysis results in a overflow/underflow, this routine returns
590   /// false and the value of the offset APInt is undefined (it is *not*
591   /// preserved!).
592   ///
593   /// The APInt passed into this routine must be at exactly as wide as the
594   /// IntPtr type for the address space of the base GEP pointer.
595   bool accumulateConstantOffset(
596       const DataLayout &DL, APInt &Offset,
597       function_ref<bool(Value &, APInt &)> ExternalAnalysis = nullptr) const;
598 
599   static bool accumulateConstantOffset(
600       Type *SourceType, ArrayRef<const Value *> Index, const DataLayout &DL,
601       APInt &Offset,
602       function_ref<bool(Value &, APInt &)> ExternalAnalysis = nullptr);
603 
604   /// Collect the offset of this GEP as a map of Values to their associated
605   /// APInt multipliers, as well as a total Constant Offset.
606   bool collectOffset(const DataLayout &DL, unsigned BitWidth,
607                      MapVector<Value *, APInt> &VariableOffsets,
608                      APInt &ConstantOffset) const;
609 };
610 
611 class PtrToIntOperator
612     : public ConcreteOperator<Operator, Instruction::PtrToInt> {
613   friend class PtrToInt;
614   friend class ConstantExpr;
615 
616 public:
617   Value *getPointerOperand() {
618     return getOperand(0);
619   }
620   const Value *getPointerOperand() const {
621     return getOperand(0);
622   }
623 
624   static unsigned getPointerOperandIndex() {
625     return 0U;                      // get index for modifying correct operand
626   }
627 
628   /// Method to return the pointer operand as a PointerType.
629   Type *getPointerOperandType() const {
630     return getPointerOperand()->getType();
631   }
632 
633   /// Method to return the address space of the pointer operand.
634   unsigned getPointerAddressSpace() const {
635     return cast<PointerType>(getPointerOperandType())->getAddressSpace();
636   }
637 };
638 
639 class BitCastOperator
640     : public ConcreteOperator<Operator, Instruction::BitCast> {
641   friend class BitCastInst;
642   friend class ConstantExpr;
643 
644 public:
645   Type *getSrcTy() const {
646     return getOperand(0)->getType();
647   }
648 
649   Type *getDestTy() const {
650     return getType();
651   }
652 };
653 
654 class AddrSpaceCastOperator
655     : public ConcreteOperator<Operator, Instruction::AddrSpaceCast> {
656   friend class AddrSpaceCastInst;
657   friend class ConstantExpr;
658 
659 public:
660   Value *getPointerOperand() { return getOperand(0); }
661 
662   const Value *getPointerOperand() const { return getOperand(0); }
663 
664   unsigned getSrcAddressSpace() const {
665     return getPointerOperand()->getType()->getPointerAddressSpace();
666   }
667 
668   unsigned getDestAddressSpace() const {
669     return getType()->getPointerAddressSpace();
670   }
671 };
672 
673 } // end namespace llvm
674 
675 #endif // LLVM_IR_OPERATOR_H
676