You've already forked linux-packaging-mono
							
							
		
			
	
	
		
			319 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			319 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | //===- X86InstrFMA3Info.h - X86 FMA3 Instruction Information ----*- C++ -*-===//
 | ||
|  | //
 | ||
|  | //                     The LLVM Compiler Infrastructure
 | ||
|  | //
 | ||
|  | // This file is distributed under the University of Illinois Open Source
 | ||
|  | // License. See LICENSE.TXT for details.
 | ||
|  | //
 | ||
|  | //===----------------------------------------------------------------------===//
 | ||
|  | //
 | ||
|  | // This file contains the implementation of the classes providing information
 | ||
|  | // about existing X86 FMA3 opcodes, classifying and grouping them.
 | ||
|  | //
 | ||
|  | //===----------------------------------------------------------------------===//
 | ||
|  | 
 | ||
|  | #ifndef LLVM_LIB_TARGET_X86_UTILS_X86INSTRFMA3INFO_H
 | ||
|  | #define LLVM_LIB_TARGET_X86_UTILS_X86INSTRFMA3INFO_H
 | ||
|  | 
 | ||
|  | #include "X86.h"
 | ||
|  | #include "llvm/ADT/DenseMap.h"
 | ||
|  | #include <cassert>
 | ||
|  | #include <cstdint>
 | ||
|  | #include <set>
 | ||
|  | 
 | ||
|  | namespace llvm { | ||
|  | 
 | ||
|  | /// This class is used to group {132, 213, 231} forms of FMA opcodes together.
 | ||
|  | /// Each of the groups has either 3 register opcodes, 3 memory opcodes,
 | ||
|  | /// or 6 register and memory opcodes. Also, each group has an attrubutes field
 | ||
|  | /// describing it.
 | ||
|  | class X86InstrFMA3Group { | ||
|  | private: | ||
|  |   /// Reference to an array holding 3 forms of register FMA opcodes.
 | ||
|  |   /// It may be set to nullptr if the group of FMA opcodes does not have
 | ||
|  |   /// any register form opcodes.
 | ||
|  |   const uint16_t *RegOpcodes; | ||
|  | 
 | ||
|  |   /// Reference to an array holding 3 forms of memory FMA opcodes.
 | ||
|  |   /// It may be set to nullptr if the group of FMA opcodes does not have
 | ||
|  |   /// any register form opcodes.
 | ||
|  |   const uint16_t *MemOpcodes; | ||
|  | 
 | ||
|  |   /// This bitfield specifies the attributes associated with the created
 | ||
|  |   /// FMA groups of opcodes.
 | ||
|  |   unsigned Attributes; | ||
|  | 
 | ||
|  |   static const unsigned Form132 = 0; | ||
|  |   static const unsigned Form213 = 1; | ||
|  |   static const unsigned Form231 = 2; | ||
|  | 
 | ||
|  | public: | ||
|  |   /// This bit must be set in the 'Attributes' field of FMA group if such
 | ||
|  |   /// group of FMA opcodes consists of FMA intrinsic opcodes.
 | ||
|  |   static const unsigned X86FMA3Intrinsic = 0x1; | ||
|  | 
 | ||
|  |   /// This bit must be set in the 'Attributes' field of FMA group if such
 | ||
|  |   /// group of FMA opcodes consists of AVX512 opcodes accepting a k-mask and
 | ||
|  |   /// passing the elements from the 1st operand to the result of the operation
 | ||
|  |   /// when the correpondings bits in the k-mask are unset.
 | ||
|  |   static const unsigned X86FMA3KMergeMasked = 0x2; | ||
|  | 
 | ||
|  |   /// This bit must be set in the 'Attributes' field of FMA group if such
 | ||
|  |   /// group of FMA opcodes consists of AVX512 opcodes accepting a k-zeromask.
 | ||
|  |   static const unsigned X86FMA3KZeroMasked = 0x4; | ||
|  | 
 | ||
|  |   /// Constructor. Creates a new group of FMA opcodes with three register form
 | ||
|  |   /// FMA opcodes \p RegOpcodes and three memory form FMA opcodes \p MemOpcodes.
 | ||
|  |   /// The parameters \p RegOpcodes and \p MemOpcodes may be set to nullptr,
 | ||
|  |   /// which means that the created group of FMA opcodes does not have the
 | ||
|  |   /// corresponding (register or memory) opcodes.
 | ||
|  |   /// The parameter \p Attr specifies the attributes describing the created
 | ||
|  |   /// group.
 | ||
|  |   X86InstrFMA3Group(const uint16_t *RegOpcodes, const uint16_t *MemOpcodes, | ||
|  |                     unsigned Attr) | ||
|  |       : RegOpcodes(RegOpcodes), MemOpcodes(MemOpcodes), Attributes(Attr) { | ||
|  |     assert((RegOpcodes || MemOpcodes) && | ||
|  |            "Cannot create a group not having any opcodes."); | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Returns a memory form opcode that is the equivalent of the given register
 | ||
|  |   /// form opcode \p RegOpcode. 0 is returned if the group does not have
 | ||
|  |   /// either register of memory opcodes.
 | ||
|  |   unsigned getMemOpcode(unsigned RegOpcode) const { | ||
|  |     if (!RegOpcodes || !MemOpcodes) | ||
|  |       return 0; | ||
|  |     for (unsigned Form = 0; Form < 3; Form++) | ||
|  |       if (RegOpcodes[Form] == RegOpcode) | ||
|  |         return MemOpcodes[Form]; | ||
|  |     return 0; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Returns the 132 form of FMA register opcode.
 | ||
|  |   unsigned getReg132Opcode() const { | ||
|  |     assert(RegOpcodes && "The group does not have register opcodes."); | ||
|  |     return RegOpcodes[Form132]; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Returns the 213 form of FMA register opcode.
 | ||
|  |   unsigned getReg213Opcode() const { | ||
|  |     assert(RegOpcodes && "The group does not have register opcodes."); | ||
|  |     return RegOpcodes[Form213]; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Returns the 231 form of FMA register opcode.
 | ||
|  |   unsigned getReg231Opcode() const { | ||
|  |     assert(RegOpcodes && "The group does not have register opcodes."); | ||
|  |     return RegOpcodes[Form231]; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Returns the 132 form of FMA memory opcode.
 | ||
|  |   unsigned getMem132Opcode() const { | ||
|  |     assert(MemOpcodes && "The group does not have memory opcodes."); | ||
|  |     return MemOpcodes[Form132]; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Returns the 213 form of FMA memory opcode.
 | ||
|  |   unsigned getMem213Opcode() const { | ||
|  |     assert(MemOpcodes && "The group does not have memory opcodes."); | ||
|  |     return MemOpcodes[Form213]; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Returns the 231 form of FMA memory opcode.
 | ||
|  |   unsigned getMem231Opcode() const { | ||
|  |     assert(MemOpcodes && "The group does not have memory opcodes."); | ||
|  |     return MemOpcodes[Form231]; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Returns true iff the group of FMA opcodes holds intrinsic opcodes.
 | ||
|  |   bool isIntrinsic() const { return (Attributes & X86FMA3Intrinsic) != 0; } | ||
|  | 
 | ||
|  |   /// Returns true iff the group of FMA opcodes holds k-merge-masked opcodes.
 | ||
|  |   bool isKMergeMasked() const { | ||
|  |     return (Attributes & X86FMA3KMergeMasked) != 0; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Returns true iff the group of FMA opcodes holds k-zero-masked opcodes.
 | ||
|  |   bool isKZeroMasked() const { return (Attributes & X86FMA3KZeroMasked) != 0; } | ||
|  | 
 | ||
|  |   /// Returns true iff the group of FMA opcodes holds any of k-masked opcodes.
 | ||
|  |   bool isKMasked() const { | ||
|  |     return (Attributes & (X86FMA3KMergeMasked | X86FMA3KZeroMasked)) != 0; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Returns true iff the given \p Opcode is a register opcode from the
 | ||
|  |   /// groups of FMA opcodes.
 | ||
|  |   bool isRegOpcodeFromGroup(unsigned Opcode) const { | ||
|  |     if (!RegOpcodes) | ||
|  |       return false; | ||
|  |     for (unsigned Form = 0; Form < 3; Form++) | ||
|  |       if (Opcode == RegOpcodes[Form]) | ||
|  |         return true; | ||
|  |     return false; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Returns true iff the given \p Opcode is a memory opcode from the
 | ||
|  |   /// groups of FMA opcodes.
 | ||
|  |   bool isMemOpcodeFromGroup(unsigned Opcode) const { | ||
|  |     if (!MemOpcodes) | ||
|  |       return false; | ||
|  |     for (unsigned Form = 0; Form < 3; Form++) | ||
|  |       if (Opcode == MemOpcodes[Form]) | ||
|  |         return true; | ||
|  |     return false; | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | /// This class provides information about all existing FMA3 opcodes
 | ||
|  | ///
 | ||
|  | class X86InstrFMA3Info { | ||
|  | private: | ||
|  |   /// A map that is used to find the group of FMA opcodes using any FMA opcode
 | ||
|  |   /// from the group.
 | ||
|  |   DenseMap<unsigned, const X86InstrFMA3Group *> OpcodeToGroup; | ||
|  | 
 | ||
|  |   /// Creates groups of FMA opcodes and initializes Opcode-to-Group map.
 | ||
|  |   /// This method can be called many times, but the actual initialization is
 | ||
|  |   /// called only once.
 | ||
|  |   static void initGroupsOnce(); | ||
|  | 
 | ||
|  |   /// Creates groups of FMA opcodes and initializes Opcode-to-Group map.
 | ||
|  |   /// This method must be called ONLY from initGroupsOnce(). Otherwise, such
 | ||
|  |   /// call is not thread safe.
 | ||
|  |   void initGroupsOnceImpl(); | ||
|  | 
 | ||
|  |   /// Creates one group of FMA opcodes having the register opcodes
 | ||
|  |   /// \p RegOpcodes and memory opcodes \p MemOpcodes. The parameter \p Attr
 | ||
|  |   /// specifies the attributes describing the created group.
 | ||
|  |   void initRMGroup(const uint16_t *RegOpcodes, | ||
|  |                    const uint16_t *MemOpcodes, unsigned Attr = 0); | ||
|  | 
 | ||
|  |   /// Creates one group of FMA opcodes having only the register opcodes
 | ||
|  |   /// \p RegOpcodes. The parameter \p Attr specifies the attributes describing
 | ||
|  |   /// the created group.
 | ||
|  |   void initRGroup(const uint16_t *RegOpcodes, unsigned Attr = 0); | ||
|  | 
 | ||
|  |   /// Creates one group of FMA opcodes having only the memory opcodes
 | ||
|  |   /// \p MemOpcodes. The parameter \p Attr specifies the attributes describing
 | ||
|  |   /// the created group.
 | ||
|  |   void initMGroup(const uint16_t *MemOpcodes, unsigned Attr = 0); | ||
|  | 
 | ||
|  | public: | ||
|  |   /// Returns the reference to an object of this class. It is assumed that
 | ||
|  |   /// only one object may exist.
 | ||
|  |   static X86InstrFMA3Info *getX86InstrFMA3Info(); | ||
|  | 
 | ||
|  |   /// Constructor. Just creates an object of the class.
 | ||
|  |   X86InstrFMA3Info() = default; | ||
|  | 
 | ||
|  |   /// Destructor. Deallocates the memory used for FMA3 Groups.
 | ||
|  |   ~X86InstrFMA3Info() { | ||
|  |     std::set<const X86InstrFMA3Group *> DeletedGroups; | ||
|  |     auto E = OpcodeToGroup.end(); | ||
|  |     for (auto I = OpcodeToGroup.begin(); I != E; I++) { | ||
|  |       const X86InstrFMA3Group *G = I->second; | ||
|  |       if (DeletedGroups.find(G) == DeletedGroups.end()) { | ||
|  |         DeletedGroups.insert(G); | ||
|  |         delete G; | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Returns a reference to a group of FMA3 opcodes to where the given
 | ||
|  |   /// \p Opcode is included. If the given \p Opcode is not recognized as FMA3
 | ||
|  |   /// and not included into any FMA3 group, then nullptr is returned.
 | ||
|  |   static const X86InstrFMA3Group *getFMA3Group(unsigned Opcode) { | ||
|  |     // Ensure that the groups of opcodes are initialized.
 | ||
|  |     initGroupsOnce(); | ||
|  | 
 | ||
|  |     // Find the group including the given opcode.
 | ||
|  |     const X86InstrFMA3Info *FMA3Info = getX86InstrFMA3Info(); | ||
|  |     auto I = FMA3Info->OpcodeToGroup.find(Opcode); | ||
|  |     if (I == FMA3Info->OpcodeToGroup.end()) | ||
|  |       return nullptr; | ||
|  | 
 | ||
|  |     return I->second; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Returns true iff the given \p Opcode is recognized as FMA3 by this class.
 | ||
|  |   static bool isFMA3(unsigned Opcode) { | ||
|  |     return getFMA3Group(Opcode) != nullptr; | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Iterator that is used to walk on FMA register opcodes having memory
 | ||
|  |   /// form equivalents.
 | ||
|  |   class rm_iterator { | ||
|  |   private: | ||
|  |     /// Iterator associated with the OpcodeToGroup map. It must always be
 | ||
|  |     /// initialized with an entry from OpcodeToGroup for which I->first
 | ||
|  |     /// points to a register FMA opcode and I->second points to a group of
 | ||
|  |     /// FMA opcodes having memory form equivalent of I->first.
 | ||
|  |     DenseMap<unsigned, const X86InstrFMA3Group *>::const_iterator I; | ||
|  | 
 | ||
|  |   public: | ||
|  |     /// Constructor. Creates rm_iterator. The parameter \p I must be an
 | ||
|  |     /// iterator to OpcodeToGroup map entry having I->first pointing to
 | ||
|  |     /// register form FMA opcode and I->second pointing to a group of FMA
 | ||
|  |     /// opcodes holding memory form equivalent for I->fist.
 | ||
|  |     rm_iterator(DenseMap<unsigned, const X86InstrFMA3Group *>::const_iterator I) | ||
|  |         : I(I) {} | ||
|  | 
 | ||
|  |     /// Returns the register form FMA opcode.
 | ||
|  |     unsigned getRegOpcode() const { return I->first; }; | ||
|  | 
 | ||
|  |     /// Returns the memory form equivalent opcode for FMA register opcode
 | ||
|  |     /// referenced by I->first.
 | ||
|  |     unsigned getMemOpcode() const { | ||
|  |       unsigned Opcode = I->first; | ||
|  |       const X86InstrFMA3Group *Group = I->second; | ||
|  |       return Group->getMemOpcode(Opcode); | ||
|  |     } | ||
|  | 
 | ||
|  |     /// Returns a reference to a group of FMA opcodes.
 | ||
|  |     const X86InstrFMA3Group *getGroup() const { return I->second; } | ||
|  | 
 | ||
|  |     bool operator==(const rm_iterator &OtherIt) const { return I == OtherIt.I; } | ||
|  |     bool operator!=(const rm_iterator &OtherIt) const { return I != OtherIt.I; } | ||
|  | 
 | ||
|  |     /// Increment. Advances the 'I' iterator to the next OpcodeToGroup entry
 | ||
|  |     /// having I->first pointing to register form FMA and I->second pointing
 | ||
|  |     /// to a group of FMA opcodes holding memory form equivalen for I->first.
 | ||
|  |     rm_iterator &operator++() { | ||
|  |       auto E = getX86InstrFMA3Info()->OpcodeToGroup.end(); | ||
|  |       for (++I; I != E; ++I) { | ||
|  |         unsigned RegOpcode = I->first; | ||
|  |         const X86InstrFMA3Group *Group = I->second; | ||
|  |         if (Group->getMemOpcode(RegOpcode) != 0) | ||
|  |           break; | ||
|  |       } | ||
|  |       return *this; | ||
|  |     } | ||
|  |   }; | ||
|  | 
 | ||
|  |   /// Returns rm_iterator pointing to the first entry of OpcodeToGroup map
 | ||
|  |   /// with a register FMA opcode having memory form opcode equivalent.
 | ||
|  |   static rm_iterator rm_begin() { | ||
|  |     initGroupsOnce(); | ||
|  |     const X86InstrFMA3Info *FMA3Info = getX86InstrFMA3Info(); | ||
|  |     auto I = FMA3Info->OpcodeToGroup.begin(); | ||
|  |     auto E = FMA3Info->OpcodeToGroup.end(); | ||
|  |     while (I != E) { | ||
|  |       unsigned Opcode = I->first; | ||
|  |       const X86InstrFMA3Group *G = I->second; | ||
|  |       if (G->getMemOpcode(Opcode) != 0) | ||
|  |         break; | ||
|  |       I++; | ||
|  |     } | ||
|  |     return rm_iterator(I); | ||
|  |   } | ||
|  | 
 | ||
|  |   /// Returns the last rm_iterator.
 | ||
|  |   static rm_iterator rm_end() { | ||
|  |     initGroupsOnce(); | ||
|  |     return rm_iterator(getX86InstrFMA3Info()->OpcodeToGroup.end()); | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | } // end namespace llvm
 | ||
|  | 
 | ||
|  | #endif // LLVM_LIB_TARGET_X86_UTILS_X86INSTRFMA3INFO_H
 |