xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/Transforms/Scalar/GVNExpression.h (revision fe6060f10f634930ff71b7c50291ddc610da2475)
10b57cec5SDimitry Andric //===- GVNExpression.h - GVN Expression classes -----------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric ///
110b57cec5SDimitry Andric /// The header file for the GVN pass that contains expression handling
120b57cec5SDimitry Andric /// classes
130b57cec5SDimitry Andric //
140b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #ifndef LLVM_TRANSFORMS_SCALAR_GVNEXPRESSION_H
170b57cec5SDimitry Andric #define LLVM_TRANSFORMS_SCALAR_GVNEXPRESSION_H
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric #include "llvm/ADT/Hashing.h"
200b57cec5SDimitry Andric #include "llvm/ADT/iterator_range.h"
210b57cec5SDimitry Andric #include "llvm/Analysis/MemorySSA.h"
220b57cec5SDimitry Andric #include "llvm/IR/Constant.h"
230b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
240b57cec5SDimitry Andric #include "llvm/IR/Value.h"
250b57cec5SDimitry Andric #include "llvm/Support/Allocator.h"
260b57cec5SDimitry Andric #include "llvm/Support/ArrayRecycler.h"
270b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
280b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
290b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
300b57cec5SDimitry Andric #include <algorithm>
310b57cec5SDimitry Andric #include <cassert>
320b57cec5SDimitry Andric #include <iterator>
330b57cec5SDimitry Andric #include <utility>
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric namespace llvm {
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric class BasicBlock;
380b57cec5SDimitry Andric class Type;
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric namespace GVNExpression {
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric enum ExpressionType {
430b57cec5SDimitry Andric   ET_Base,
440b57cec5SDimitry Andric   ET_Constant,
450b57cec5SDimitry Andric   ET_Variable,
460b57cec5SDimitry Andric   ET_Dead,
470b57cec5SDimitry Andric   ET_Unknown,
480b57cec5SDimitry Andric   ET_BasicStart,
490b57cec5SDimitry Andric   ET_Basic,
500b57cec5SDimitry Andric   ET_AggregateValue,
510b57cec5SDimitry Andric   ET_Phi,
520b57cec5SDimitry Andric   ET_MemoryStart,
530b57cec5SDimitry Andric   ET_Call,
540b57cec5SDimitry Andric   ET_Load,
550b57cec5SDimitry Andric   ET_Store,
560b57cec5SDimitry Andric   ET_MemoryEnd,
570b57cec5SDimitry Andric   ET_BasicEnd
580b57cec5SDimitry Andric };
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric class Expression {
610b57cec5SDimitry Andric private:
620b57cec5SDimitry Andric   ExpressionType EType;
630b57cec5SDimitry Andric   unsigned Opcode;
640b57cec5SDimitry Andric   mutable hash_code HashVal = 0;
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric public:
670b57cec5SDimitry Andric   Expression(ExpressionType ET = ET_Base, unsigned O = ~2U)
EType(ET)680b57cec5SDimitry Andric       : EType(ET), Opcode(O) {}
690b57cec5SDimitry Andric   Expression(const Expression &) = delete;
700b57cec5SDimitry Andric   Expression &operator=(const Expression &) = delete;
710b57cec5SDimitry Andric   virtual ~Expression();
720b57cec5SDimitry Andric 
getEmptyKey()730b57cec5SDimitry Andric   static unsigned getEmptyKey() { return ~0U; }
getTombstoneKey()740b57cec5SDimitry Andric   static unsigned getTombstoneKey() { return ~1U; }
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   bool operator!=(const Expression &Other) const { return !(*this == Other); }
770b57cec5SDimitry Andric   bool operator==(const Expression &Other) const {
780b57cec5SDimitry Andric     if (getOpcode() != Other.getOpcode())
790b57cec5SDimitry Andric       return false;
800b57cec5SDimitry Andric     if (getOpcode() == getEmptyKey() || getOpcode() == getTombstoneKey())
810b57cec5SDimitry Andric       return true;
820b57cec5SDimitry Andric     // Compare the expression type for anything but load and store.
830b57cec5SDimitry Andric     // For load and store we set the opcode to zero to make them equal.
840b57cec5SDimitry Andric     if (getExpressionType() != ET_Load && getExpressionType() != ET_Store &&
850b57cec5SDimitry Andric         getExpressionType() != Other.getExpressionType())
860b57cec5SDimitry Andric       return false;
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric     return equals(Other);
890b57cec5SDimitry Andric   }
900b57cec5SDimitry Andric 
getComputedHash()910b57cec5SDimitry Andric   hash_code getComputedHash() const {
920b57cec5SDimitry Andric     // It's theoretically possible for a thing to hash to zero.  In that case,
930b57cec5SDimitry Andric     // we will just compute the hash a few extra times, which is no worse that
940b57cec5SDimitry Andric     // we did before, which was to compute it always.
950b57cec5SDimitry Andric     if (static_cast<unsigned>(HashVal) == 0)
960b57cec5SDimitry Andric       HashVal = getHashValue();
970b57cec5SDimitry Andric     return HashVal;
980b57cec5SDimitry Andric   }
990b57cec5SDimitry Andric 
equals(const Expression & Other)1000b57cec5SDimitry Andric   virtual bool equals(const Expression &Other) const { return true; }
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   // Return true if the two expressions are exactly the same, including the
1030b57cec5SDimitry Andric   // normally ignored fields.
exactlyEquals(const Expression & Other)1040b57cec5SDimitry Andric   virtual bool exactlyEquals(const Expression &Other) const {
1050b57cec5SDimitry Andric     return getExpressionType() == Other.getExpressionType() && equals(Other);
1060b57cec5SDimitry Andric   }
1070b57cec5SDimitry Andric 
getOpcode()1080b57cec5SDimitry Andric   unsigned getOpcode() const { return Opcode; }
setOpcode(unsigned opcode)1090b57cec5SDimitry Andric   void setOpcode(unsigned opcode) { Opcode = opcode; }
getExpressionType()1100b57cec5SDimitry Andric   ExpressionType getExpressionType() const { return EType; }
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   // We deliberately leave the expression type out of the hash value.
getHashValue()1130b57cec5SDimitry Andric   virtual hash_code getHashValue() const { return getOpcode(); }
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric   // Debugging support
printInternal(raw_ostream & OS,bool PrintEType)1160b57cec5SDimitry Andric   virtual void printInternal(raw_ostream &OS, bool PrintEType) const {
1170b57cec5SDimitry Andric     if (PrintEType)
1180b57cec5SDimitry Andric       OS << "etype = " << getExpressionType() << ",";
1190b57cec5SDimitry Andric     OS << "opcode = " << getOpcode() << ", ";
1200b57cec5SDimitry Andric   }
1210b57cec5SDimitry Andric 
print(raw_ostream & OS)1220b57cec5SDimitry Andric   void print(raw_ostream &OS) const {
1230b57cec5SDimitry Andric     OS << "{ ";
1240b57cec5SDimitry Andric     printInternal(OS, true);
1250b57cec5SDimitry Andric     OS << "}";
1260b57cec5SDimitry Andric   }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric   LLVM_DUMP_METHOD void dump() const;
1290b57cec5SDimitry Andric };
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const Expression &E) {
1320b57cec5SDimitry Andric   E.print(OS);
1330b57cec5SDimitry Andric   return OS;
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric class BasicExpression : public Expression {
1370b57cec5SDimitry Andric private:
1380b57cec5SDimitry Andric   using RecyclerType = ArrayRecycler<Value *>;
1390b57cec5SDimitry Andric   using RecyclerCapacity = RecyclerType::Capacity;
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   Value **Operands = nullptr;
1420b57cec5SDimitry Andric   unsigned MaxOperands;
1430b57cec5SDimitry Andric   unsigned NumOperands = 0;
1440b57cec5SDimitry Andric   Type *ValueType = nullptr;
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric public:
BasicExpression(unsigned NumOperands)1470b57cec5SDimitry Andric   BasicExpression(unsigned NumOperands)
1480b57cec5SDimitry Andric       : BasicExpression(NumOperands, ET_Basic) {}
BasicExpression(unsigned NumOperands,ExpressionType ET)1490b57cec5SDimitry Andric   BasicExpression(unsigned NumOperands, ExpressionType ET)
1500b57cec5SDimitry Andric       : Expression(ET), MaxOperands(NumOperands) {}
1510b57cec5SDimitry Andric   BasicExpression() = delete;
1520b57cec5SDimitry Andric   BasicExpression(const BasicExpression &) = delete;
1530b57cec5SDimitry Andric   BasicExpression &operator=(const BasicExpression &) = delete;
1540b57cec5SDimitry Andric   ~BasicExpression() override;
1550b57cec5SDimitry Andric 
classof(const Expression * EB)1560b57cec5SDimitry Andric   static bool classof(const Expression *EB) {
1570b57cec5SDimitry Andric     ExpressionType ET = EB->getExpressionType();
1580b57cec5SDimitry Andric     return ET > ET_BasicStart && ET < ET_BasicEnd;
1590b57cec5SDimitry Andric   }
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric   /// Swap two operands. Used during GVN to put commutative operands in
1620b57cec5SDimitry Andric   /// order.
swapOperands(unsigned First,unsigned Second)1630b57cec5SDimitry Andric   void swapOperands(unsigned First, unsigned Second) {
1640b57cec5SDimitry Andric     std::swap(Operands[First], Operands[Second]);
1650b57cec5SDimitry Andric   }
1660b57cec5SDimitry Andric 
getOperand(unsigned N)1670b57cec5SDimitry Andric   Value *getOperand(unsigned N) const {
1680b57cec5SDimitry Andric     assert(Operands && "Operands not allocated");
1690b57cec5SDimitry Andric     assert(N < NumOperands && "Operand out of range");
1700b57cec5SDimitry Andric     return Operands[N];
1710b57cec5SDimitry Andric   }
1720b57cec5SDimitry Andric 
setOperand(unsigned N,Value * V)1730b57cec5SDimitry Andric   void setOperand(unsigned N, Value *V) {
1740b57cec5SDimitry Andric     assert(Operands && "Operands not allocated before setting");
1750b57cec5SDimitry Andric     assert(N < NumOperands && "Operand out of range");
1760b57cec5SDimitry Andric     Operands[N] = V;
1770b57cec5SDimitry Andric   }
1780b57cec5SDimitry Andric 
getNumOperands()1790b57cec5SDimitry Andric   unsigned getNumOperands() const { return NumOperands; }
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric   using op_iterator = Value **;
1820b57cec5SDimitry Andric   using const_op_iterator = Value *const *;
1830b57cec5SDimitry Andric 
op_begin()1840b57cec5SDimitry Andric   op_iterator op_begin() { return Operands; }
op_end()1850b57cec5SDimitry Andric   op_iterator op_end() { return Operands + NumOperands; }
op_begin()1860b57cec5SDimitry Andric   const_op_iterator op_begin() const { return Operands; }
op_end()1870b57cec5SDimitry Andric   const_op_iterator op_end() const { return Operands + NumOperands; }
operands()1880b57cec5SDimitry Andric   iterator_range<op_iterator> operands() {
1890b57cec5SDimitry Andric     return iterator_range<op_iterator>(op_begin(), op_end());
1900b57cec5SDimitry Andric   }
operands()1910b57cec5SDimitry Andric   iterator_range<const_op_iterator> operands() const {
1920b57cec5SDimitry Andric     return iterator_range<const_op_iterator>(op_begin(), op_end());
1930b57cec5SDimitry Andric   }
1940b57cec5SDimitry Andric 
op_push_back(Value * Arg)1950b57cec5SDimitry Andric   void op_push_back(Value *Arg) {
1960b57cec5SDimitry Andric     assert(NumOperands < MaxOperands && "Tried to add too many operands");
1970b57cec5SDimitry Andric     assert(Operands && "Operandss not allocated before pushing");
1980b57cec5SDimitry Andric     Operands[NumOperands++] = Arg;
1990b57cec5SDimitry Andric   }
op_empty()2000b57cec5SDimitry Andric   bool op_empty() const { return getNumOperands() == 0; }
2010b57cec5SDimitry Andric 
allocateOperands(RecyclerType & Recycler,BumpPtrAllocator & Allocator)2020b57cec5SDimitry Andric   void allocateOperands(RecyclerType &Recycler, BumpPtrAllocator &Allocator) {
2030b57cec5SDimitry Andric     assert(!Operands && "Operands already allocated");
2040b57cec5SDimitry Andric     Operands = Recycler.allocate(RecyclerCapacity::get(MaxOperands), Allocator);
2050b57cec5SDimitry Andric   }
deallocateOperands(RecyclerType & Recycler)2060b57cec5SDimitry Andric   void deallocateOperands(RecyclerType &Recycler) {
2070b57cec5SDimitry Andric     Recycler.deallocate(RecyclerCapacity::get(MaxOperands), Operands);
2080b57cec5SDimitry Andric   }
2090b57cec5SDimitry Andric 
setType(Type * T)2100b57cec5SDimitry Andric   void setType(Type *T) { ValueType = T; }
getType()2110b57cec5SDimitry Andric   Type *getType() const { return ValueType; }
2120b57cec5SDimitry Andric 
equals(const Expression & Other)2130b57cec5SDimitry Andric   bool equals(const Expression &Other) const override {
2140b57cec5SDimitry Andric     if (getOpcode() != Other.getOpcode())
2150b57cec5SDimitry Andric       return false;
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric     const auto &OE = cast<BasicExpression>(Other);
2180b57cec5SDimitry Andric     return getType() == OE.getType() && NumOperands == OE.NumOperands &&
2190b57cec5SDimitry Andric            std::equal(op_begin(), op_end(), OE.op_begin());
2200b57cec5SDimitry Andric   }
2210b57cec5SDimitry Andric 
getHashValue()2220b57cec5SDimitry Andric   hash_code getHashValue() const override {
2230b57cec5SDimitry Andric     return hash_combine(this->Expression::getHashValue(), ValueType,
2240b57cec5SDimitry Andric                         hash_combine_range(op_begin(), op_end()));
2250b57cec5SDimitry Andric   }
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric   // Debugging support
printInternal(raw_ostream & OS,bool PrintEType)2280b57cec5SDimitry Andric   void printInternal(raw_ostream &OS, bool PrintEType) const override {
2290b57cec5SDimitry Andric     if (PrintEType)
2300b57cec5SDimitry Andric       OS << "ExpressionTypeBasic, ";
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric     this->Expression::printInternal(OS, false);
2330b57cec5SDimitry Andric     OS << "operands = {";
2340b57cec5SDimitry Andric     for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
2350b57cec5SDimitry Andric       OS << "[" << i << "] = ";
2360b57cec5SDimitry Andric       Operands[i]->printAsOperand(OS);
2370b57cec5SDimitry Andric       OS << "  ";
2380b57cec5SDimitry Andric     }
2390b57cec5SDimitry Andric     OS << "} ";
2400b57cec5SDimitry Andric   }
2410b57cec5SDimitry Andric };
2420b57cec5SDimitry Andric 
243*fe6060f1SDimitry Andric class op_inserter {
2440b57cec5SDimitry Andric private:
2450b57cec5SDimitry Andric   using Container = BasicExpression;
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric   Container *BE;
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric public:
250*fe6060f1SDimitry Andric   using iterator_category = std::output_iterator_tag;
251*fe6060f1SDimitry Andric   using value_type = void;
252*fe6060f1SDimitry Andric   using difference_type = void;
253*fe6060f1SDimitry Andric   using pointer = void;
254*fe6060f1SDimitry Andric   using reference = void;
255*fe6060f1SDimitry Andric 
op_inserter(BasicExpression & E)2560b57cec5SDimitry Andric   explicit op_inserter(BasicExpression &E) : BE(&E) {}
op_inserter(BasicExpression * E)2570b57cec5SDimitry Andric   explicit op_inserter(BasicExpression *E) : BE(E) {}
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric   op_inserter &operator=(Value *val) {
2600b57cec5SDimitry Andric     BE->op_push_back(val);
2610b57cec5SDimitry Andric     return *this;
2620b57cec5SDimitry Andric   }
2630b57cec5SDimitry Andric   op_inserter &operator*() { return *this; }
2640b57cec5SDimitry Andric   op_inserter &operator++() { return *this; }
2650b57cec5SDimitry Andric   op_inserter &operator++(int) { return *this; }
2660b57cec5SDimitry Andric };
2670b57cec5SDimitry Andric 
2680b57cec5SDimitry Andric class MemoryExpression : public BasicExpression {
2690b57cec5SDimitry Andric private:
2700b57cec5SDimitry Andric   const MemoryAccess *MemoryLeader;
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric public:
MemoryExpression(unsigned NumOperands,enum ExpressionType EType,const MemoryAccess * MemoryLeader)2730b57cec5SDimitry Andric   MemoryExpression(unsigned NumOperands, enum ExpressionType EType,
2740b57cec5SDimitry Andric                    const MemoryAccess *MemoryLeader)
2750b57cec5SDimitry Andric       : BasicExpression(NumOperands, EType), MemoryLeader(MemoryLeader) {}
2760b57cec5SDimitry Andric   MemoryExpression() = delete;
2770b57cec5SDimitry Andric   MemoryExpression(const MemoryExpression &) = delete;
2780b57cec5SDimitry Andric   MemoryExpression &operator=(const MemoryExpression &) = delete;
2790b57cec5SDimitry Andric 
classof(const Expression * EB)2800b57cec5SDimitry Andric   static bool classof(const Expression *EB) {
2810b57cec5SDimitry Andric     return EB->getExpressionType() > ET_MemoryStart &&
2820b57cec5SDimitry Andric            EB->getExpressionType() < ET_MemoryEnd;
2830b57cec5SDimitry Andric   }
2840b57cec5SDimitry Andric 
getHashValue()2850b57cec5SDimitry Andric   hash_code getHashValue() const override {
2860b57cec5SDimitry Andric     return hash_combine(this->BasicExpression::getHashValue(), MemoryLeader);
2870b57cec5SDimitry Andric   }
2880b57cec5SDimitry Andric 
equals(const Expression & Other)2890b57cec5SDimitry Andric   bool equals(const Expression &Other) const override {
2900b57cec5SDimitry Andric     if (!this->BasicExpression::equals(Other))
2910b57cec5SDimitry Andric       return false;
2920b57cec5SDimitry Andric     const MemoryExpression &OtherMCE = cast<MemoryExpression>(Other);
2930b57cec5SDimitry Andric 
2940b57cec5SDimitry Andric     return MemoryLeader == OtherMCE.MemoryLeader;
2950b57cec5SDimitry Andric   }
2960b57cec5SDimitry Andric 
getMemoryLeader()2970b57cec5SDimitry Andric   const MemoryAccess *getMemoryLeader() const { return MemoryLeader; }
setMemoryLeader(const MemoryAccess * ML)2980b57cec5SDimitry Andric   void setMemoryLeader(const MemoryAccess *ML) { MemoryLeader = ML; }
2990b57cec5SDimitry Andric };
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric class CallExpression final : public MemoryExpression {
3020b57cec5SDimitry Andric private:
3030b57cec5SDimitry Andric   CallInst *Call;
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric public:
CallExpression(unsigned NumOperands,CallInst * C,const MemoryAccess * MemoryLeader)3060b57cec5SDimitry Andric   CallExpression(unsigned NumOperands, CallInst *C,
3070b57cec5SDimitry Andric                  const MemoryAccess *MemoryLeader)
3080b57cec5SDimitry Andric       : MemoryExpression(NumOperands, ET_Call, MemoryLeader), Call(C) {}
3090b57cec5SDimitry Andric   CallExpression() = delete;
3100b57cec5SDimitry Andric   CallExpression(const CallExpression &) = delete;
3110b57cec5SDimitry Andric   CallExpression &operator=(const CallExpression &) = delete;
3120b57cec5SDimitry Andric   ~CallExpression() override;
3130b57cec5SDimitry Andric 
classof(const Expression * EB)3140b57cec5SDimitry Andric   static bool classof(const Expression *EB) {
3150b57cec5SDimitry Andric     return EB->getExpressionType() == ET_Call;
3160b57cec5SDimitry Andric   }
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric   // Debugging support
printInternal(raw_ostream & OS,bool PrintEType)3190b57cec5SDimitry Andric   void printInternal(raw_ostream &OS, bool PrintEType) const override {
3200b57cec5SDimitry Andric     if (PrintEType)
3210b57cec5SDimitry Andric       OS << "ExpressionTypeCall, ";
3220b57cec5SDimitry Andric     this->BasicExpression::printInternal(OS, false);
3230b57cec5SDimitry Andric     OS << " represents call at ";
3240b57cec5SDimitry Andric     Call->printAsOperand(OS);
3250b57cec5SDimitry Andric   }
3260b57cec5SDimitry Andric };
3270b57cec5SDimitry Andric 
3280b57cec5SDimitry Andric class LoadExpression final : public MemoryExpression {
3290b57cec5SDimitry Andric private:
3300b57cec5SDimitry Andric   LoadInst *Load;
3310b57cec5SDimitry Andric 
3320b57cec5SDimitry Andric public:
LoadExpression(unsigned NumOperands,LoadInst * L,const MemoryAccess * MemoryLeader)3330b57cec5SDimitry Andric   LoadExpression(unsigned NumOperands, LoadInst *L,
3340b57cec5SDimitry Andric                  const MemoryAccess *MemoryLeader)
3350b57cec5SDimitry Andric       : LoadExpression(ET_Load, NumOperands, L, MemoryLeader) {}
3360b57cec5SDimitry Andric 
LoadExpression(enum ExpressionType EType,unsigned NumOperands,LoadInst * L,const MemoryAccess * MemoryLeader)3370b57cec5SDimitry Andric   LoadExpression(enum ExpressionType EType, unsigned NumOperands, LoadInst *L,
3380b57cec5SDimitry Andric                  const MemoryAccess *MemoryLeader)
3395ffd83dbSDimitry Andric       : MemoryExpression(NumOperands, EType, MemoryLeader), Load(L) {}
3400b57cec5SDimitry Andric 
3410b57cec5SDimitry Andric   LoadExpression() = delete;
3420b57cec5SDimitry Andric   LoadExpression(const LoadExpression &) = delete;
3430b57cec5SDimitry Andric   LoadExpression &operator=(const LoadExpression &) = delete;
3440b57cec5SDimitry Andric   ~LoadExpression() override;
3450b57cec5SDimitry Andric 
classof(const Expression * EB)3460b57cec5SDimitry Andric   static bool classof(const Expression *EB) {
3470b57cec5SDimitry Andric     return EB->getExpressionType() == ET_Load;
3480b57cec5SDimitry Andric   }
3490b57cec5SDimitry Andric 
getLoadInst()3500b57cec5SDimitry Andric   LoadInst *getLoadInst() const { return Load; }
setLoadInst(LoadInst * L)3510b57cec5SDimitry Andric   void setLoadInst(LoadInst *L) { Load = L; }
3520b57cec5SDimitry Andric 
3530b57cec5SDimitry Andric   bool equals(const Expression &Other) const override;
exactlyEquals(const Expression & Other)3540b57cec5SDimitry Andric   bool exactlyEquals(const Expression &Other) const override {
3550b57cec5SDimitry Andric     return Expression::exactlyEquals(Other) &&
3560b57cec5SDimitry Andric            cast<LoadExpression>(Other).getLoadInst() == getLoadInst();
3570b57cec5SDimitry Andric   }
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric   // Debugging support
printInternal(raw_ostream & OS,bool PrintEType)3600b57cec5SDimitry Andric   void printInternal(raw_ostream &OS, bool PrintEType) const override {
3610b57cec5SDimitry Andric     if (PrintEType)
3620b57cec5SDimitry Andric       OS << "ExpressionTypeLoad, ";
3630b57cec5SDimitry Andric     this->BasicExpression::printInternal(OS, false);
3640b57cec5SDimitry Andric     OS << " represents Load at ";
3650b57cec5SDimitry Andric     Load->printAsOperand(OS);
3660b57cec5SDimitry Andric     OS << " with MemoryLeader " << *getMemoryLeader();
3670b57cec5SDimitry Andric   }
3680b57cec5SDimitry Andric };
3690b57cec5SDimitry Andric 
3700b57cec5SDimitry Andric class StoreExpression final : public MemoryExpression {
3710b57cec5SDimitry Andric private:
3720b57cec5SDimitry Andric   StoreInst *Store;
3730b57cec5SDimitry Andric   Value *StoredValue;
3740b57cec5SDimitry Andric 
3750b57cec5SDimitry Andric public:
StoreExpression(unsigned NumOperands,StoreInst * S,Value * StoredValue,const MemoryAccess * MemoryLeader)3760b57cec5SDimitry Andric   StoreExpression(unsigned NumOperands, StoreInst *S, Value *StoredValue,
3770b57cec5SDimitry Andric                   const MemoryAccess *MemoryLeader)
3780b57cec5SDimitry Andric       : MemoryExpression(NumOperands, ET_Store, MemoryLeader), Store(S),
3790b57cec5SDimitry Andric         StoredValue(StoredValue) {}
3800b57cec5SDimitry Andric   StoreExpression() = delete;
3810b57cec5SDimitry Andric   StoreExpression(const StoreExpression &) = delete;
3820b57cec5SDimitry Andric   StoreExpression &operator=(const StoreExpression &) = delete;
3830b57cec5SDimitry Andric   ~StoreExpression() override;
3840b57cec5SDimitry Andric 
classof(const Expression * EB)3850b57cec5SDimitry Andric   static bool classof(const Expression *EB) {
3860b57cec5SDimitry Andric     return EB->getExpressionType() == ET_Store;
3870b57cec5SDimitry Andric   }
3880b57cec5SDimitry Andric 
getStoreInst()3890b57cec5SDimitry Andric   StoreInst *getStoreInst() const { return Store; }
getStoredValue()3900b57cec5SDimitry Andric   Value *getStoredValue() const { return StoredValue; }
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric   bool equals(const Expression &Other) const override;
3930b57cec5SDimitry Andric 
exactlyEquals(const Expression & Other)3940b57cec5SDimitry Andric   bool exactlyEquals(const Expression &Other) const override {
3950b57cec5SDimitry Andric     return Expression::exactlyEquals(Other) &&
3960b57cec5SDimitry Andric            cast<StoreExpression>(Other).getStoreInst() == getStoreInst();
3970b57cec5SDimitry Andric   }
3980b57cec5SDimitry Andric 
3990b57cec5SDimitry Andric   // Debugging support
printInternal(raw_ostream & OS,bool PrintEType)4000b57cec5SDimitry Andric   void printInternal(raw_ostream &OS, bool PrintEType) const override {
4010b57cec5SDimitry Andric     if (PrintEType)
4020b57cec5SDimitry Andric       OS << "ExpressionTypeStore, ";
4030b57cec5SDimitry Andric     this->BasicExpression::printInternal(OS, false);
4040b57cec5SDimitry Andric     OS << " represents Store  " << *Store;
4050b57cec5SDimitry Andric     OS << " with StoredValue ";
4060b57cec5SDimitry Andric     StoredValue->printAsOperand(OS);
4070b57cec5SDimitry Andric     OS << " and MemoryLeader " << *getMemoryLeader();
4080b57cec5SDimitry Andric   }
4090b57cec5SDimitry Andric };
4100b57cec5SDimitry Andric 
4110b57cec5SDimitry Andric class AggregateValueExpression final : public BasicExpression {
4120b57cec5SDimitry Andric private:
4130b57cec5SDimitry Andric   unsigned MaxIntOperands;
4140b57cec5SDimitry Andric   unsigned NumIntOperands = 0;
4150b57cec5SDimitry Andric   unsigned *IntOperands = nullptr;
4160b57cec5SDimitry Andric 
4170b57cec5SDimitry Andric public:
AggregateValueExpression(unsigned NumOperands,unsigned NumIntOperands)4180b57cec5SDimitry Andric   AggregateValueExpression(unsigned NumOperands, unsigned NumIntOperands)
4190b57cec5SDimitry Andric       : BasicExpression(NumOperands, ET_AggregateValue),
4200b57cec5SDimitry Andric         MaxIntOperands(NumIntOperands) {}
4210b57cec5SDimitry Andric   AggregateValueExpression() = delete;
4220b57cec5SDimitry Andric   AggregateValueExpression(const AggregateValueExpression &) = delete;
4230b57cec5SDimitry Andric   AggregateValueExpression &
4240b57cec5SDimitry Andric   operator=(const AggregateValueExpression &) = delete;
4250b57cec5SDimitry Andric   ~AggregateValueExpression() override;
4260b57cec5SDimitry Andric 
classof(const Expression * EB)4270b57cec5SDimitry Andric   static bool classof(const Expression *EB) {
4280b57cec5SDimitry Andric     return EB->getExpressionType() == ET_AggregateValue;
4290b57cec5SDimitry Andric   }
4300b57cec5SDimitry Andric 
4310b57cec5SDimitry Andric   using int_arg_iterator = unsigned *;
4320b57cec5SDimitry Andric   using const_int_arg_iterator = const unsigned *;
4330b57cec5SDimitry Andric 
int_op_begin()4340b57cec5SDimitry Andric   int_arg_iterator int_op_begin() { return IntOperands; }
int_op_end()4350b57cec5SDimitry Andric   int_arg_iterator int_op_end() { return IntOperands + NumIntOperands; }
int_op_begin()4360b57cec5SDimitry Andric   const_int_arg_iterator int_op_begin() const { return IntOperands; }
int_op_end()4370b57cec5SDimitry Andric   const_int_arg_iterator int_op_end() const {
4380b57cec5SDimitry Andric     return IntOperands + NumIntOperands;
4390b57cec5SDimitry Andric   }
int_op_size()4400b57cec5SDimitry Andric   unsigned int_op_size() const { return NumIntOperands; }
int_op_empty()4410b57cec5SDimitry Andric   bool int_op_empty() const { return NumIntOperands == 0; }
int_op_push_back(unsigned IntOperand)4420b57cec5SDimitry Andric   void int_op_push_back(unsigned IntOperand) {
4430b57cec5SDimitry Andric     assert(NumIntOperands < MaxIntOperands &&
4440b57cec5SDimitry Andric            "Tried to add too many int operands");
4450b57cec5SDimitry Andric     assert(IntOperands && "Operands not allocated before pushing");
4460b57cec5SDimitry Andric     IntOperands[NumIntOperands++] = IntOperand;
4470b57cec5SDimitry Andric   }
4480b57cec5SDimitry Andric 
allocateIntOperands(BumpPtrAllocator & Allocator)4490b57cec5SDimitry Andric   virtual void allocateIntOperands(BumpPtrAllocator &Allocator) {
4500b57cec5SDimitry Andric     assert(!IntOperands && "Operands already allocated");
4510b57cec5SDimitry Andric     IntOperands = Allocator.Allocate<unsigned>(MaxIntOperands);
4520b57cec5SDimitry Andric   }
4530b57cec5SDimitry Andric 
equals(const Expression & Other)4540b57cec5SDimitry Andric   bool equals(const Expression &Other) const override {
4550b57cec5SDimitry Andric     if (!this->BasicExpression::equals(Other))
4560b57cec5SDimitry Andric       return false;
4570b57cec5SDimitry Andric     const AggregateValueExpression &OE = cast<AggregateValueExpression>(Other);
4580b57cec5SDimitry Andric     return NumIntOperands == OE.NumIntOperands &&
4590b57cec5SDimitry Andric            std::equal(int_op_begin(), int_op_end(), OE.int_op_begin());
4600b57cec5SDimitry Andric   }
4610b57cec5SDimitry Andric 
getHashValue()4620b57cec5SDimitry Andric   hash_code getHashValue() const override {
4630b57cec5SDimitry Andric     return hash_combine(this->BasicExpression::getHashValue(),
4640b57cec5SDimitry Andric                         hash_combine_range(int_op_begin(), int_op_end()));
4650b57cec5SDimitry Andric   }
4660b57cec5SDimitry Andric 
4670b57cec5SDimitry Andric   // Debugging support
printInternal(raw_ostream & OS,bool PrintEType)4680b57cec5SDimitry Andric   void printInternal(raw_ostream &OS, bool PrintEType) const override {
4690b57cec5SDimitry Andric     if (PrintEType)
4700b57cec5SDimitry Andric       OS << "ExpressionTypeAggregateValue, ";
4710b57cec5SDimitry Andric     this->BasicExpression::printInternal(OS, false);
4720b57cec5SDimitry Andric     OS << ", intoperands = {";
4730b57cec5SDimitry Andric     for (unsigned i = 0, e = int_op_size(); i != e; ++i) {
4740b57cec5SDimitry Andric       OS << "[" << i << "] = " << IntOperands[i] << "  ";
4750b57cec5SDimitry Andric     }
4760b57cec5SDimitry Andric     OS << "}";
4770b57cec5SDimitry Andric   }
4780b57cec5SDimitry Andric };
4790b57cec5SDimitry Andric 
480*fe6060f1SDimitry Andric class int_op_inserter {
4810b57cec5SDimitry Andric private:
4820b57cec5SDimitry Andric   using Container = AggregateValueExpression;
4830b57cec5SDimitry Andric 
4840b57cec5SDimitry Andric   Container *AVE;
4850b57cec5SDimitry Andric 
4860b57cec5SDimitry Andric public:
487*fe6060f1SDimitry Andric   using iterator_category = std::output_iterator_tag;
488*fe6060f1SDimitry Andric   using value_type = void;
489*fe6060f1SDimitry Andric   using difference_type = void;
490*fe6060f1SDimitry Andric   using pointer = void;
491*fe6060f1SDimitry Andric   using reference = void;
492*fe6060f1SDimitry Andric 
int_op_inserter(AggregateValueExpression & E)4930b57cec5SDimitry Andric   explicit int_op_inserter(AggregateValueExpression &E) : AVE(&E) {}
int_op_inserter(AggregateValueExpression * E)4940b57cec5SDimitry Andric   explicit int_op_inserter(AggregateValueExpression *E) : AVE(E) {}
4950b57cec5SDimitry Andric 
4960b57cec5SDimitry Andric   int_op_inserter &operator=(unsigned int val) {
4970b57cec5SDimitry Andric     AVE->int_op_push_back(val);
4980b57cec5SDimitry Andric     return *this;
4990b57cec5SDimitry Andric   }
5000b57cec5SDimitry Andric   int_op_inserter &operator*() { return *this; }
5010b57cec5SDimitry Andric   int_op_inserter &operator++() { return *this; }
5020b57cec5SDimitry Andric   int_op_inserter &operator++(int) { return *this; }
5030b57cec5SDimitry Andric };
5040b57cec5SDimitry Andric 
5050b57cec5SDimitry Andric class PHIExpression final : public BasicExpression {
5060b57cec5SDimitry Andric private:
5070b57cec5SDimitry Andric   BasicBlock *BB;
5080b57cec5SDimitry Andric 
5090b57cec5SDimitry Andric public:
PHIExpression(unsigned NumOperands,BasicBlock * B)5100b57cec5SDimitry Andric   PHIExpression(unsigned NumOperands, BasicBlock *B)
5110b57cec5SDimitry Andric       : BasicExpression(NumOperands, ET_Phi), BB(B) {}
5120b57cec5SDimitry Andric   PHIExpression() = delete;
5130b57cec5SDimitry Andric   PHIExpression(const PHIExpression &) = delete;
5140b57cec5SDimitry Andric   PHIExpression &operator=(const PHIExpression &) = delete;
5150b57cec5SDimitry Andric   ~PHIExpression() override;
5160b57cec5SDimitry Andric 
classof(const Expression * EB)5170b57cec5SDimitry Andric   static bool classof(const Expression *EB) {
5180b57cec5SDimitry Andric     return EB->getExpressionType() == ET_Phi;
5190b57cec5SDimitry Andric   }
5200b57cec5SDimitry Andric 
equals(const Expression & Other)5210b57cec5SDimitry Andric   bool equals(const Expression &Other) const override {
5220b57cec5SDimitry Andric     if (!this->BasicExpression::equals(Other))
5230b57cec5SDimitry Andric       return false;
5240b57cec5SDimitry Andric     const PHIExpression &OE = cast<PHIExpression>(Other);
5250b57cec5SDimitry Andric     return BB == OE.BB;
5260b57cec5SDimitry Andric   }
5270b57cec5SDimitry Andric 
getHashValue()5280b57cec5SDimitry Andric   hash_code getHashValue() const override {
5290b57cec5SDimitry Andric     return hash_combine(this->BasicExpression::getHashValue(), BB);
5300b57cec5SDimitry Andric   }
5310b57cec5SDimitry Andric 
5320b57cec5SDimitry Andric   // Debugging support
printInternal(raw_ostream & OS,bool PrintEType)5330b57cec5SDimitry Andric   void printInternal(raw_ostream &OS, bool PrintEType) const override {
5340b57cec5SDimitry Andric     if (PrintEType)
5350b57cec5SDimitry Andric       OS << "ExpressionTypePhi, ";
5360b57cec5SDimitry Andric     this->BasicExpression::printInternal(OS, false);
5370b57cec5SDimitry Andric     OS << "bb = " << BB;
5380b57cec5SDimitry Andric   }
5390b57cec5SDimitry Andric };
5400b57cec5SDimitry Andric 
5410b57cec5SDimitry Andric class DeadExpression final : public Expression {
5420b57cec5SDimitry Andric public:
DeadExpression()5430b57cec5SDimitry Andric   DeadExpression() : Expression(ET_Dead) {}
5440b57cec5SDimitry Andric   DeadExpression(const DeadExpression &) = delete;
5450b57cec5SDimitry Andric   DeadExpression &operator=(const DeadExpression &) = delete;
5460b57cec5SDimitry Andric 
classof(const Expression * E)5470b57cec5SDimitry Andric   static bool classof(const Expression *E) {
5480b57cec5SDimitry Andric     return E->getExpressionType() == ET_Dead;
5490b57cec5SDimitry Andric   }
5500b57cec5SDimitry Andric };
5510b57cec5SDimitry Andric 
5520b57cec5SDimitry Andric class VariableExpression final : public Expression {
5530b57cec5SDimitry Andric private:
5540b57cec5SDimitry Andric   Value *VariableValue;
5550b57cec5SDimitry Andric 
5560b57cec5SDimitry Andric public:
VariableExpression(Value * V)5570b57cec5SDimitry Andric   VariableExpression(Value *V) : Expression(ET_Variable), VariableValue(V) {}
5580b57cec5SDimitry Andric   VariableExpression() = delete;
5590b57cec5SDimitry Andric   VariableExpression(const VariableExpression &) = delete;
5600b57cec5SDimitry Andric   VariableExpression &operator=(const VariableExpression &) = delete;
5610b57cec5SDimitry Andric 
classof(const Expression * EB)5620b57cec5SDimitry Andric   static bool classof(const Expression *EB) {
5630b57cec5SDimitry Andric     return EB->getExpressionType() == ET_Variable;
5640b57cec5SDimitry Andric   }
5650b57cec5SDimitry Andric 
getVariableValue()5660b57cec5SDimitry Andric   Value *getVariableValue() const { return VariableValue; }
setVariableValue(Value * V)5670b57cec5SDimitry Andric   void setVariableValue(Value *V) { VariableValue = V; }
5680b57cec5SDimitry Andric 
equals(const Expression & Other)5690b57cec5SDimitry Andric   bool equals(const Expression &Other) const override {
5700b57cec5SDimitry Andric     const VariableExpression &OC = cast<VariableExpression>(Other);
5710b57cec5SDimitry Andric     return VariableValue == OC.VariableValue;
5720b57cec5SDimitry Andric   }
5730b57cec5SDimitry Andric 
getHashValue()5740b57cec5SDimitry Andric   hash_code getHashValue() const override {
5750b57cec5SDimitry Andric     return hash_combine(this->Expression::getHashValue(),
5760b57cec5SDimitry Andric                         VariableValue->getType(), VariableValue);
5770b57cec5SDimitry Andric   }
5780b57cec5SDimitry Andric 
5790b57cec5SDimitry Andric   // Debugging support
printInternal(raw_ostream & OS,bool PrintEType)5800b57cec5SDimitry Andric   void printInternal(raw_ostream &OS, bool PrintEType) const override {
5810b57cec5SDimitry Andric     if (PrintEType)
5820b57cec5SDimitry Andric       OS << "ExpressionTypeVariable, ";
5830b57cec5SDimitry Andric     this->Expression::printInternal(OS, false);
5840b57cec5SDimitry Andric     OS << " variable = " << *VariableValue;
5850b57cec5SDimitry Andric   }
5860b57cec5SDimitry Andric };
5870b57cec5SDimitry Andric 
5880b57cec5SDimitry Andric class ConstantExpression final : public Expression {
5890b57cec5SDimitry Andric private:
5900b57cec5SDimitry Andric   Constant *ConstantValue = nullptr;
5910b57cec5SDimitry Andric 
5920b57cec5SDimitry Andric public:
ConstantExpression()5930b57cec5SDimitry Andric   ConstantExpression() : Expression(ET_Constant) {}
ConstantExpression(Constant * constantValue)5940b57cec5SDimitry Andric   ConstantExpression(Constant *constantValue)
5950b57cec5SDimitry Andric       : Expression(ET_Constant), ConstantValue(constantValue) {}
5960b57cec5SDimitry Andric   ConstantExpression(const ConstantExpression &) = delete;
5970b57cec5SDimitry Andric   ConstantExpression &operator=(const ConstantExpression &) = delete;
5980b57cec5SDimitry Andric 
classof(const Expression * EB)5990b57cec5SDimitry Andric   static bool classof(const Expression *EB) {
6000b57cec5SDimitry Andric     return EB->getExpressionType() == ET_Constant;
6010b57cec5SDimitry Andric   }
6020b57cec5SDimitry Andric 
getConstantValue()6030b57cec5SDimitry Andric   Constant *getConstantValue() const { return ConstantValue; }
setConstantValue(Constant * V)6040b57cec5SDimitry Andric   void setConstantValue(Constant *V) { ConstantValue = V; }
6050b57cec5SDimitry Andric 
equals(const Expression & Other)6060b57cec5SDimitry Andric   bool equals(const Expression &Other) const override {
6070b57cec5SDimitry Andric     const ConstantExpression &OC = cast<ConstantExpression>(Other);
6080b57cec5SDimitry Andric     return ConstantValue == OC.ConstantValue;
6090b57cec5SDimitry Andric   }
6100b57cec5SDimitry Andric 
getHashValue()6110b57cec5SDimitry Andric   hash_code getHashValue() const override {
6120b57cec5SDimitry Andric     return hash_combine(this->Expression::getHashValue(),
6130b57cec5SDimitry Andric                         ConstantValue->getType(), ConstantValue);
6140b57cec5SDimitry Andric   }
6150b57cec5SDimitry Andric 
6160b57cec5SDimitry Andric   // Debugging support
printInternal(raw_ostream & OS,bool PrintEType)6170b57cec5SDimitry Andric   void printInternal(raw_ostream &OS, bool PrintEType) const override {
6180b57cec5SDimitry Andric     if (PrintEType)
6190b57cec5SDimitry Andric       OS << "ExpressionTypeConstant, ";
6200b57cec5SDimitry Andric     this->Expression::printInternal(OS, false);
6210b57cec5SDimitry Andric     OS << " constant = " << *ConstantValue;
6220b57cec5SDimitry Andric   }
6230b57cec5SDimitry Andric };
6240b57cec5SDimitry Andric 
6250b57cec5SDimitry Andric class UnknownExpression final : public Expression {
6260b57cec5SDimitry Andric private:
6270b57cec5SDimitry Andric   Instruction *Inst;
6280b57cec5SDimitry Andric 
6290b57cec5SDimitry Andric public:
UnknownExpression(Instruction * I)6300b57cec5SDimitry Andric   UnknownExpression(Instruction *I) : Expression(ET_Unknown), Inst(I) {}
6310b57cec5SDimitry Andric   UnknownExpression() = delete;
6320b57cec5SDimitry Andric   UnknownExpression(const UnknownExpression &) = delete;
6330b57cec5SDimitry Andric   UnknownExpression &operator=(const UnknownExpression &) = delete;
6340b57cec5SDimitry Andric 
classof(const Expression * EB)6350b57cec5SDimitry Andric   static bool classof(const Expression *EB) {
6360b57cec5SDimitry Andric     return EB->getExpressionType() == ET_Unknown;
6370b57cec5SDimitry Andric   }
6380b57cec5SDimitry Andric 
getInstruction()6390b57cec5SDimitry Andric   Instruction *getInstruction() const { return Inst; }
setInstruction(Instruction * I)6400b57cec5SDimitry Andric   void setInstruction(Instruction *I) { Inst = I; }
6410b57cec5SDimitry Andric 
equals(const Expression & Other)6420b57cec5SDimitry Andric   bool equals(const Expression &Other) const override {
6430b57cec5SDimitry Andric     const auto &OU = cast<UnknownExpression>(Other);
6440b57cec5SDimitry Andric     return Inst == OU.Inst;
6450b57cec5SDimitry Andric   }
6460b57cec5SDimitry Andric 
getHashValue()6470b57cec5SDimitry Andric   hash_code getHashValue() const override {
6480b57cec5SDimitry Andric     return hash_combine(this->Expression::getHashValue(), Inst);
6490b57cec5SDimitry Andric   }
6500b57cec5SDimitry Andric 
6510b57cec5SDimitry Andric   // Debugging support
printInternal(raw_ostream & OS,bool PrintEType)6520b57cec5SDimitry Andric   void printInternal(raw_ostream &OS, bool PrintEType) const override {
6530b57cec5SDimitry Andric     if (PrintEType)
6540b57cec5SDimitry Andric       OS << "ExpressionTypeUnknown, ";
6550b57cec5SDimitry Andric     this->Expression::printInternal(OS, false);
6560b57cec5SDimitry Andric     OS << " inst = " << *Inst;
6570b57cec5SDimitry Andric   }
6580b57cec5SDimitry Andric };
6590b57cec5SDimitry Andric 
6600b57cec5SDimitry Andric } // end namespace GVNExpression
6610b57cec5SDimitry Andric 
6620b57cec5SDimitry Andric } // end namespace llvm
6630b57cec5SDimitry Andric 
6640b57cec5SDimitry Andric #endif // LLVM_TRANSFORMS_SCALAR_GVNEXPRESSION_H
665