Index: projects/clang380-import/contrib/llvm/include/llvm/CodeGen/LiveInterval.h =================================================================== --- projects/clang380-import/contrib/llvm/include/llvm/CodeGen/LiveInterval.h (revision 295858) +++ projects/clang380-import/contrib/llvm/include/llvm/CodeGen/LiveInterval.h (revision 295859) @@ -1,868 +1,873 @@ //===-- llvm/CodeGen/LiveInterval.h - Interval representation ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the LiveRange and LiveInterval classes. Given some // numbering of each the machine instructions an interval [i, j) is said to be a // live range for register v if there is no instruction with number j' >= j // such that v is live at j' and there is no instruction with number i' < i such // that v is live at i'. In this implementation ranges can have holes, // i.e. a range might look like [1,20), [50,65), [1000,1001). Each // individual segment is represented as an instance of LiveRange::Segment, // and the whole range is represented as an instance of LiveRange. // //===----------------------------------------------------------------------===// #ifndef LLVM_CODEGEN_LIVEINTERVAL_H #define LLVM_CODEGEN_LIVEINTERVAL_H #include "llvm/ADT/IntEqClasses.h" #include "llvm/CodeGen/SlotIndexes.h" #include "llvm/Support/AlignOf.h" #include "llvm/Support/Allocator.h" #include "llvm/Target/TargetRegisterInfo.h" #include #include #include namespace llvm { class CoalescerPair; class LiveIntervals; class MachineInstr; class MachineRegisterInfo; class TargetRegisterInfo; class raw_ostream; template class SmallPtrSet; /// VNInfo - Value Number Information. /// This class holds information about a machine level values, including /// definition and use points. /// class VNInfo { public: typedef BumpPtrAllocator Allocator; /// The ID number of this value. unsigned id; /// The index of the defining instruction. SlotIndex def; /// VNInfo constructor. VNInfo(unsigned i, SlotIndex d) : id(i), def(d) { } /// VNInfo construtor, copies values from orig, except for the value number. VNInfo(unsigned i, const VNInfo &orig) : id(i), def(orig.def) { } /// Copy from the parameter into this VNInfo. void copyFrom(VNInfo &src) { def = src.def; } /// Returns true if this value is defined by a PHI instruction (or was, /// PHI instructions may have been eliminated). /// PHI-defs begin at a block boundary, all other defs begin at register or /// EC slots. bool isPHIDef() const { return def.isBlock(); } /// Returns true if this value is unused. bool isUnused() const { return !def.isValid(); } /// Mark this value as unused. void markUnused() { def = SlotIndex(); } }; /// Result of a LiveRange query. This class hides the implementation details /// of live ranges, and it should be used as the primary interface for /// examining live ranges around instructions. class LiveQueryResult { VNInfo *const EarlyVal; VNInfo *const LateVal; const SlotIndex EndPoint; const bool Kill; public: LiveQueryResult(VNInfo *EarlyVal, VNInfo *LateVal, SlotIndex EndPoint, bool Kill) : EarlyVal(EarlyVal), LateVal(LateVal), EndPoint(EndPoint), Kill(Kill) {} /// Return the value that is live-in to the instruction. This is the value /// that will be read by the instruction's use operands. Return NULL if no /// value is live-in. VNInfo *valueIn() const { return EarlyVal; } /// Return true if the live-in value is killed by this instruction. This /// means that either the live range ends at the instruction, or it changes /// value. bool isKill() const { return Kill; } /// Return true if this instruction has a dead def. bool isDeadDef() const { return EndPoint.isDead(); } /// Return the value leaving the instruction, if any. This can be a /// live-through value, or a live def. A dead def returns NULL. VNInfo *valueOut() const { return isDeadDef() ? nullptr : LateVal; } /// Returns the value alive at the end of the instruction, if any. This can /// be a live-through value, a live def or a dead def. VNInfo *valueOutOrDead() const { return LateVal; } /// Return the value defined by this instruction, if any. This includes /// dead defs, it is the value created by the instruction's def operands. VNInfo *valueDefined() const { return EarlyVal == LateVal ? nullptr : LateVal; } /// Return the end point of the last live range segment to interact with /// the instruction, if any. /// /// The end point is an invalid SlotIndex only if the live range doesn't /// intersect the instruction at all. /// /// The end point may be at or past the end of the instruction's basic /// block. That means the value was live out of the block. SlotIndex endPoint() const { return EndPoint; } }; /// This class represents the liveness of a register, stack slot, etc. /// It manages an ordered list of Segment objects. /// The Segments are organized in a static single assignment form: At places /// where a new value is defined or different values reach a CFG join a new /// segment with a new value number is used. class LiveRange { public: /// This represents a simple continuous liveness interval for a value. /// The start point is inclusive, the end point exclusive. These intervals /// are rendered as [start,end). struct Segment { SlotIndex start; // Start point of the interval (inclusive) SlotIndex end; // End point of the interval (exclusive) VNInfo *valno; // identifier for the value contained in this segment. Segment() : valno(nullptr) {} Segment(SlotIndex S, SlotIndex E, VNInfo *V) : start(S), end(E), valno(V) { assert(S < E && "Cannot create empty or backwards segment"); } /// Return true if the index is covered by this segment. bool contains(SlotIndex I) const { return start <= I && I < end; } /// Return true if the given interval, [S, E), is covered by this segment. bool containsInterval(SlotIndex S, SlotIndex E) const { assert((S < E) && "Backwards interval?"); return (start <= S && S < end) && (start < E && E <= end); } bool operator<(const Segment &Other) const { return std::tie(start, end) < std::tie(Other.start, Other.end); } bool operator==(const Segment &Other) const { return start == Other.start && end == Other.end; } void dump() const; }; typedef SmallVector Segments; typedef SmallVector VNInfoList; Segments segments; // the liveness segments VNInfoList valnos; // value#'s // The segment set is used temporarily to accelerate initial computation // of live ranges of physical registers in computeRegUnitRange. // After that the set is flushed to the segment vector and deleted. typedef std::set SegmentSet; std::unique_ptr segmentSet; typedef Segments::iterator iterator; iterator begin() { return segments.begin(); } iterator end() { return segments.end(); } typedef Segments::const_iterator const_iterator; const_iterator begin() const { return segments.begin(); } const_iterator end() const { return segments.end(); } typedef VNInfoList::iterator vni_iterator; vni_iterator vni_begin() { return valnos.begin(); } vni_iterator vni_end() { return valnos.end(); } typedef VNInfoList::const_iterator const_vni_iterator; const_vni_iterator vni_begin() const { return valnos.begin(); } const_vni_iterator vni_end() const { return valnos.end(); } /// Constructs a new LiveRange object. LiveRange(bool UseSegmentSet = false) : segmentSet(UseSegmentSet ? llvm::make_unique() : nullptr) {} /// Constructs a new LiveRange object by copying segments and valnos from /// another LiveRange. LiveRange(const LiveRange &Other, BumpPtrAllocator &Allocator) { assert(Other.segmentSet == nullptr && "Copying of LiveRanges with active SegmentSets is not supported"); // Duplicate valnos. for (const VNInfo *VNI : Other.valnos) { createValueCopy(VNI, Allocator); } // Now we can copy segments and remap their valnos. for (const Segment &S : Other.segments) { segments.push_back(Segment(S.start, S.end, valnos[S.valno->id])); } } /// advanceTo - Advance the specified iterator to point to the Segment /// containing the specified position, or end() if the position is past the /// end of the range. If no Segment contains this position, but the /// position is in a hole, this method returns an iterator pointing to the /// Segment immediately after the hole. iterator advanceTo(iterator I, SlotIndex Pos) { assert(I != end()); if (Pos >= endIndex()) return end(); while (I->end <= Pos) ++I; return I; } const_iterator advanceTo(const_iterator I, SlotIndex Pos) const { assert(I != end()); if (Pos >= endIndex()) return end(); while (I->end <= Pos) ++I; return I; } /// find - Return an iterator pointing to the first segment that ends after /// Pos, or end(). This is the same as advanceTo(begin(), Pos), but faster /// when searching large ranges. /// /// If Pos is contained in a Segment, that segment is returned. /// If Pos is in a hole, the following Segment is returned. /// If Pos is beyond endIndex, end() is returned. iterator find(SlotIndex Pos); const_iterator find(SlotIndex Pos) const { return const_cast(this)->find(Pos); } void clear() { valnos.clear(); segments.clear(); } size_t size() const { return segments.size(); } bool hasAtLeastOneValue() const { return !valnos.empty(); } bool containsOneValue() const { return valnos.size() == 1; } unsigned getNumValNums() const { return (unsigned)valnos.size(); } /// getValNumInfo - Returns pointer to the specified val#. /// inline VNInfo *getValNumInfo(unsigned ValNo) { return valnos[ValNo]; } inline const VNInfo *getValNumInfo(unsigned ValNo) const { return valnos[ValNo]; } /// containsValue - Returns true if VNI belongs to this range. bool containsValue(const VNInfo *VNI) const { return VNI && VNI->id < getNumValNums() && VNI == getValNumInfo(VNI->id); } /// getNextValue - Create a new value number and return it. MIIdx specifies /// the instruction that defines the value number. VNInfo *getNextValue(SlotIndex def, VNInfo::Allocator &VNInfoAllocator) { VNInfo *VNI = new (VNInfoAllocator) VNInfo((unsigned)valnos.size(), def); valnos.push_back(VNI); return VNI; } /// createDeadDef - Make sure the range has a value defined at Def. /// If one already exists, return it. Otherwise allocate a new value and /// add liveness for a dead def. VNInfo *createDeadDef(SlotIndex Def, VNInfo::Allocator &VNInfoAllocator); /// Create a copy of the given value. The new value will be identical except /// for the Value number. VNInfo *createValueCopy(const VNInfo *orig, VNInfo::Allocator &VNInfoAllocator) { VNInfo *VNI = new (VNInfoAllocator) VNInfo((unsigned)valnos.size(), *orig); valnos.push_back(VNI); return VNI; } /// RenumberValues - Renumber all values in order of appearance and remove /// unused values. void RenumberValues(); /// MergeValueNumberInto - This method is called when two value numbers /// are found to be equivalent. This eliminates V1, replacing all /// segments with the V1 value number with the V2 value number. This can /// cause merging of V1/V2 values numbers and compaction of the value space. VNInfo* MergeValueNumberInto(VNInfo *V1, VNInfo *V2); /// Merge all of the live segments of a specific val# in RHS into this live /// range as the specified value number. The segments in RHS are allowed /// to overlap with segments in the current range, it will replace the /// value numbers of the overlaped live segments with the specified value /// number. void MergeSegmentsInAsValue(const LiveRange &RHS, VNInfo *LHSValNo); /// MergeValueInAsValue - Merge all of the segments of a specific val# /// in RHS into this live range as the specified value number. /// The segments in RHS are allowed to overlap with segments in the /// current range, but only if the overlapping segments have the /// specified value number. void MergeValueInAsValue(const LiveRange &RHS, const VNInfo *RHSValNo, VNInfo *LHSValNo); bool empty() const { return segments.empty(); } /// beginIndex - Return the lowest numbered slot covered. SlotIndex beginIndex() const { assert(!empty() && "Call to beginIndex() on empty range."); return segments.front().start; } /// endNumber - return the maximum point of the range of the whole, /// exclusive. SlotIndex endIndex() const { assert(!empty() && "Call to endIndex() on empty range."); return segments.back().end; } bool expiredAt(SlotIndex index) const { return index >= endIndex(); } bool liveAt(SlotIndex index) const { const_iterator r = find(index); return r != end() && r->start <= index; } /// Return the segment that contains the specified index, or null if there /// is none. const Segment *getSegmentContaining(SlotIndex Idx) const { const_iterator I = FindSegmentContaining(Idx); return I == end() ? nullptr : &*I; } /// Return the live segment that contains the specified index, or null if /// there is none. Segment *getSegmentContaining(SlotIndex Idx) { iterator I = FindSegmentContaining(Idx); return I == end() ? nullptr : &*I; } /// getVNInfoAt - Return the VNInfo that is live at Idx, or NULL. VNInfo *getVNInfoAt(SlotIndex Idx) const { const_iterator I = FindSegmentContaining(Idx); return I == end() ? nullptr : I->valno; } /// getVNInfoBefore - Return the VNInfo that is live up to but not /// necessarilly including Idx, or NULL. Use this to find the reaching def /// used by an instruction at this SlotIndex position. VNInfo *getVNInfoBefore(SlotIndex Idx) const { const_iterator I = FindSegmentContaining(Idx.getPrevSlot()); return I == end() ? nullptr : I->valno; } /// Return an iterator to the segment that contains the specified index, or /// end() if there is none. iterator FindSegmentContaining(SlotIndex Idx) { iterator I = find(Idx); return I != end() && I->start <= Idx ? I : end(); } const_iterator FindSegmentContaining(SlotIndex Idx) const { const_iterator I = find(Idx); return I != end() && I->start <= Idx ? I : end(); } /// overlaps - Return true if the intersection of the two live ranges is /// not empty. bool overlaps(const LiveRange &other) const { if (other.empty()) return false; return overlapsFrom(other, other.begin()); } /// overlaps - Return true if the two ranges have overlapping segments /// that are not coalescable according to CP. /// /// Overlapping segments where one range is defined by a coalescable /// copy are allowed. bool overlaps(const LiveRange &Other, const CoalescerPair &CP, const SlotIndexes&) const; /// overlaps - Return true if the live range overlaps an interval specified /// by [Start, End). bool overlaps(SlotIndex Start, SlotIndex End) const; /// overlapsFrom - Return true if the intersection of the two live ranges /// is not empty. The specified iterator is a hint that we can begin /// scanning the Other range starting at I. bool overlapsFrom(const LiveRange &Other, const_iterator I) const; /// Returns true if all segments of the @p Other live range are completely /// covered by this live range. /// Adjacent live ranges do not affect the covering:the liverange /// [1,5](5,10] covers (3,7]. bool covers(const LiveRange &Other) const; /// Add the specified Segment to this range, merging segments as /// appropriate. This returns an iterator to the inserted segment (which /// may have grown since it was inserted). iterator addSegment(Segment S); /// If this range is live before @p Use in the basic block that starts at /// @p StartIdx, extend it to be live up to @p Use, and return the value. If /// there is no segment before @p Use, return nullptr. VNInfo *extendInBlock(SlotIndex StartIdx, SlotIndex Use); /// join - Join two live ranges (this, and other) together. This applies /// mappings to the value numbers in the LHS/RHS ranges as specified. If /// the ranges are not joinable, this aborts. void join(LiveRange &Other, const int *ValNoAssignments, const int *RHSValNoAssignments, SmallVectorImpl &NewVNInfo); /// True iff this segment is a single segment that lies between the /// specified boundaries, exclusively. Vregs live across a backedge are not /// considered local. The boundaries are expected to lie within an extended /// basic block, so vregs that are not live out should contain no holes. bool isLocal(SlotIndex Start, SlotIndex End) const { return beginIndex() > Start.getBaseIndex() && endIndex() < End.getBoundaryIndex(); } /// Remove the specified segment from this range. Note that the segment /// must be a single Segment in its entirety. void removeSegment(SlotIndex Start, SlotIndex End, bool RemoveDeadValNo = false); void removeSegment(Segment S, bool RemoveDeadValNo = false) { removeSegment(S.start, S.end, RemoveDeadValNo); } /// Remove segment pointed to by iterator @p I from this range. This does /// not remove dead value numbers. iterator removeSegment(iterator I) { return segments.erase(I); } /// Query Liveness at Idx. /// The sub-instruction slot of Idx doesn't matter, only the instruction /// it refers to is considered. LiveQueryResult Query(SlotIndex Idx) const { // Find the segment that enters the instruction. const_iterator I = find(Idx.getBaseIndex()); const_iterator E = end(); if (I == E) return LiveQueryResult(nullptr, nullptr, SlotIndex(), false); // Is this an instruction live-in segment? // If Idx is the start index of a basic block, include live-in segments // that start at Idx.getBaseIndex(). VNInfo *EarlyVal = nullptr; VNInfo *LateVal = nullptr; SlotIndex EndPoint; bool Kill = false; if (I->start <= Idx.getBaseIndex()) { EarlyVal = I->valno; EndPoint = I->end; // Move to the potentially live-out segment. if (SlotIndex::isSameInstr(Idx, I->end)) { Kill = true; if (++I == E) return LiveQueryResult(EarlyVal, LateVal, EndPoint, Kill); } // Special case: A PHIDef value can have its def in the middle of a // segment if the value happens to be live out of the layout // predecessor. // Such a value is not live-in. if (EarlyVal->def == Idx.getBaseIndex()) EarlyVal = nullptr; } // I now points to the segment that may be live-through, or defined by // this instr. Ignore segments starting after the current instr. if (!SlotIndex::isEarlierInstr(Idx, I->start)) { LateVal = I->valno; EndPoint = I->end; } return LiveQueryResult(EarlyVal, LateVal, EndPoint, Kill); } /// removeValNo - Remove all the segments defined by the specified value#. /// Also remove the value# from value# list. void removeValNo(VNInfo *ValNo); /// Returns true if the live range is zero length, i.e. no live segments /// span instructions. It doesn't pay to spill such a range. bool isZeroLength(SlotIndexes *Indexes) const { for (const Segment &S : segments) if (Indexes->getNextNonNullIndex(S.start).getBaseIndex() < S.end.getBaseIndex()) return false; return true; } + // Returns true if any segment in the live range contains any of the + // provided slot indexes. Slots which occur in holes between + // segments will not cause the function to return true. + bool isLiveAtIndexes(ArrayRef Slots) const; + bool operator<(const LiveRange& other) const { const SlotIndex &thisIndex = beginIndex(); const SlotIndex &otherIndex = other.beginIndex(); return thisIndex < otherIndex; } /// Flush segment set into the regular segment vector. /// The method is to be called after the live range /// has been created, if use of the segment set was /// activated in the constructor of the live range. void flushSegmentSet(); void print(raw_ostream &OS) const; void dump() const; /// \brief Walk the range and assert if any invariants fail to hold. /// /// Note that this is a no-op when asserts are disabled. #ifdef NDEBUG void verify() const {} #else void verify() const; #endif protected: /// Append a segment to the list of segments. void append(const LiveRange::Segment S); private: friend class LiveRangeUpdater; void addSegmentToSet(Segment S); void markValNoForDeletion(VNInfo *V); }; inline raw_ostream &operator<<(raw_ostream &OS, const LiveRange &LR) { LR.print(OS); return OS; } /// LiveInterval - This class represents the liveness of a register, /// or stack slot. class LiveInterval : public LiveRange { public: typedef LiveRange super; /// A live range for subregisters. The LaneMask specifies which parts of the /// super register are covered by the interval. /// (@sa TargetRegisterInfo::getSubRegIndexLaneMask()). class SubRange : public LiveRange { public: SubRange *Next; LaneBitmask LaneMask; /// Constructs a new SubRange object. SubRange(LaneBitmask LaneMask) : Next(nullptr), LaneMask(LaneMask) { } /// Constructs a new SubRange object by copying liveness from @p Other. SubRange(LaneBitmask LaneMask, const LiveRange &Other, BumpPtrAllocator &Allocator) : LiveRange(Other, Allocator), Next(nullptr), LaneMask(LaneMask) { } }; private: SubRange *SubRanges; ///< Single linked list of subregister live ranges. public: const unsigned reg; // the register or stack slot of this interval. float weight; // weight of this interval LiveInterval(unsigned Reg, float Weight) : SubRanges(nullptr), reg(Reg), weight(Weight) {} ~LiveInterval() { clearSubRanges(); } template class SingleLinkedListIterator { T *P; public: SingleLinkedListIterator(T *P) : P(P) {} SingleLinkedListIterator &operator++() { P = P->Next; return *this; } SingleLinkedListIterator &operator++(int) { SingleLinkedListIterator res = *this; ++*this; return res; } bool operator!=(const SingleLinkedListIterator &Other) { return P != Other.operator->(); } bool operator==(const SingleLinkedListIterator &Other) { return P == Other.operator->(); } T &operator*() const { return *P; } T *operator->() const { return P; } }; typedef SingleLinkedListIterator subrange_iterator; subrange_iterator subrange_begin() { return subrange_iterator(SubRanges); } subrange_iterator subrange_end() { return subrange_iterator(nullptr); } typedef SingleLinkedListIterator const_subrange_iterator; const_subrange_iterator subrange_begin() const { return const_subrange_iterator(SubRanges); } const_subrange_iterator subrange_end() const { return const_subrange_iterator(nullptr); } iterator_range subranges() { return make_range(subrange_begin(), subrange_end()); } iterator_range subranges() const { return make_range(subrange_begin(), subrange_end()); } /// Creates a new empty subregister live range. The range is added at the /// beginning of the subrange list; subrange iterators stay valid. SubRange *createSubRange(BumpPtrAllocator &Allocator, LaneBitmask LaneMask) { SubRange *Range = new (Allocator) SubRange(LaneMask); appendSubRange(Range); return Range; } /// Like createSubRange() but the new range is filled with a copy of the /// liveness information in @p CopyFrom. SubRange *createSubRangeFrom(BumpPtrAllocator &Allocator, LaneBitmask LaneMask, const LiveRange &CopyFrom) { SubRange *Range = new (Allocator) SubRange(LaneMask, CopyFrom, Allocator); appendSubRange(Range); return Range; } /// Returns true if subregister liveness information is available. bool hasSubRanges() const { return SubRanges != nullptr; } /// Removes all subregister liveness information. void clearSubRanges(); /// Removes all subranges without any segments (subranges without segments /// are not considered valid and should only exist temporarily). void removeEmptySubRanges(); /// Construct main live range by merging the SubRanges of @p LI. void constructMainRangeFromSubranges(const SlotIndexes &Indexes, VNInfo::Allocator &VNIAllocator); /// getSize - Returns the sum of sizes of all the LiveRange's. /// unsigned getSize() const; /// isSpillable - Can this interval be spilled? bool isSpillable() const { return weight != llvm::huge_valf; } /// markNotSpillable - Mark interval as not spillable void markNotSpillable() { weight = llvm::huge_valf; } bool operator<(const LiveInterval& other) const { const SlotIndex &thisIndex = beginIndex(); const SlotIndex &otherIndex = other.beginIndex(); return std::tie(thisIndex, reg) < std::tie(otherIndex, other.reg); } void print(raw_ostream &OS) const; void dump() const; /// \brief Walks the interval and assert if any invariants fail to hold. /// /// Note that this is a no-op when asserts are disabled. #ifdef NDEBUG void verify(const MachineRegisterInfo *MRI = nullptr) const {} #else void verify(const MachineRegisterInfo *MRI = nullptr) const; #endif private: /// Appends @p Range to SubRanges list. void appendSubRange(SubRange *Range) { Range->Next = SubRanges; SubRanges = Range; } /// Free memory held by SubRange. void freeSubRange(SubRange *S); }; inline raw_ostream &operator<<(raw_ostream &OS, const LiveInterval &LI) { LI.print(OS); return OS; } raw_ostream &operator<<(raw_ostream &OS, const LiveRange::Segment &S); inline bool operator<(SlotIndex V, const LiveRange::Segment &S) { return V < S.start; } inline bool operator<(const LiveRange::Segment &S, SlotIndex V) { return S.start < V; } /// Helper class for performant LiveRange bulk updates. /// /// Calling LiveRange::addSegment() repeatedly can be expensive on large /// live ranges because segments after the insertion point may need to be /// shifted. The LiveRangeUpdater class can defer the shifting when adding /// many segments in order. /// /// The LiveRange will be in an invalid state until flush() is called. class LiveRangeUpdater { LiveRange *LR; SlotIndex LastStart; LiveRange::iterator WriteI; LiveRange::iterator ReadI; SmallVector Spills; void mergeSpills(); public: /// Create a LiveRangeUpdater for adding segments to LR. /// LR will temporarily be in an invalid state until flush() is called. LiveRangeUpdater(LiveRange *lr = nullptr) : LR(lr) {} ~LiveRangeUpdater() { flush(); } /// Add a segment to LR and coalesce when possible, just like /// LR.addSegment(). Segments should be added in increasing start order for /// best performance. void add(LiveRange::Segment); void add(SlotIndex Start, SlotIndex End, VNInfo *VNI) { add(LiveRange::Segment(Start, End, VNI)); } /// Return true if the LR is currently in an invalid state, and flush() /// needs to be called. bool isDirty() const { return LastStart.isValid(); } /// Flush the updater state to LR so it is valid and contains all added /// segments. void flush(); /// Select a different destination live range. void setDest(LiveRange *lr) { if (LR != lr && isDirty()) flush(); LR = lr; } /// Get the current destination live range. LiveRange *getDest() const { return LR; } void dump() const; void print(raw_ostream&) const; }; inline raw_ostream &operator<<(raw_ostream &OS, const LiveRangeUpdater &X) { X.print(OS); return OS; } /// ConnectedVNInfoEqClasses - Helper class that can divide VNInfos in a /// LiveInterval into equivalence clases of connected components. A /// LiveInterval that has multiple connected components can be broken into /// multiple LiveIntervals. /// /// Given a LiveInterval that may have multiple connected components, run: /// /// unsigned numComps = ConEQ.Classify(LI); /// if (numComps > 1) { /// // allocate numComps-1 new LiveIntervals into LIS[1..] /// ConEQ.Distribute(LIS); /// } class ConnectedVNInfoEqClasses { LiveIntervals &LIS; IntEqClasses EqClass; public: explicit ConnectedVNInfoEqClasses(LiveIntervals &lis) : LIS(lis) {} /// Classify the values in \p LR into connected components. /// Returns the number of connected components. unsigned Classify(const LiveRange &LR); /// getEqClass - Classify creates equivalence classes numbered 0..N. Return /// the equivalence class assigned the VNI. unsigned getEqClass(const VNInfo *VNI) const { return EqClass[VNI->id]; } /// Distribute values in \p LI into a separate LiveIntervals /// for each connected component. LIV must have an empty LiveInterval for /// each additional connected component. The first connected component is /// left in \p LI. void Distribute(LiveInterval &LI, LiveInterval *LIV[], MachineRegisterInfo &MRI); }; } #endif Index: projects/clang380-import/contrib/llvm/include/llvm/IR/IRBuilder.h =================================================================== --- projects/clang380-import/contrib/llvm/include/llvm/IR/IRBuilder.h (revision 295858) +++ projects/clang380-import/contrib/llvm/include/llvm/IR/IRBuilder.h (revision 295859) @@ -1,1796 +1,1796 @@ //===---- llvm/IRBuilder.h - Builder for LLVM Instructions ------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the IRBuilder class, which is used as a convenient way // to create LLVM instructions with a consistent and simplified interface. // //===----------------------------------------------------------------------===// #ifndef LLVM_IR_IRBUILDER_H #define LLVM_IR_IRBUILDER_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/ConstantFolder.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Operator.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/CBindingWrapping.h" namespace llvm { class MDNode; /// \brief This provides the default implementation of the IRBuilder /// 'InsertHelper' method that is called whenever an instruction is created by /// IRBuilder and needs to be inserted. /// /// By default, this inserts the instruction at the insertion point. template class IRBuilderDefaultInserter { protected: void InsertHelper(Instruction *I, const Twine &Name, BasicBlock *BB, BasicBlock::iterator InsertPt) const { if (BB) BB->getInstList().insert(InsertPt, I); if (preserveNames) I->setName(Name); } }; /// \brief Common base class shared among various IRBuilders. class IRBuilderBase { DebugLoc CurDbgLocation; protected: BasicBlock *BB; BasicBlock::iterator InsertPt; LLVMContext &Context; MDNode *DefaultFPMathTag; FastMathFlags FMF; ArrayRef DefaultOperandBundles; public: IRBuilderBase(LLVMContext &context, MDNode *FPMathTag = nullptr, ArrayRef OpBundles = None) : Context(context), DefaultFPMathTag(FPMathTag), FMF(), DefaultOperandBundles(OpBundles) { ClearInsertionPoint(); } //===--------------------------------------------------------------------===// // Builder configuration methods //===--------------------------------------------------------------------===// /// \brief Clear the insertion point: created instructions will not be /// inserted into a block. void ClearInsertionPoint() { BB = nullptr; InsertPt.reset(nullptr); } BasicBlock *GetInsertBlock() const { return BB; } BasicBlock::iterator GetInsertPoint() const { return InsertPt; } LLVMContext &getContext() const { return Context; } /// \brief This specifies that created instructions should be appended to the /// end of the specified block. void SetInsertPoint(BasicBlock *TheBB) { BB = TheBB; InsertPt = BB->end(); } /// \brief This specifies that created instructions should be inserted before /// the specified instruction. void SetInsertPoint(Instruction *I) { BB = I->getParent(); InsertPt = I->getIterator(); assert(InsertPt != BB->end() && "Can't read debug loc from end()"); SetCurrentDebugLocation(I->getDebugLoc()); } /// \brief This specifies that created instructions should be inserted at the /// specified point. void SetInsertPoint(BasicBlock *TheBB, BasicBlock::iterator IP) { BB = TheBB; InsertPt = IP; if (IP != TheBB->end()) SetCurrentDebugLocation(IP->getDebugLoc()); } /// \brief Set location information used by debugging information. void SetCurrentDebugLocation(DebugLoc L) { CurDbgLocation = std::move(L); } /// \brief Get location information used by debugging information. const DebugLoc &getCurrentDebugLocation() const { return CurDbgLocation; } /// \brief If this builder has a current debug location, set it on the /// specified instruction. void SetInstDebugLocation(Instruction *I) const { if (CurDbgLocation) I->setDebugLoc(CurDbgLocation); } /// \brief Get the return type of the current function that we're emitting /// into. Type *getCurrentFunctionReturnType() const; /// InsertPoint - A saved insertion point. class InsertPoint { BasicBlock *Block; BasicBlock::iterator Point; public: /// \brief Creates a new insertion point which doesn't point to anything. InsertPoint() : Block(nullptr) {} /// \brief Creates a new insertion point at the given location. InsertPoint(BasicBlock *InsertBlock, BasicBlock::iterator InsertPoint) : Block(InsertBlock), Point(InsertPoint) {} /// \brief Returns true if this insert point is set. bool isSet() const { return (Block != nullptr); } llvm::BasicBlock *getBlock() const { return Block; } llvm::BasicBlock::iterator getPoint() const { return Point; } }; /// \brief Returns the current insert point. InsertPoint saveIP() const { return InsertPoint(GetInsertBlock(), GetInsertPoint()); } /// \brief Returns the current insert point, clearing it in the process. InsertPoint saveAndClearIP() { InsertPoint IP(GetInsertBlock(), GetInsertPoint()); ClearInsertionPoint(); return IP; } /// \brief Sets the current insert point to a previously-saved location. void restoreIP(InsertPoint IP) { if (IP.isSet()) SetInsertPoint(IP.getBlock(), IP.getPoint()); else ClearInsertionPoint(); } /// \brief Get the floating point math metadata being used. MDNode *getDefaultFPMathTag() const { return DefaultFPMathTag; } /// \brief Get the flags to be applied to created floating point ops FastMathFlags getFastMathFlags() const { return FMF; } /// \brief Clear the fast-math flags. void clearFastMathFlags() { FMF.clear(); } /// \brief Set the floating point math metadata to be used. void setDefaultFPMathTag(MDNode *FPMathTag) { DefaultFPMathTag = FPMathTag; } /// \brief Set the fast-math flags to be used with generated fp-math operators void setFastMathFlags(FastMathFlags NewFMF) { FMF = NewFMF; } //===--------------------------------------------------------------------===// // RAII helpers. //===--------------------------------------------------------------------===// // \brief RAII object that stores the current insertion point and restores it // when the object is destroyed. This includes the debug location. class InsertPointGuard { IRBuilderBase &Builder; AssertingVH Block; BasicBlock::iterator Point; DebugLoc DbgLoc; InsertPointGuard(const InsertPointGuard &) = delete; InsertPointGuard &operator=(const InsertPointGuard &) = delete; public: InsertPointGuard(IRBuilderBase &B) : Builder(B), Block(B.GetInsertBlock()), Point(B.GetInsertPoint()), DbgLoc(B.getCurrentDebugLocation()) {} ~InsertPointGuard() { Builder.restoreIP(InsertPoint(Block, Point)); Builder.SetCurrentDebugLocation(DbgLoc); } }; // \brief RAII object that stores the current fast math settings and restores // them when the object is destroyed. class FastMathFlagGuard { IRBuilderBase &Builder; FastMathFlags FMF; MDNode *FPMathTag; FastMathFlagGuard(const FastMathFlagGuard &) = delete; FastMathFlagGuard &operator=( const FastMathFlagGuard &) = delete; public: FastMathFlagGuard(IRBuilderBase &B) : Builder(B), FMF(B.FMF), FPMathTag(B.DefaultFPMathTag) {} ~FastMathFlagGuard() { Builder.FMF = FMF; Builder.DefaultFPMathTag = FPMathTag; } }; //===--------------------------------------------------------------------===// // Miscellaneous creation methods. //===--------------------------------------------------------------------===// /// \brief Make a new global variable with initializer type i8* /// /// Make a new global variable with an initializer that has array of i8 type /// filled in with the null terminated string value specified. The new global /// variable will be marked mergable with any others of the same contents. If /// Name is specified, it is the name of the global variable created. GlobalVariable *CreateGlobalString(StringRef Str, const Twine &Name = "", unsigned AddressSpace = 0); /// \brief Get a constant value representing either true or false. ConstantInt *getInt1(bool V) { return ConstantInt::get(getInt1Ty(), V); } /// \brief Get the constant value for i1 true. ConstantInt *getTrue() { return ConstantInt::getTrue(Context); } /// \brief Get the constant value for i1 false. ConstantInt *getFalse() { return ConstantInt::getFalse(Context); } /// \brief Get a constant 8-bit value. ConstantInt *getInt8(uint8_t C) { return ConstantInt::get(getInt8Ty(), C); } /// \brief Get a constant 16-bit value. ConstantInt *getInt16(uint16_t C) { return ConstantInt::get(getInt16Ty(), C); } /// \brief Get a constant 32-bit value. ConstantInt *getInt32(uint32_t C) { return ConstantInt::get(getInt32Ty(), C); } /// \brief Get a constant 64-bit value. ConstantInt *getInt64(uint64_t C) { return ConstantInt::get(getInt64Ty(), C); } /// \brief Get a constant N-bit value, zero extended or truncated from /// a 64-bit value. ConstantInt *getIntN(unsigned N, uint64_t C) { return ConstantInt::get(getIntNTy(N), C); } /// \brief Get a constant integer value. ConstantInt *getInt(const APInt &AI) { return ConstantInt::get(Context, AI); } //===--------------------------------------------------------------------===// // Type creation methods //===--------------------------------------------------------------------===// /// \brief Fetch the type representing a single bit IntegerType *getInt1Ty() { return Type::getInt1Ty(Context); } /// \brief Fetch the type representing an 8-bit integer. IntegerType *getInt8Ty() { return Type::getInt8Ty(Context); } /// \brief Fetch the type representing a 16-bit integer. IntegerType *getInt16Ty() { return Type::getInt16Ty(Context); } /// \brief Fetch the type representing a 32-bit integer. IntegerType *getInt32Ty() { return Type::getInt32Ty(Context); } /// \brief Fetch the type representing a 64-bit integer. IntegerType *getInt64Ty() { return Type::getInt64Ty(Context); } /// \brief Fetch the type representing a 128-bit integer. IntegerType *getInt128Ty() { return Type::getInt128Ty(Context); } /// \brief Fetch the type representing an N-bit integer. IntegerType *getIntNTy(unsigned N) { return Type::getIntNTy(Context, N); } /// \brief Fetch the type representing a 16-bit floating point value. Type *getHalfTy() { return Type::getHalfTy(Context); } /// \brief Fetch the type representing a 32-bit floating point value. Type *getFloatTy() { return Type::getFloatTy(Context); } /// \brief Fetch the type representing a 64-bit floating point value. Type *getDoubleTy() { return Type::getDoubleTy(Context); } /// \brief Fetch the type representing void. Type *getVoidTy() { return Type::getVoidTy(Context); } /// \brief Fetch the type representing a pointer to an 8-bit integer value. PointerType *getInt8PtrTy(unsigned AddrSpace = 0) { return Type::getInt8PtrTy(Context, AddrSpace); } /// \brief Fetch the type representing a pointer to an integer value. IntegerType *getIntPtrTy(const DataLayout &DL, unsigned AddrSpace = 0) { return DL.getIntPtrType(Context, AddrSpace); } //===--------------------------------------------------------------------===// // Intrinsic creation methods //===--------------------------------------------------------------------===// /// \brief Create and insert a memset to the specified pointer and the /// specified value. /// /// If the pointer isn't an i8*, it will be converted. If a TBAA tag is /// specified, it will be added to the instruction. Likewise with alias.scope /// and noalias tags. CallInst *CreateMemSet(Value *Ptr, Value *Val, uint64_t Size, unsigned Align, bool isVolatile = false, MDNode *TBAATag = nullptr, MDNode *ScopeTag = nullptr, MDNode *NoAliasTag = nullptr) { return CreateMemSet(Ptr, Val, getInt64(Size), Align, isVolatile, TBAATag, ScopeTag, NoAliasTag); } CallInst *CreateMemSet(Value *Ptr, Value *Val, Value *Size, unsigned Align, bool isVolatile = false, MDNode *TBAATag = nullptr, MDNode *ScopeTag = nullptr, MDNode *NoAliasTag = nullptr); /// \brief Create and insert a memcpy between the specified pointers. /// /// If the pointers aren't i8*, they will be converted. If a TBAA tag is /// specified, it will be added to the instruction. Likewise with alias.scope /// and noalias tags. CallInst *CreateMemCpy(Value *Dst, Value *Src, uint64_t Size, unsigned Align, bool isVolatile = false, MDNode *TBAATag = nullptr, MDNode *TBAAStructTag = nullptr, MDNode *ScopeTag = nullptr, MDNode *NoAliasTag = nullptr) { return CreateMemCpy(Dst, Src, getInt64(Size), Align, isVolatile, TBAATag, TBAAStructTag, ScopeTag, NoAliasTag); } CallInst *CreateMemCpy(Value *Dst, Value *Src, Value *Size, unsigned Align, bool isVolatile = false, MDNode *TBAATag = nullptr, MDNode *TBAAStructTag = nullptr, MDNode *ScopeTag = nullptr, MDNode *NoAliasTag = nullptr); /// \brief Create and insert a memmove between the specified /// pointers. /// /// If the pointers aren't i8*, they will be converted. If a TBAA tag is /// specified, it will be added to the instruction. Likewise with alias.scope /// and noalias tags. CallInst *CreateMemMove(Value *Dst, Value *Src, uint64_t Size, unsigned Align, bool isVolatile = false, MDNode *TBAATag = nullptr, MDNode *ScopeTag = nullptr, MDNode *NoAliasTag = nullptr) { return CreateMemMove(Dst, Src, getInt64(Size), Align, isVolatile, TBAATag, ScopeTag, NoAliasTag); } CallInst *CreateMemMove(Value *Dst, Value *Src, Value *Size, unsigned Align, bool isVolatile = false, MDNode *TBAATag = nullptr, MDNode *ScopeTag = nullptr, MDNode *NoAliasTag = nullptr); /// \brief Create a lifetime.start intrinsic. /// /// If the pointer isn't i8* it will be converted. CallInst *CreateLifetimeStart(Value *Ptr, ConstantInt *Size = nullptr); /// \brief Create a lifetime.end intrinsic. /// /// If the pointer isn't i8* it will be converted. CallInst *CreateLifetimeEnd(Value *Ptr, ConstantInt *Size = nullptr); /// \brief Create a call to Masked Load intrinsic CallInst *CreateMaskedLoad(Value *Ptr, unsigned Align, Value *Mask, Value *PassThru = nullptr, const Twine &Name = ""); /// \brief Create a call to Masked Store intrinsic CallInst *CreateMaskedStore(Value *Val, Value *Ptr, unsigned Align, Value *Mask); /// \brief Create an assume intrinsic call that allows the optimizer to /// assume that the provided condition will be true. CallInst *CreateAssumption(Value *Cond); /// \brief Create a call to the experimental.gc.statepoint intrinsic to /// start a new statepoint sequence. CallInst *CreateGCStatepointCall(uint64_t ID, uint32_t NumPatchBytes, Value *ActualCallee, ArrayRef CallArgs, ArrayRef DeoptArgs, ArrayRef GCArgs, const Twine &Name = ""); /// \brief Create a call to the experimental.gc.statepoint intrinsic to /// start a new statepoint sequence. CallInst *CreateGCStatepointCall(uint64_t ID, uint32_t NumPatchBytes, Value *ActualCallee, uint32_t Flags, ArrayRef CallArgs, ArrayRef TransitionArgs, ArrayRef DeoptArgs, ArrayRef GCArgs, const Twine &Name = ""); // \brief Conveninence function for the common case when CallArgs are filled // in using makeArrayRef(CS.arg_begin(), CS.arg_end()); Use needs to be // .get()'ed to get the Value pointer. CallInst *CreateGCStatepointCall(uint64_t ID, uint32_t NumPatchBytes, Value *ActualCallee, ArrayRef CallArgs, ArrayRef DeoptArgs, ArrayRef GCArgs, const Twine &Name = ""); /// brief Create an invoke to the experimental.gc.statepoint intrinsic to /// start a new statepoint sequence. InvokeInst * CreateGCStatepointInvoke(uint64_t ID, uint32_t NumPatchBytes, Value *ActualInvokee, BasicBlock *NormalDest, BasicBlock *UnwindDest, ArrayRef InvokeArgs, ArrayRef DeoptArgs, ArrayRef GCArgs, const Twine &Name = ""); /// brief Create an invoke to the experimental.gc.statepoint intrinsic to /// start a new statepoint sequence. InvokeInst *CreateGCStatepointInvoke( uint64_t ID, uint32_t NumPatchBytes, Value *ActualInvokee, BasicBlock *NormalDest, BasicBlock *UnwindDest, uint32_t Flags, ArrayRef InvokeArgs, ArrayRef TransitionArgs, ArrayRef DeoptArgs, ArrayRef GCArgs, const Twine &Name = ""); // Conveninence function for the common case when CallArgs are filled in using // makeArrayRef(CS.arg_begin(), CS.arg_end()); Use needs to be .get()'ed to // get the Value *. InvokeInst * CreateGCStatepointInvoke(uint64_t ID, uint32_t NumPatchBytes, Value *ActualInvokee, BasicBlock *NormalDest, BasicBlock *UnwindDest, ArrayRef InvokeArgs, ArrayRef DeoptArgs, ArrayRef GCArgs, const Twine &Name = ""); /// \brief Create a call to the experimental.gc.result intrinsic to extract /// the result from a call wrapped in a statepoint. CallInst *CreateGCResult(Instruction *Statepoint, Type *ResultType, const Twine &Name = ""); /// \brief Create a call to the experimental.gc.relocate intrinsics to /// project the relocated value of one pointer from the statepoint. CallInst *CreateGCRelocate(Instruction *Statepoint, int BaseOffset, int DerivedOffset, Type *ResultType, const Twine &Name = ""); private: /// \brief Create a call to a masked intrinsic with given Id. /// Masked intrinsic has only one overloaded type - data type. CallInst *CreateMaskedIntrinsic(Intrinsic::ID Id, ArrayRef Ops, Type *DataTy, const Twine &Name = ""); Value *getCastedInt8PtrValue(Value *Ptr); }; /// \brief This provides a uniform API for creating instructions and inserting /// them into a basic block: either at the end of a BasicBlock, or at a specific /// iterator location in a block. /// /// Note that the builder does not expose the full generality of LLVM /// instructions. For access to extra instruction properties, use the mutators /// (e.g. setVolatile) on the instructions after they have been /// created. Convenience state exists to specify fast-math flags and fp-math /// tags. /// /// The first template argument handles whether or not to preserve names in the /// final instruction output. This defaults to on. The second template argument /// specifies a class to use for creating constants. This defaults to creating /// minimally folded constants. The third template argument allows clients to /// specify custom insertion hooks that are called on every newly created /// insertion. template > class IRBuilder : public IRBuilderBase, public Inserter { T Folder; public: IRBuilder(LLVMContext &C, const T &F, Inserter I = Inserter(), MDNode *FPMathTag = nullptr, ArrayRef OpBundles = None) : IRBuilderBase(C, FPMathTag, OpBundles), Inserter(std::move(I)), Folder(F) {} explicit IRBuilder(LLVMContext &C, MDNode *FPMathTag = nullptr, ArrayRef OpBundles = None) : IRBuilderBase(C, FPMathTag, OpBundles), Folder() {} explicit IRBuilder(BasicBlock *TheBB, const T &F, MDNode *FPMathTag = nullptr, ArrayRef OpBundles = None) : IRBuilderBase(TheBB->getContext(), FPMathTag, OpBundles), Folder(F) { SetInsertPoint(TheBB); } explicit IRBuilder(BasicBlock *TheBB, MDNode *FPMathTag = nullptr, ArrayRef OpBundles = None) : IRBuilderBase(TheBB->getContext(), FPMathTag, OpBundles), Folder() { SetInsertPoint(TheBB); } explicit IRBuilder(Instruction *IP, MDNode *FPMathTag = nullptr, ArrayRef OpBundles = None) : IRBuilderBase(IP->getContext(), FPMathTag, OpBundles), Folder() { SetInsertPoint(IP); } IRBuilder(BasicBlock *TheBB, BasicBlock::iterator IP, const T &F, MDNode *FPMathTag = nullptr, ArrayRef OpBundles = None) : IRBuilderBase(TheBB->getContext(), FPMathTag, OpBundles), Folder(F) { SetInsertPoint(TheBB, IP); } IRBuilder(BasicBlock *TheBB, BasicBlock::iterator IP, MDNode *FPMathTag = nullptr, ArrayRef OpBundles = None) : IRBuilderBase(TheBB->getContext(), FPMathTag, OpBundles), Folder() { SetInsertPoint(TheBB, IP); } /// \brief Get the constant folder being used. const T &getFolder() { return Folder; } /// \brief Return true if this builder is configured to actually add the /// requested names to IR created through it. bool isNamePreserving() const { return preserveNames; } /// \brief Insert and return the specified instruction. template InstTy *Insert(InstTy *I, const Twine &Name = "") const { this->InsertHelper(I, Name, BB, InsertPt); this->SetInstDebugLocation(I); return I; } /// \brief No-op overload to handle constants. Constant *Insert(Constant *C, const Twine& = "") const { return C; } //===--------------------------------------------------------------------===// // Instruction creation methods: Terminators //===--------------------------------------------------------------------===// private: /// \brief Helper to add branch weight and unpredictable metadata onto an /// instruction. /// \returns The annotated instruction. template InstTy *addBranchMetadata(InstTy *I, MDNode *Weights, MDNode *Unpredictable) { if (Weights) I->setMetadata(LLVMContext::MD_prof, Weights); if (Unpredictable) I->setMetadata(LLVMContext::MD_unpredictable, Unpredictable); return I; } public: /// \brief Create a 'ret void' instruction. ReturnInst *CreateRetVoid() { return Insert(ReturnInst::Create(Context)); } /// \brief Create a 'ret ' instruction. ReturnInst *CreateRet(Value *V) { return Insert(ReturnInst::Create(Context, V)); } /// \brief Create a sequence of N insertvalue instructions, /// with one Value from the retVals array each, that build a aggregate /// return value one value at a time, and a ret instruction to return /// the resulting aggregate value. /// /// This is a convenience function for code that uses aggregate return values /// as a vehicle for having multiple return values. ReturnInst *CreateAggregateRet(Value *const *retVals, unsigned N) { Value *V = UndefValue::get(getCurrentFunctionReturnType()); for (unsigned i = 0; i != N; ++i) V = CreateInsertValue(V, retVals[i], i, "mrv"); return Insert(ReturnInst::Create(Context, V)); } /// \brief Create an unconditional 'br label X' instruction. BranchInst *CreateBr(BasicBlock *Dest) { return Insert(BranchInst::Create(Dest)); } /// \brief Create a conditional 'br Cond, TrueDest, FalseDest' /// instruction. BranchInst *CreateCondBr(Value *Cond, BasicBlock *True, BasicBlock *False, MDNode *BranchWeights = nullptr, MDNode *Unpredictable = nullptr) { return Insert(addBranchMetadata(BranchInst::Create(True, False, Cond), BranchWeights, Unpredictable)); } /// \brief Create a switch instruction with the specified value, default dest, /// and with a hint for the number of cases that will be added (for efficient /// allocation). SwitchInst *CreateSwitch(Value *V, BasicBlock *Dest, unsigned NumCases = 10, MDNode *BranchWeights = nullptr, MDNode *Unpredictable = nullptr) { return Insert(addBranchMetadata(SwitchInst::Create(V, Dest, NumCases), BranchWeights, Unpredictable)); } /// \brief Create an indirect branch instruction with the specified address /// operand, with an optional hint for the number of destinations that will be /// added (for efficient allocation). IndirectBrInst *CreateIndirectBr(Value *Addr, unsigned NumDests = 10) { return Insert(IndirectBrInst::Create(Addr, NumDests)); } InvokeInst *CreateInvoke(Value *Callee, BasicBlock *NormalDest, BasicBlock *UnwindDest, const Twine &Name = "") { return Insert(InvokeInst::Create(Callee, NormalDest, UnwindDest, None), Name); } InvokeInst *CreateInvoke(Value *Callee, BasicBlock *NormalDest, BasicBlock *UnwindDest, Value *Arg1, const Twine &Name = "") { return Insert(InvokeInst::Create(Callee, NormalDest, UnwindDest, Arg1), Name); } InvokeInst *CreateInvoke3(Value *Callee, BasicBlock *NormalDest, BasicBlock *UnwindDest, Value *Arg1, Value *Arg2, Value *Arg3, const Twine &Name = "") { Value *Args[] = { Arg1, Arg2, Arg3 }; return Insert(InvokeInst::Create(Callee, NormalDest, UnwindDest, Args), Name); } /// \brief Create an invoke instruction. InvokeInst *CreateInvoke(Value *Callee, BasicBlock *NormalDest, BasicBlock *UnwindDest, ArrayRef Args, const Twine &Name = "") { return Insert(InvokeInst::Create(Callee, NormalDest, UnwindDest, Args), Name); } InvokeInst *CreateInvoke(Value *Callee, BasicBlock *NormalDest, BasicBlock *UnwindDest, ArrayRef Args, ArrayRef OpBundles, const Twine &Name = "") { return Insert(InvokeInst::Create(Callee, NormalDest, UnwindDest, Args, OpBundles), Name); } ResumeInst *CreateResume(Value *Exn) { return Insert(ResumeInst::Create(Exn)); } CleanupReturnInst *CreateCleanupRet(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB = nullptr) { return Insert(CleanupReturnInst::Create(CleanupPad, UnwindBB)); } CatchSwitchInst *CreateCatchSwitch(Value *ParentPad, BasicBlock *UnwindBB, unsigned NumHandlers, const Twine &Name = "") { return Insert(CatchSwitchInst::Create(ParentPad, UnwindBB, NumHandlers), Name); } CatchPadInst *CreateCatchPad(Value *ParentPad, ArrayRef Args, const Twine &Name = "") { return Insert(CatchPadInst::Create(ParentPad, Args), Name); } CleanupPadInst *CreateCleanupPad(Value *ParentPad, ArrayRef Args = None, const Twine &Name = "") { return Insert(CleanupPadInst::Create(ParentPad, Args), Name); } CatchReturnInst *CreateCatchRet(CatchPadInst *CatchPad, BasicBlock *BB) { return Insert(CatchReturnInst::Create(CatchPad, BB)); } UnreachableInst *CreateUnreachable() { return Insert(new UnreachableInst(Context)); } //===--------------------------------------------------------------------===// // Instruction creation methods: Binary Operators //===--------------------------------------------------------------------===// private: BinaryOperator *CreateInsertNUWNSWBinOp(BinaryOperator::BinaryOps Opc, Value *LHS, Value *RHS, const Twine &Name, bool HasNUW, bool HasNSW) { BinaryOperator *BO = Insert(BinaryOperator::Create(Opc, LHS, RHS), Name); if (HasNUW) BO->setHasNoUnsignedWrap(); if (HasNSW) BO->setHasNoSignedWrap(); return BO; } Instruction *AddFPMathAttributes(Instruction *I, MDNode *FPMathTag, FastMathFlags FMF) const { if (!FPMathTag) FPMathTag = DefaultFPMathTag; if (FPMathTag) I->setMetadata(LLVMContext::MD_fpmath, FPMathTag); I->setFastMathFlags(FMF); return I; } public: Value *CreateAdd(Value *LHS, Value *RHS, const Twine &Name = "", bool HasNUW = false, bool HasNSW = false) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateAdd(LC, RC, HasNUW, HasNSW), Name); return CreateInsertNUWNSWBinOp(Instruction::Add, LHS, RHS, Name, HasNUW, HasNSW); } Value *CreateNSWAdd(Value *LHS, Value *RHS, const Twine &Name = "") { return CreateAdd(LHS, RHS, Name, false, true); } Value *CreateNUWAdd(Value *LHS, Value *RHS, const Twine &Name = "") { return CreateAdd(LHS, RHS, Name, true, false); } Value *CreateFAdd(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateFAdd(LC, RC), Name); return Insert(AddFPMathAttributes(BinaryOperator::CreateFAdd(LHS, RHS), FPMathTag, FMF), Name); } Value *CreateSub(Value *LHS, Value *RHS, const Twine &Name = "", bool HasNUW = false, bool HasNSW = false) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateSub(LC, RC, HasNUW, HasNSW), Name); return CreateInsertNUWNSWBinOp(Instruction::Sub, LHS, RHS, Name, HasNUW, HasNSW); } Value *CreateNSWSub(Value *LHS, Value *RHS, const Twine &Name = "") { return CreateSub(LHS, RHS, Name, false, true); } Value *CreateNUWSub(Value *LHS, Value *RHS, const Twine &Name = "") { return CreateSub(LHS, RHS, Name, true, false); } Value *CreateFSub(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateFSub(LC, RC), Name); return Insert(AddFPMathAttributes(BinaryOperator::CreateFSub(LHS, RHS), FPMathTag, FMF), Name); } Value *CreateMul(Value *LHS, Value *RHS, const Twine &Name = "", bool HasNUW = false, bool HasNSW = false) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateMul(LC, RC, HasNUW, HasNSW), Name); return CreateInsertNUWNSWBinOp(Instruction::Mul, LHS, RHS, Name, HasNUW, HasNSW); } Value *CreateNSWMul(Value *LHS, Value *RHS, const Twine &Name = "") { return CreateMul(LHS, RHS, Name, false, true); } Value *CreateNUWMul(Value *LHS, Value *RHS, const Twine &Name = "") { return CreateMul(LHS, RHS, Name, true, false); } Value *CreateFMul(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateFMul(LC, RC), Name); return Insert(AddFPMathAttributes(BinaryOperator::CreateFMul(LHS, RHS), FPMathTag, FMF), Name); } Value *CreateUDiv(Value *LHS, Value *RHS, const Twine &Name = "", bool isExact = false) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateUDiv(LC, RC, isExact), Name); if (!isExact) return Insert(BinaryOperator::CreateUDiv(LHS, RHS), Name); return Insert(BinaryOperator::CreateExactUDiv(LHS, RHS), Name); } Value *CreateExactUDiv(Value *LHS, Value *RHS, const Twine &Name = "") { return CreateUDiv(LHS, RHS, Name, true); } Value *CreateSDiv(Value *LHS, Value *RHS, const Twine &Name = "", bool isExact = false) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateSDiv(LC, RC, isExact), Name); if (!isExact) return Insert(BinaryOperator::CreateSDiv(LHS, RHS), Name); return Insert(BinaryOperator::CreateExactSDiv(LHS, RHS), Name); } Value *CreateExactSDiv(Value *LHS, Value *RHS, const Twine &Name = "") { return CreateSDiv(LHS, RHS, Name, true); } Value *CreateFDiv(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateFDiv(LC, RC), Name); return Insert(AddFPMathAttributes(BinaryOperator::CreateFDiv(LHS, RHS), FPMathTag, FMF), Name); } Value *CreateURem(Value *LHS, Value *RHS, const Twine &Name = "") { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateURem(LC, RC), Name); return Insert(BinaryOperator::CreateURem(LHS, RHS), Name); } Value *CreateSRem(Value *LHS, Value *RHS, const Twine &Name = "") { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateSRem(LC, RC), Name); return Insert(BinaryOperator::CreateSRem(LHS, RHS), Name); } Value *CreateFRem(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateFRem(LC, RC), Name); return Insert(AddFPMathAttributes(BinaryOperator::CreateFRem(LHS, RHS), FPMathTag, FMF), Name); } Value *CreateShl(Value *LHS, Value *RHS, const Twine &Name = "", bool HasNUW = false, bool HasNSW = false) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateShl(LC, RC, HasNUW, HasNSW), Name); return CreateInsertNUWNSWBinOp(Instruction::Shl, LHS, RHS, Name, HasNUW, HasNSW); } Value *CreateShl(Value *LHS, const APInt &RHS, const Twine &Name = "", bool HasNUW = false, bool HasNSW = false) { return CreateShl(LHS, ConstantInt::get(LHS->getType(), RHS), Name, HasNUW, HasNSW); } Value *CreateShl(Value *LHS, uint64_t RHS, const Twine &Name = "", bool HasNUW = false, bool HasNSW = false) { return CreateShl(LHS, ConstantInt::get(LHS->getType(), RHS), Name, HasNUW, HasNSW); } Value *CreateLShr(Value *LHS, Value *RHS, const Twine &Name = "", bool isExact = false) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateLShr(LC, RC, isExact), Name); if (!isExact) return Insert(BinaryOperator::CreateLShr(LHS, RHS), Name); return Insert(BinaryOperator::CreateExactLShr(LHS, RHS), Name); } Value *CreateLShr(Value *LHS, const APInt &RHS, const Twine &Name = "", bool isExact = false) { return CreateLShr(LHS, ConstantInt::get(LHS->getType(), RHS), Name,isExact); } Value *CreateLShr(Value *LHS, uint64_t RHS, const Twine &Name = "", bool isExact = false) { return CreateLShr(LHS, ConstantInt::get(LHS->getType(), RHS), Name,isExact); } Value *CreateAShr(Value *LHS, Value *RHS, const Twine &Name = "", bool isExact = false) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateAShr(LC, RC, isExact), Name); if (!isExact) return Insert(BinaryOperator::CreateAShr(LHS, RHS), Name); return Insert(BinaryOperator::CreateExactAShr(LHS, RHS), Name); } Value *CreateAShr(Value *LHS, const APInt &RHS, const Twine &Name = "", bool isExact = false) { return CreateAShr(LHS, ConstantInt::get(LHS->getType(), RHS), Name,isExact); } Value *CreateAShr(Value *LHS, uint64_t RHS, const Twine &Name = "", bool isExact = false) { return CreateAShr(LHS, ConstantInt::get(LHS->getType(), RHS), Name,isExact); } Value *CreateAnd(Value *LHS, Value *RHS, const Twine &Name = "") { if (Constant *RC = dyn_cast(RHS)) { if (isa(RC) && cast(RC)->isAllOnesValue()) return LHS; // LHS & -1 -> LHS if (Constant *LC = dyn_cast(LHS)) return Insert(Folder.CreateAnd(LC, RC), Name); } return Insert(BinaryOperator::CreateAnd(LHS, RHS), Name); } Value *CreateAnd(Value *LHS, const APInt &RHS, const Twine &Name = "") { return CreateAnd(LHS, ConstantInt::get(LHS->getType(), RHS), Name); } Value *CreateAnd(Value *LHS, uint64_t RHS, const Twine &Name = "") { return CreateAnd(LHS, ConstantInt::get(LHS->getType(), RHS), Name); } Value *CreateOr(Value *LHS, Value *RHS, const Twine &Name = "") { if (Constant *RC = dyn_cast(RHS)) { if (RC->isNullValue()) return LHS; // LHS | 0 -> LHS if (Constant *LC = dyn_cast(LHS)) return Insert(Folder.CreateOr(LC, RC), Name); } return Insert(BinaryOperator::CreateOr(LHS, RHS), Name); } Value *CreateOr(Value *LHS, const APInt &RHS, const Twine &Name = "") { return CreateOr(LHS, ConstantInt::get(LHS->getType(), RHS), Name); } Value *CreateOr(Value *LHS, uint64_t RHS, const Twine &Name = "") { return CreateOr(LHS, ConstantInt::get(LHS->getType(), RHS), Name); } Value *CreateXor(Value *LHS, Value *RHS, const Twine &Name = "") { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateXor(LC, RC), Name); return Insert(BinaryOperator::CreateXor(LHS, RHS), Name); } Value *CreateXor(Value *LHS, const APInt &RHS, const Twine &Name = "") { return CreateXor(LHS, ConstantInt::get(LHS->getType(), RHS), Name); } Value *CreateXor(Value *LHS, uint64_t RHS, const Twine &Name = "") { return CreateXor(LHS, ConstantInt::get(LHS->getType(), RHS), Name); } Value *CreateBinOp(Instruction::BinaryOps Opc, Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateBinOp(Opc, LC, RC), Name); llvm::Instruction *BinOp = BinaryOperator::Create(Opc, LHS, RHS); if (isa(BinOp)) BinOp = AddFPMathAttributes(BinOp, FPMathTag, FMF); return Insert(BinOp, Name); } Value *CreateNeg(Value *V, const Twine &Name = "", bool HasNUW = false, bool HasNSW = false) { if (Constant *VC = dyn_cast(V)) return Insert(Folder.CreateNeg(VC, HasNUW, HasNSW), Name); BinaryOperator *BO = Insert(BinaryOperator::CreateNeg(V), Name); if (HasNUW) BO->setHasNoUnsignedWrap(); if (HasNSW) BO->setHasNoSignedWrap(); return BO; } Value *CreateNSWNeg(Value *V, const Twine &Name = "") { return CreateNeg(V, Name, false, true); } Value *CreateNUWNeg(Value *V, const Twine &Name = "") { return CreateNeg(V, Name, true, false); } Value *CreateFNeg(Value *V, const Twine &Name = "", MDNode *FPMathTag = nullptr) { if (Constant *VC = dyn_cast(V)) return Insert(Folder.CreateFNeg(VC), Name); return Insert(AddFPMathAttributes(BinaryOperator::CreateFNeg(V), FPMathTag, FMF), Name); } Value *CreateNot(Value *V, const Twine &Name = "") { if (Constant *VC = dyn_cast(V)) return Insert(Folder.CreateNot(VC), Name); return Insert(BinaryOperator::CreateNot(V), Name); } //===--------------------------------------------------------------------===// // Instruction creation methods: Memory Instructions //===--------------------------------------------------------------------===// AllocaInst *CreateAlloca(Type *Ty, Value *ArraySize = nullptr, const Twine &Name = "") { return Insert(new AllocaInst(Ty, ArraySize), Name); } // \brief Provided to resolve 'CreateLoad(Ptr, "...")' correctly, instead of // converting the string to 'bool' for the isVolatile parameter. LoadInst *CreateLoad(Value *Ptr, const char *Name) { return Insert(new LoadInst(Ptr), Name); } LoadInst *CreateLoad(Value *Ptr, const Twine &Name = "") { return Insert(new LoadInst(Ptr), Name); } LoadInst *CreateLoad(Type *Ty, Value *Ptr, const Twine &Name = "") { return Insert(new LoadInst(Ty, Ptr), Name); } LoadInst *CreateLoad(Value *Ptr, bool isVolatile, const Twine &Name = "") { return Insert(new LoadInst(Ptr, nullptr, isVolatile), Name); } StoreInst *CreateStore(Value *Val, Value *Ptr, bool isVolatile = false) { return Insert(new StoreInst(Val, Ptr, isVolatile)); } // \brief Provided to resolve 'CreateAlignedLoad(Ptr, Align, "...")' // correctly, instead of converting the string to 'bool' for the isVolatile // parameter. LoadInst *CreateAlignedLoad(Value *Ptr, unsigned Align, const char *Name) { LoadInst *LI = CreateLoad(Ptr, Name); LI->setAlignment(Align); return LI; } LoadInst *CreateAlignedLoad(Value *Ptr, unsigned Align, const Twine &Name = "") { LoadInst *LI = CreateLoad(Ptr, Name); LI->setAlignment(Align); return LI; } LoadInst *CreateAlignedLoad(Value *Ptr, unsigned Align, bool isVolatile, const Twine &Name = "") { LoadInst *LI = CreateLoad(Ptr, isVolatile, Name); LI->setAlignment(Align); return LI; } StoreInst *CreateAlignedStore(Value *Val, Value *Ptr, unsigned Align, bool isVolatile = false) { StoreInst *SI = CreateStore(Val, Ptr, isVolatile); SI->setAlignment(Align); return SI; } FenceInst *CreateFence(AtomicOrdering Ordering, SynchronizationScope SynchScope = CrossThread, const Twine &Name = "") { return Insert(new FenceInst(Context, Ordering, SynchScope), Name); } AtomicCmpXchgInst * CreateAtomicCmpXchg(Value *Ptr, Value *Cmp, Value *New, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, SynchronizationScope SynchScope = CrossThread) { return Insert(new AtomicCmpXchgInst(Ptr, Cmp, New, SuccessOrdering, FailureOrdering, SynchScope)); } AtomicRMWInst *CreateAtomicRMW(AtomicRMWInst::BinOp Op, Value *Ptr, Value *Val, AtomicOrdering Ordering, SynchronizationScope SynchScope = CrossThread) { return Insert(new AtomicRMWInst(Op, Ptr, Val, Ordering, SynchScope)); } Value *CreateGEP(Value *Ptr, ArrayRef IdxList, const Twine &Name = "") { return CreateGEP(nullptr, Ptr, IdxList, Name); } Value *CreateGEP(Type *Ty, Value *Ptr, ArrayRef IdxList, const Twine &Name = "") { if (Constant *PC = dyn_cast(Ptr)) { // Every index must be constant. size_t i, e; for (i = 0, e = IdxList.size(); i != e; ++i) if (!isa(IdxList[i])) break; if (i == e) return Insert(Folder.CreateGetElementPtr(Ty, PC, IdxList), Name); } return Insert(GetElementPtrInst::Create(Ty, Ptr, IdxList), Name); } Value *CreateInBoundsGEP(Value *Ptr, ArrayRef IdxList, const Twine &Name = "") { return CreateInBoundsGEP(nullptr, Ptr, IdxList, Name); } Value *CreateInBoundsGEP(Type *Ty, Value *Ptr, ArrayRef IdxList, const Twine &Name = "") { if (Constant *PC = dyn_cast(Ptr)) { // Every index must be constant. size_t i, e; for (i = 0, e = IdxList.size(); i != e; ++i) if (!isa(IdxList[i])) break; if (i == e) return Insert(Folder.CreateInBoundsGetElementPtr(Ty, PC, IdxList), Name); } return Insert(GetElementPtrInst::CreateInBounds(Ty, Ptr, IdxList), Name); } Value *CreateGEP(Value *Ptr, Value *Idx, const Twine &Name = "") { return CreateGEP(nullptr, Ptr, Idx, Name); } Value *CreateGEP(Type *Ty, Value *Ptr, Value *Idx, const Twine &Name = "") { if (Constant *PC = dyn_cast(Ptr)) if (Constant *IC = dyn_cast(Idx)) return Insert(Folder.CreateGetElementPtr(Ty, PC, IC), Name); return Insert(GetElementPtrInst::Create(Ty, Ptr, Idx), Name); } Value *CreateInBoundsGEP(Type *Ty, Value *Ptr, Value *Idx, const Twine &Name = "") { if (Constant *PC = dyn_cast(Ptr)) if (Constant *IC = dyn_cast(Idx)) return Insert(Folder.CreateInBoundsGetElementPtr(Ty, PC, IC), Name); return Insert(GetElementPtrInst::CreateInBounds(Ty, Ptr, Idx), Name); } Value *CreateConstGEP1_32(Value *Ptr, unsigned Idx0, const Twine &Name = "") { return CreateConstGEP1_32(nullptr, Ptr, Idx0, Name); } Value *CreateConstGEP1_32(Type *Ty, Value *Ptr, unsigned Idx0, const Twine &Name = "") { Value *Idx = ConstantInt::get(Type::getInt32Ty(Context), Idx0); if (Constant *PC = dyn_cast(Ptr)) return Insert(Folder.CreateGetElementPtr(Ty, PC, Idx), Name); return Insert(GetElementPtrInst::Create(Ty, Ptr, Idx), Name); } Value *CreateConstInBoundsGEP1_32(Type *Ty, Value *Ptr, unsigned Idx0, const Twine &Name = "") { Value *Idx = ConstantInt::get(Type::getInt32Ty(Context), Idx0); if (Constant *PC = dyn_cast(Ptr)) return Insert(Folder.CreateInBoundsGetElementPtr(Ty, PC, Idx), Name); return Insert(GetElementPtrInst::CreateInBounds(Ty, Ptr, Idx), Name); } Value *CreateConstGEP2_32(Type *Ty, Value *Ptr, unsigned Idx0, unsigned Idx1, const Twine &Name = "") { Value *Idxs[] = { ConstantInt::get(Type::getInt32Ty(Context), Idx0), ConstantInt::get(Type::getInt32Ty(Context), Idx1) }; if (Constant *PC = dyn_cast(Ptr)) return Insert(Folder.CreateGetElementPtr(Ty, PC, Idxs), Name); return Insert(GetElementPtrInst::Create(Ty, Ptr, Idxs), Name); } Value *CreateConstInBoundsGEP2_32(Type *Ty, Value *Ptr, unsigned Idx0, unsigned Idx1, const Twine &Name = "") { Value *Idxs[] = { ConstantInt::get(Type::getInt32Ty(Context), Idx0), ConstantInt::get(Type::getInt32Ty(Context), Idx1) }; if (Constant *PC = dyn_cast(Ptr)) return Insert(Folder.CreateInBoundsGetElementPtr(Ty, PC, Idxs), Name); return Insert(GetElementPtrInst::CreateInBounds(Ty, Ptr, Idxs), Name); } Value *CreateConstGEP1_64(Value *Ptr, uint64_t Idx0, const Twine &Name = "") { Value *Idx = ConstantInt::get(Type::getInt64Ty(Context), Idx0); if (Constant *PC = dyn_cast(Ptr)) return Insert(Folder.CreateGetElementPtr(nullptr, PC, Idx), Name); return Insert(GetElementPtrInst::Create(nullptr, Ptr, Idx), Name); } Value *CreateConstInBoundsGEP1_64(Value *Ptr, uint64_t Idx0, const Twine &Name = "") { Value *Idx = ConstantInt::get(Type::getInt64Ty(Context), Idx0); if (Constant *PC = dyn_cast(Ptr)) return Insert(Folder.CreateInBoundsGetElementPtr(nullptr, PC, Idx), Name); return Insert(GetElementPtrInst::CreateInBounds(nullptr, Ptr, Idx), Name); } Value *CreateConstGEP2_64(Value *Ptr, uint64_t Idx0, uint64_t Idx1, const Twine &Name = "") { Value *Idxs[] = { ConstantInt::get(Type::getInt64Ty(Context), Idx0), ConstantInt::get(Type::getInt64Ty(Context), Idx1) }; if (Constant *PC = dyn_cast(Ptr)) return Insert(Folder.CreateGetElementPtr(nullptr, PC, Idxs), Name); return Insert(GetElementPtrInst::Create(nullptr, Ptr, Idxs), Name); } Value *CreateConstInBoundsGEP2_64(Value *Ptr, uint64_t Idx0, uint64_t Idx1, const Twine &Name = "") { Value *Idxs[] = { ConstantInt::get(Type::getInt64Ty(Context), Idx0), ConstantInt::get(Type::getInt64Ty(Context), Idx1) }; if (Constant *PC = dyn_cast(Ptr)) return Insert(Folder.CreateInBoundsGetElementPtr(nullptr, PC, Idxs), Name); return Insert(GetElementPtrInst::CreateInBounds(nullptr, Ptr, Idxs), Name); } Value *CreateStructGEP(Type *Ty, Value *Ptr, unsigned Idx, const Twine &Name = "") { return CreateConstInBoundsGEP2_32(Ty, Ptr, 0, Idx, Name); } /// \brief Same as CreateGlobalString, but return a pointer with "i8*" type /// instead of a pointer to array of i8. Value *CreateGlobalStringPtr(StringRef Str, const Twine &Name = "", unsigned AddressSpace = 0) { GlobalVariable *gv = CreateGlobalString(Str, Name, AddressSpace); Value *zero = ConstantInt::get(Type::getInt32Ty(Context), 0); Value *Args[] = { zero, zero }; return CreateInBoundsGEP(gv->getValueType(), gv, Args, Name); } //===--------------------------------------------------------------------===// // Instruction creation methods: Cast/Conversion Operators //===--------------------------------------------------------------------===// Value *CreateTrunc(Value *V, Type *DestTy, const Twine &Name = "") { return CreateCast(Instruction::Trunc, V, DestTy, Name); } Value *CreateZExt(Value *V, Type *DestTy, const Twine &Name = "") { return CreateCast(Instruction::ZExt, V, DestTy, Name); } Value *CreateSExt(Value *V, Type *DestTy, const Twine &Name = "") { return CreateCast(Instruction::SExt, V, DestTy, Name); } /// \brief Create a ZExt or Trunc from the integer value V to DestTy. Return /// the value untouched if the type of V is already DestTy. Value *CreateZExtOrTrunc(Value *V, Type *DestTy, const Twine &Name = "") { assert(V->getType()->isIntOrIntVectorTy() && DestTy->isIntOrIntVectorTy() && "Can only zero extend/truncate integers!"); Type *VTy = V->getType(); if (VTy->getScalarSizeInBits() < DestTy->getScalarSizeInBits()) return CreateZExt(V, DestTy, Name); if (VTy->getScalarSizeInBits() > DestTy->getScalarSizeInBits()) return CreateTrunc(V, DestTy, Name); return V; } /// \brief Create a SExt or Trunc from the integer value V to DestTy. Return /// the value untouched if the type of V is already DestTy. Value *CreateSExtOrTrunc(Value *V, Type *DestTy, const Twine &Name = "") { assert(V->getType()->isIntOrIntVectorTy() && DestTy->isIntOrIntVectorTy() && "Can only sign extend/truncate integers!"); Type *VTy = V->getType(); if (VTy->getScalarSizeInBits() < DestTy->getScalarSizeInBits()) return CreateSExt(V, DestTy, Name); if (VTy->getScalarSizeInBits() > DestTy->getScalarSizeInBits()) return CreateTrunc(V, DestTy, Name); return V; } Value *CreateFPToUI(Value *V, Type *DestTy, const Twine &Name = ""){ return CreateCast(Instruction::FPToUI, V, DestTy, Name); } Value *CreateFPToSI(Value *V, Type *DestTy, const Twine &Name = ""){ return CreateCast(Instruction::FPToSI, V, DestTy, Name); } Value *CreateUIToFP(Value *V, Type *DestTy, const Twine &Name = ""){ return CreateCast(Instruction::UIToFP, V, DestTy, Name); } Value *CreateSIToFP(Value *V, Type *DestTy, const Twine &Name = ""){ return CreateCast(Instruction::SIToFP, V, DestTy, Name); } Value *CreateFPTrunc(Value *V, Type *DestTy, const Twine &Name = "") { return CreateCast(Instruction::FPTrunc, V, DestTy, Name); } Value *CreateFPExt(Value *V, Type *DestTy, const Twine &Name = "") { return CreateCast(Instruction::FPExt, V, DestTy, Name); } Value *CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name = "") { return CreateCast(Instruction::PtrToInt, V, DestTy, Name); } Value *CreateIntToPtr(Value *V, Type *DestTy, const Twine &Name = "") { return CreateCast(Instruction::IntToPtr, V, DestTy, Name); } Value *CreateBitCast(Value *V, Type *DestTy, const Twine &Name = "") { return CreateCast(Instruction::BitCast, V, DestTy, Name); } Value *CreateAddrSpaceCast(Value *V, Type *DestTy, const Twine &Name = "") { return CreateCast(Instruction::AddrSpaceCast, V, DestTy, Name); } Value *CreateZExtOrBitCast(Value *V, Type *DestTy, const Twine &Name = "") { if (V->getType() == DestTy) return V; if (Constant *VC = dyn_cast(V)) return Insert(Folder.CreateZExtOrBitCast(VC, DestTy), Name); return Insert(CastInst::CreateZExtOrBitCast(V, DestTy), Name); } Value *CreateSExtOrBitCast(Value *V, Type *DestTy, const Twine &Name = "") { if (V->getType() == DestTy) return V; if (Constant *VC = dyn_cast(V)) return Insert(Folder.CreateSExtOrBitCast(VC, DestTy), Name); return Insert(CastInst::CreateSExtOrBitCast(V, DestTy), Name); } Value *CreateTruncOrBitCast(Value *V, Type *DestTy, const Twine &Name = "") { if (V->getType() == DestTy) return V; if (Constant *VC = dyn_cast(V)) return Insert(Folder.CreateTruncOrBitCast(VC, DestTy), Name); return Insert(CastInst::CreateTruncOrBitCast(V, DestTy), Name); } Value *CreateCast(Instruction::CastOps Op, Value *V, Type *DestTy, const Twine &Name = "") { if (V->getType() == DestTy) return V; if (Constant *VC = dyn_cast(V)) return Insert(Folder.CreateCast(Op, VC, DestTy), Name); return Insert(CastInst::Create(Op, V, DestTy), Name); } Value *CreatePointerCast(Value *V, Type *DestTy, const Twine &Name = "") { if (V->getType() == DestTy) return V; if (Constant *VC = dyn_cast(V)) return Insert(Folder.CreatePointerCast(VC, DestTy), Name); return Insert(CastInst::CreatePointerCast(V, DestTy), Name); } Value *CreatePointerBitCastOrAddrSpaceCast(Value *V, Type *DestTy, const Twine &Name = "") { if (V->getType() == DestTy) return V; if (Constant *VC = dyn_cast(V)) { return Insert(Folder.CreatePointerBitCastOrAddrSpaceCast(VC, DestTy), Name); } return Insert(CastInst::CreatePointerBitCastOrAddrSpaceCast(V, DestTy), Name); } Value *CreateIntCast(Value *V, Type *DestTy, bool isSigned, const Twine &Name = "") { if (V->getType() == DestTy) return V; if (Constant *VC = dyn_cast(V)) return Insert(Folder.CreateIntCast(VC, DestTy, isSigned), Name); return Insert(CastInst::CreateIntegerCast(V, DestTy, isSigned), Name); } Value *CreateBitOrPointerCast(Value *V, Type *DestTy, const Twine &Name = "") { if (V->getType() == DestTy) return V; if (V->getType()->getScalarType()->isPointerTy() && DestTy->getScalarType()->isIntegerTy()) return CreatePtrToInt(V, DestTy, Name); if (V->getType()->getScalarType()->isIntegerTy() && DestTy->getScalarType()->isPointerTy()) return CreateIntToPtr(V, DestTy, Name); return CreateBitCast(V, DestTy, Name); } private: // \brief Provided to resolve 'CreateIntCast(Ptr, Ptr, "...")', giving a // compile time error, instead of converting the string to bool for the // isSigned parameter. Value *CreateIntCast(Value *, Type *, const char *) = delete; public: Value *CreateFPCast(Value *V, Type *DestTy, const Twine &Name = "") { if (V->getType() == DestTy) return V; if (Constant *VC = dyn_cast(V)) return Insert(Folder.CreateFPCast(VC, DestTy), Name); return Insert(CastInst::CreateFPCast(V, DestTy), Name); } //===--------------------------------------------------------------------===// // Instruction creation methods: Compare Instructions //===--------------------------------------------------------------------===// Value *CreateICmpEQ(Value *LHS, Value *RHS, const Twine &Name = "") { return CreateICmp(ICmpInst::ICMP_EQ, LHS, RHS, Name); } Value *CreateICmpNE(Value *LHS, Value *RHS, const Twine &Name = "") { return CreateICmp(ICmpInst::ICMP_NE, LHS, RHS, Name); } Value *CreateICmpUGT(Value *LHS, Value *RHS, const Twine &Name = "") { return CreateICmp(ICmpInst::ICMP_UGT, LHS, RHS, Name); } Value *CreateICmpUGE(Value *LHS, Value *RHS, const Twine &Name = "") { return CreateICmp(ICmpInst::ICMP_UGE, LHS, RHS, Name); } Value *CreateICmpULT(Value *LHS, Value *RHS, const Twine &Name = "") { return CreateICmp(ICmpInst::ICMP_ULT, LHS, RHS, Name); } Value *CreateICmpULE(Value *LHS, Value *RHS, const Twine &Name = "") { return CreateICmp(ICmpInst::ICMP_ULE, LHS, RHS, Name); } Value *CreateICmpSGT(Value *LHS, Value *RHS, const Twine &Name = "") { return CreateICmp(ICmpInst::ICMP_SGT, LHS, RHS, Name); } Value *CreateICmpSGE(Value *LHS, Value *RHS, const Twine &Name = "") { return CreateICmp(ICmpInst::ICMP_SGE, LHS, RHS, Name); } Value *CreateICmpSLT(Value *LHS, Value *RHS, const Twine &Name = "") { return CreateICmp(ICmpInst::ICMP_SLT, LHS, RHS, Name); } Value *CreateICmpSLE(Value *LHS, Value *RHS, const Twine &Name = "") { return CreateICmp(ICmpInst::ICMP_SLE, LHS, RHS, Name); } Value *CreateFCmpOEQ(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { return CreateFCmp(FCmpInst::FCMP_OEQ, LHS, RHS, Name, FPMathTag); } Value *CreateFCmpOGT(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { return CreateFCmp(FCmpInst::FCMP_OGT, LHS, RHS, Name, FPMathTag); } Value *CreateFCmpOGE(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { return CreateFCmp(FCmpInst::FCMP_OGE, LHS, RHS, Name, FPMathTag); } Value *CreateFCmpOLT(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { return CreateFCmp(FCmpInst::FCMP_OLT, LHS, RHS, Name, FPMathTag); } Value *CreateFCmpOLE(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { return CreateFCmp(FCmpInst::FCMP_OLE, LHS, RHS, Name, FPMathTag); } Value *CreateFCmpONE(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { return CreateFCmp(FCmpInst::FCMP_ONE, LHS, RHS, Name, FPMathTag); } Value *CreateFCmpORD(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { return CreateFCmp(FCmpInst::FCMP_ORD, LHS, RHS, Name, FPMathTag); } Value *CreateFCmpUNO(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { return CreateFCmp(FCmpInst::FCMP_UNO, LHS, RHS, Name, FPMathTag); } Value *CreateFCmpUEQ(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { return CreateFCmp(FCmpInst::FCMP_UEQ, LHS, RHS, Name, FPMathTag); } Value *CreateFCmpUGT(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { return CreateFCmp(FCmpInst::FCMP_UGT, LHS, RHS, Name, FPMathTag); } Value *CreateFCmpUGE(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { return CreateFCmp(FCmpInst::FCMP_UGE, LHS, RHS, Name, FPMathTag); } Value *CreateFCmpULT(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { return CreateFCmp(FCmpInst::FCMP_ULT, LHS, RHS, Name, FPMathTag); } Value *CreateFCmpULE(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { return CreateFCmp(FCmpInst::FCMP_ULE, LHS, RHS, Name, FPMathTag); } Value *CreateFCmpUNE(Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { return CreateFCmp(FCmpInst::FCMP_UNE, LHS, RHS, Name, FPMathTag); } Value *CreateICmp(CmpInst::Predicate P, Value *LHS, Value *RHS, const Twine &Name = "") { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateICmp(P, LC, RC), Name); return Insert(new ICmpInst(P, LHS, RHS), Name); } Value *CreateFCmp(CmpInst::Predicate P, Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) return Insert(Folder.CreateFCmp(P, LC, RC), Name); return Insert(AddFPMathAttributes(new FCmpInst(P, LHS, RHS), FPMathTag, FMF), Name); } //===--------------------------------------------------------------------===// // Instruction creation methods: Other Instructions //===--------------------------------------------------------------------===// PHINode *CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name = "") { return Insert(PHINode::Create(Ty, NumReservedValues), Name); } CallInst *CreateCall(Value *Callee, ArrayRef Args = None, - ArrayRef OpBundles = None, const Twine &Name = "", MDNode *FPMathTag = nullptr) { - CallInst *CI = CallInst::Create(Callee, Args, OpBundles); - if (isa(CI)) - CI = cast(AddFPMathAttributes(CI, FPMathTag, FMF)); - return Insert(CI, Name); - } - - CallInst *CreateCall(Value *Callee, ArrayRef Args, - const Twine &Name, MDNode *FPMathTag = nullptr) { PointerType *PTy = cast(Callee->getType()); FunctionType *FTy = cast(PTy->getElementType()); return CreateCall(FTy, Callee, Args, Name, FPMathTag); } CallInst *CreateCall(llvm::FunctionType *FTy, Value *Callee, ArrayRef Args, const Twine &Name = "", MDNode *FPMathTag = nullptr) { CallInst *CI = CallInst::Create(FTy, Callee, Args, DefaultOperandBundles); + if (isa(CI)) + CI = cast(AddFPMathAttributes(CI, FPMathTag, FMF)); + return Insert(CI, Name); + } + + CallInst *CreateCall(Value *Callee, ArrayRef Args, + ArrayRef OpBundles, + const Twine &Name = "", MDNode *FPMathTag = nullptr) { + CallInst *CI = CallInst::Create(Callee, Args, OpBundles); if (isa(CI)) CI = cast(AddFPMathAttributes(CI, FPMathTag, FMF)); return Insert(CI, Name); } CallInst *CreateCall(Function *Callee, ArrayRef Args, const Twine &Name = "", MDNode *FPMathTag = nullptr) { return CreateCall(Callee->getFunctionType(), Callee, Args, Name, FPMathTag); } Value *CreateSelect(Value *C, Value *True, Value *False, const Twine &Name = "") { if (Constant *CC = dyn_cast(C)) if (Constant *TC = dyn_cast(True)) if (Constant *FC = dyn_cast(False)) return Insert(Folder.CreateSelect(CC, TC, FC), Name); return Insert(SelectInst::Create(C, True, False), Name); } VAArgInst *CreateVAArg(Value *List, Type *Ty, const Twine &Name = "") { return Insert(new VAArgInst(List, Ty), Name); } Value *CreateExtractElement(Value *Vec, Value *Idx, const Twine &Name = "") { if (Constant *VC = dyn_cast(Vec)) if (Constant *IC = dyn_cast(Idx)) return Insert(Folder.CreateExtractElement(VC, IC), Name); return Insert(ExtractElementInst::Create(Vec, Idx), Name); } Value *CreateExtractElement(Value *Vec, uint64_t Idx, const Twine &Name = "") { return CreateExtractElement(Vec, getInt64(Idx), Name); } Value *CreateInsertElement(Value *Vec, Value *NewElt, Value *Idx, const Twine &Name = "") { if (Constant *VC = dyn_cast(Vec)) if (Constant *NC = dyn_cast(NewElt)) if (Constant *IC = dyn_cast(Idx)) return Insert(Folder.CreateInsertElement(VC, NC, IC), Name); return Insert(InsertElementInst::Create(Vec, NewElt, Idx), Name); } Value *CreateInsertElement(Value *Vec, Value *NewElt, uint64_t Idx, const Twine &Name = "") { return CreateInsertElement(Vec, NewElt, getInt64(Idx), Name); } Value *CreateShuffleVector(Value *V1, Value *V2, Value *Mask, const Twine &Name = "") { if (Constant *V1C = dyn_cast(V1)) if (Constant *V2C = dyn_cast(V2)) if (Constant *MC = dyn_cast(Mask)) return Insert(Folder.CreateShuffleVector(V1C, V2C, MC), Name); return Insert(new ShuffleVectorInst(V1, V2, Mask), Name); } Value *CreateShuffleVector(Value *V1, Value *V2, ArrayRef IntMask, const Twine &Name = "") { size_t MaskSize = IntMask.size(); SmallVector MaskVec(MaskSize); for (size_t i = 0; i != MaskSize; ++i) MaskVec[i] = getInt32(IntMask[i]); Value *Mask = ConstantVector::get(MaskVec); return CreateShuffleVector(V1, V2, Mask, Name); } Value *CreateExtractValue(Value *Agg, ArrayRef Idxs, const Twine &Name = "") { if (Constant *AggC = dyn_cast(Agg)) return Insert(Folder.CreateExtractValue(AggC, Idxs), Name); return Insert(ExtractValueInst::Create(Agg, Idxs), Name); } Value *CreateInsertValue(Value *Agg, Value *Val, ArrayRef Idxs, const Twine &Name = "") { if (Constant *AggC = dyn_cast(Agg)) if (Constant *ValC = dyn_cast(Val)) return Insert(Folder.CreateInsertValue(AggC, ValC, Idxs), Name); return Insert(InsertValueInst::Create(Agg, Val, Idxs), Name); } LandingPadInst *CreateLandingPad(Type *Ty, unsigned NumClauses, const Twine &Name = "") { return Insert(LandingPadInst::Create(Ty, NumClauses), Name); } //===--------------------------------------------------------------------===// // Utility creation methods //===--------------------------------------------------------------------===// /// \brief Return an i1 value testing if \p Arg is null. Value *CreateIsNull(Value *Arg, const Twine &Name = "") { return CreateICmpEQ(Arg, Constant::getNullValue(Arg->getType()), Name); } /// \brief Return an i1 value testing if \p Arg is not null. Value *CreateIsNotNull(Value *Arg, const Twine &Name = "") { return CreateICmpNE(Arg, Constant::getNullValue(Arg->getType()), Name); } /// \brief Return the i64 difference between two pointer values, dividing out /// the size of the pointed-to objects. /// /// This is intended to implement C-style pointer subtraction. As such, the /// pointers must be appropriately aligned for their element types and /// pointing into the same object. Value *CreatePtrDiff(Value *LHS, Value *RHS, const Twine &Name = "") { assert(LHS->getType() == RHS->getType() && "Pointer subtraction operand types must match!"); PointerType *ArgType = cast(LHS->getType()); Value *LHS_int = CreatePtrToInt(LHS, Type::getInt64Ty(Context)); Value *RHS_int = CreatePtrToInt(RHS, Type::getInt64Ty(Context)); Value *Difference = CreateSub(LHS_int, RHS_int); return CreateExactSDiv(Difference, ConstantExpr::getSizeOf(ArgType->getElementType()), Name); } /// \brief Create an invariant.group.barrier intrinsic call, that stops /// optimizer to propagate equality using invariant.group metadata. /// If Ptr type is different from i8*, it's casted to i8* before call /// and casted back to Ptr type after call. Value *CreateInvariantGroupBarrier(Value *Ptr) { Module *M = BB->getParent()->getParent(); Function *FnInvariantGroupBarrier = Intrinsic::getDeclaration(M, Intrinsic::invariant_group_barrier); Type *ArgumentAndReturnType = FnInvariantGroupBarrier->getReturnType(); assert(ArgumentAndReturnType == FnInvariantGroupBarrier->getFunctionType()->getParamType(0) && "InvariantGroupBarrier should take and return the same type"); Type *PtrType = Ptr->getType(); bool PtrTypeConversionNeeded = PtrType != ArgumentAndReturnType; if (PtrTypeConversionNeeded) Ptr = CreateBitCast(Ptr, ArgumentAndReturnType); CallInst *Fn = CreateCall(FnInvariantGroupBarrier, {Ptr}); if (PtrTypeConversionNeeded) return CreateBitCast(Fn, PtrType); return Fn; } /// \brief Return a vector value that contains \arg V broadcasted to \p /// NumElts elements. Value *CreateVectorSplat(unsigned NumElts, Value *V, const Twine &Name = "") { assert(NumElts > 0 && "Cannot splat to an empty vector!"); // First insert it into an undef vector so we can shuffle it. Type *I32Ty = getInt32Ty(); Value *Undef = UndefValue::get(VectorType::get(V->getType(), NumElts)); V = CreateInsertElement(Undef, V, ConstantInt::get(I32Ty, 0), Name + ".splatinsert"); // Shuffle the value across the desired number of elements. Value *Zeros = ConstantAggregateZero::get(VectorType::get(I32Ty, NumElts)); return CreateShuffleVector(V, Undef, Zeros, Name + ".splat"); } /// \brief Return a value that has been extracted from a larger integer type. Value *CreateExtractInteger(const DataLayout &DL, Value *From, IntegerType *ExtractedTy, uint64_t Offset, const Twine &Name) { IntegerType *IntTy = cast(From->getType()); assert(DL.getTypeStoreSize(ExtractedTy) + Offset <= DL.getTypeStoreSize(IntTy) && "Element extends past full value"); uint64_t ShAmt = 8 * Offset; Value *V = From; if (DL.isBigEndian()) ShAmt = 8 * (DL.getTypeStoreSize(IntTy) - DL.getTypeStoreSize(ExtractedTy) - Offset); if (ShAmt) { V = CreateLShr(V, ShAmt, Name + ".shift"); } assert(ExtractedTy->getBitWidth() <= IntTy->getBitWidth() && "Cannot extract to a larger integer!"); if (ExtractedTy != IntTy) { V = CreateTrunc(V, ExtractedTy, Name + ".trunc"); } return V; } /// \brief Create an assume intrinsic call that represents an alignment /// assumption on the provided pointer. /// /// An optional offset can be provided, and if it is provided, the offset /// must be subtracted from the provided pointer to get the pointer with the /// specified alignment. CallInst *CreateAlignmentAssumption(const DataLayout &DL, Value *PtrValue, unsigned Alignment, Value *OffsetValue = nullptr) { assert(isa(PtrValue->getType()) && "trying to create an alignment assumption on a non-pointer?"); PointerType *PtrTy = cast(PtrValue->getType()); Type *IntPtrTy = getIntPtrTy(DL, PtrTy->getAddressSpace()); Value *PtrIntValue = CreatePtrToInt(PtrValue, IntPtrTy, "ptrint"); Value *Mask = ConstantInt::get(IntPtrTy, Alignment > 0 ? Alignment - 1 : 0); if (OffsetValue) { bool IsOffsetZero = false; if (ConstantInt *CI = dyn_cast(OffsetValue)) IsOffsetZero = CI->isZero(); if (!IsOffsetZero) { if (OffsetValue->getType() != IntPtrTy) OffsetValue = CreateIntCast(OffsetValue, IntPtrTy, /*isSigned*/ true, "offsetcast"); PtrIntValue = CreateSub(PtrIntValue, OffsetValue, "offsetptr"); } } Value *Zero = ConstantInt::get(IntPtrTy, 0); Value *MaskedPtr = CreateAnd(PtrIntValue, Mask, "maskedptr"); Value *InvCond = CreateICmpEQ(MaskedPtr, Zero, "maskcond"); return CreateAssumption(InvCond); } }; // Create wrappers for C Binding types (see CBindingWrapping.h). DEFINE_SIMPLE_CONVERSION_FUNCTIONS(IRBuilder<>, LLVMBuilderRef) } // end namespace llvm #endif // LLVM_IR_IRBUILDER_H Index: projects/clang380-import/contrib/llvm/include/llvm/IR/Instructions.h =================================================================== --- projects/clang380-import/contrib/llvm/include/llvm/IR/Instructions.h (revision 295858) +++ projects/clang380-import/contrib/llvm/include/llvm/IR/Instructions.h (revision 295859) @@ -1,4825 +1,4833 @@ //===-- llvm/Instructions.h - Instruction subclass definitions --*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file exposes the class definitions of all of the subclasses of the // Instruction class. This is meant to be an easy way to get access to all // instruction subclasses. // //===----------------------------------------------------------------------===// #ifndef LLVM_IR_INSTRUCTIONS_H #define LLVM_IR_INSTRUCTIONS_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/InstrTypes.h" #include "llvm/Support/ErrorHandling.h" #include namespace llvm { class APInt; class ConstantInt; class ConstantRange; class DataLayout; class LLVMContext; enum AtomicOrdering { NotAtomic = 0, Unordered = 1, Monotonic = 2, // Consume = 3, // Not specified yet. Acquire = 4, Release = 5, AcquireRelease = 6, SequentiallyConsistent = 7 }; enum SynchronizationScope { SingleThread = 0, CrossThread = 1 }; /// Returns true if the ordering is at least as strong as acquire /// (i.e. acquire, acq_rel or seq_cst) inline bool isAtLeastAcquire(AtomicOrdering Ord) { return (Ord == Acquire || Ord == AcquireRelease || Ord == SequentiallyConsistent); } /// Returns true if the ordering is at least as strong as release /// (i.e. release, acq_rel or seq_cst) inline bool isAtLeastRelease(AtomicOrdering Ord) { return (Ord == Release || Ord == AcquireRelease || Ord == SequentiallyConsistent); } //===----------------------------------------------------------------------===// // AllocaInst Class //===----------------------------------------------------------------------===// /// AllocaInst - an instruction to allocate memory on the stack /// class AllocaInst : public UnaryInstruction { Type *AllocatedType; protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; AllocaInst *cloneImpl() const; public: explicit AllocaInst(Type *Ty, Value *ArraySize = nullptr, const Twine &Name = "", Instruction *InsertBefore = nullptr); AllocaInst(Type *Ty, Value *ArraySize, const Twine &Name, BasicBlock *InsertAtEnd); AllocaInst(Type *Ty, const Twine &Name, Instruction *InsertBefore = nullptr); AllocaInst(Type *Ty, const Twine &Name, BasicBlock *InsertAtEnd); AllocaInst(Type *Ty, Value *ArraySize, unsigned Align, const Twine &Name = "", Instruction *InsertBefore = nullptr); AllocaInst(Type *Ty, Value *ArraySize, unsigned Align, const Twine &Name, BasicBlock *InsertAtEnd); // Out of line virtual method, so the vtable, etc. has a home. ~AllocaInst() override; /// isArrayAllocation - Return true if there is an allocation size parameter /// to the allocation instruction that is not 1. /// bool isArrayAllocation() const; /// getArraySize - Get the number of elements allocated. For a simple /// allocation of a single element, this will return a constant 1 value. /// const Value *getArraySize() const { return getOperand(0); } Value *getArraySize() { return getOperand(0); } /// getType - Overload to return most specific pointer type /// PointerType *getType() const { return cast(Instruction::getType()); } /// getAllocatedType - Return the type that is being allocated by the /// instruction. /// Type *getAllocatedType() const { return AllocatedType; } /// \brief for use only in special circumstances that need to generically /// transform a whole instruction (eg: IR linking and vectorization). void setAllocatedType(Type *Ty) { AllocatedType = Ty; } /// getAlignment - Return the alignment of the memory that is being allocated /// by the instruction. /// unsigned getAlignment() const { return (1u << (getSubclassDataFromInstruction() & 31)) >> 1; } void setAlignment(unsigned Align); /// isStaticAlloca - Return true if this alloca is in the entry block of the /// function and is a constant size. If so, the code generator will fold it /// into the prolog/epilog code, so it is basically free. bool isStaticAlloca() const; /// \brief Return true if this alloca is used as an inalloca argument to a /// call. Such allocas are never considered static even if they are in the /// entry block. bool isUsedWithInAlloca() const { return getSubclassDataFromInstruction() & 32; } /// \brief Specify whether this alloca is used to represent the arguments to /// a call. void setUsedWithInAlloca(bool V) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~32) | (V ? 32 : 0)); } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return (I->getOpcode() == Instruction::Alloca); } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: // Shadow Instruction::setInstructionSubclassData with a private forwarding // method so that subclasses cannot accidentally use it. void setInstructionSubclassData(unsigned short D) { Instruction::setInstructionSubclassData(D); } }; //===----------------------------------------------------------------------===// // LoadInst Class //===----------------------------------------------------------------------===// /// LoadInst - an instruction for reading from memory. This uses the /// SubclassData field in Value to store whether or not the load is volatile. /// class LoadInst : public UnaryInstruction { void AssertOK(); protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; LoadInst *cloneImpl() const; public: LoadInst(Value *Ptr, const Twine &NameStr, Instruction *InsertBefore); LoadInst(Value *Ptr, const Twine &NameStr, BasicBlock *InsertAtEnd); LoadInst(Type *Ty, Value *Ptr, const Twine &NameStr, bool isVolatile = false, Instruction *InsertBefore = nullptr); LoadInst(Value *Ptr, const Twine &NameStr, bool isVolatile = false, Instruction *InsertBefore = nullptr) : LoadInst(cast(Ptr->getType())->getElementType(), Ptr, NameStr, isVolatile, InsertBefore) {} LoadInst(Value *Ptr, const Twine &NameStr, bool isVolatile, BasicBlock *InsertAtEnd); LoadInst(Value *Ptr, const Twine &NameStr, bool isVolatile, unsigned Align, Instruction *InsertBefore = nullptr) : LoadInst(cast(Ptr->getType())->getElementType(), Ptr, NameStr, isVolatile, Align, InsertBefore) {} LoadInst(Type *Ty, Value *Ptr, const Twine &NameStr, bool isVolatile, unsigned Align, Instruction *InsertBefore = nullptr); LoadInst(Value *Ptr, const Twine &NameStr, bool isVolatile, unsigned Align, BasicBlock *InsertAtEnd); LoadInst(Value *Ptr, const Twine &NameStr, bool isVolatile, unsigned Align, AtomicOrdering Order, SynchronizationScope SynchScope = CrossThread, Instruction *InsertBefore = nullptr) : LoadInst(cast(Ptr->getType())->getElementType(), Ptr, NameStr, isVolatile, Align, Order, SynchScope, InsertBefore) {} LoadInst(Type *Ty, Value *Ptr, const Twine &NameStr, bool isVolatile, unsigned Align, AtomicOrdering Order, SynchronizationScope SynchScope = CrossThread, Instruction *InsertBefore = nullptr); LoadInst(Value *Ptr, const Twine &NameStr, bool isVolatile, unsigned Align, AtomicOrdering Order, SynchronizationScope SynchScope, BasicBlock *InsertAtEnd); LoadInst(Value *Ptr, const char *NameStr, Instruction *InsertBefore); LoadInst(Value *Ptr, const char *NameStr, BasicBlock *InsertAtEnd); LoadInst(Type *Ty, Value *Ptr, const char *NameStr = nullptr, bool isVolatile = false, Instruction *InsertBefore = nullptr); explicit LoadInst(Value *Ptr, const char *NameStr = nullptr, bool isVolatile = false, Instruction *InsertBefore = nullptr) : LoadInst(cast(Ptr->getType())->getElementType(), Ptr, NameStr, isVolatile, InsertBefore) {} LoadInst(Value *Ptr, const char *NameStr, bool isVolatile, BasicBlock *InsertAtEnd); /// isVolatile - Return true if this is a load from a volatile memory /// location. /// bool isVolatile() const { return getSubclassDataFromInstruction() & 1; } /// setVolatile - Specify whether this is a volatile load or not. /// void setVolatile(bool V) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~1) | (V ? 1 : 0)); } /// getAlignment - Return the alignment of the access that is being performed /// unsigned getAlignment() const { return (1 << ((getSubclassDataFromInstruction() >> 1) & 31)) >> 1; } void setAlignment(unsigned Align); /// Returns the ordering effect of this fence. AtomicOrdering getOrdering() const { return AtomicOrdering((getSubclassDataFromInstruction() >> 7) & 7); } /// Set the ordering constraint on this load. May not be Release or /// AcquireRelease. void setOrdering(AtomicOrdering Ordering) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 7)) | (Ordering << 7)); } SynchronizationScope getSynchScope() const { return SynchronizationScope((getSubclassDataFromInstruction() >> 6) & 1); } /// Specify whether this load is ordered with respect to all /// concurrently executing threads, or only with respect to signal handlers /// executing in the same thread. void setSynchScope(SynchronizationScope xthread) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~(1 << 6)) | (xthread << 6)); } void setAtomic(AtomicOrdering Ordering, SynchronizationScope SynchScope = CrossThread) { setOrdering(Ordering); setSynchScope(SynchScope); } bool isSimple() const { return !isAtomic() && !isVolatile(); } bool isUnordered() const { return getOrdering() <= Unordered && !isVolatile(); } Value *getPointerOperand() { return getOperand(0); } const Value *getPointerOperand() const { return getOperand(0); } static unsigned getPointerOperandIndex() { return 0U; } /// \brief Returns the address space of the pointer operand. unsigned getPointerAddressSpace() const { return getPointerOperand()->getType()->getPointerAddressSpace(); } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::Load; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: // Shadow Instruction::setInstructionSubclassData with a private forwarding // method so that subclasses cannot accidentally use it. void setInstructionSubclassData(unsigned short D) { Instruction::setInstructionSubclassData(D); } }; //===----------------------------------------------------------------------===// // StoreInst Class //===----------------------------------------------------------------------===// /// StoreInst - an instruction for storing to memory /// class StoreInst : public Instruction { void *operator new(size_t, unsigned) = delete; void AssertOK(); protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; StoreInst *cloneImpl() const; public: // allocate space for exactly two operands void *operator new(size_t s) { return User::operator new(s, 2); } StoreInst(Value *Val, Value *Ptr, Instruction *InsertBefore); StoreInst(Value *Val, Value *Ptr, BasicBlock *InsertAtEnd); StoreInst(Value *Val, Value *Ptr, bool isVolatile = false, Instruction *InsertBefore = nullptr); StoreInst(Value *Val, Value *Ptr, bool isVolatile, BasicBlock *InsertAtEnd); StoreInst(Value *Val, Value *Ptr, bool isVolatile, unsigned Align, Instruction *InsertBefore = nullptr); StoreInst(Value *Val, Value *Ptr, bool isVolatile, unsigned Align, BasicBlock *InsertAtEnd); StoreInst(Value *Val, Value *Ptr, bool isVolatile, unsigned Align, AtomicOrdering Order, SynchronizationScope SynchScope = CrossThread, Instruction *InsertBefore = nullptr); StoreInst(Value *Val, Value *Ptr, bool isVolatile, unsigned Align, AtomicOrdering Order, SynchronizationScope SynchScope, BasicBlock *InsertAtEnd); /// isVolatile - Return true if this is a store to a volatile memory /// location. /// bool isVolatile() const { return getSubclassDataFromInstruction() & 1; } /// setVolatile - Specify whether this is a volatile store or not. /// void setVolatile(bool V) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~1) | (V ? 1 : 0)); } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); /// getAlignment - Return the alignment of the access that is being performed /// unsigned getAlignment() const { return (1 << ((getSubclassDataFromInstruction() >> 1) & 31)) >> 1; } void setAlignment(unsigned Align); /// Returns the ordering effect of this store. AtomicOrdering getOrdering() const { return AtomicOrdering((getSubclassDataFromInstruction() >> 7) & 7); } /// Set the ordering constraint on this store. May not be Acquire or /// AcquireRelease. void setOrdering(AtomicOrdering Ordering) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 7)) | (Ordering << 7)); } SynchronizationScope getSynchScope() const { return SynchronizationScope((getSubclassDataFromInstruction() >> 6) & 1); } /// Specify whether this store instruction is ordered with respect to all /// concurrently executing threads, or only with respect to signal handlers /// executing in the same thread. void setSynchScope(SynchronizationScope xthread) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~(1 << 6)) | (xthread << 6)); } void setAtomic(AtomicOrdering Ordering, SynchronizationScope SynchScope = CrossThread) { setOrdering(Ordering); setSynchScope(SynchScope); } bool isSimple() const { return !isAtomic() && !isVolatile(); } bool isUnordered() const { return getOrdering() <= Unordered && !isVolatile(); } Value *getValueOperand() { return getOperand(0); } const Value *getValueOperand() const { return getOperand(0); } Value *getPointerOperand() { return getOperand(1); } const Value *getPointerOperand() const { return getOperand(1); } static unsigned getPointerOperandIndex() { return 1U; } /// \brief Returns the address space of the pointer operand. unsigned getPointerAddressSpace() const { return getPointerOperand()->getType()->getPointerAddressSpace(); } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::Store; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: // Shadow Instruction::setInstructionSubclassData with a private forwarding // method so that subclasses cannot accidentally use it. void setInstructionSubclassData(unsigned short D) { Instruction::setInstructionSubclassData(D); } }; template <> struct OperandTraits : public FixedNumOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(StoreInst, Value) //===----------------------------------------------------------------------===// // FenceInst Class //===----------------------------------------------------------------------===// /// FenceInst - an instruction for ordering other memory operations /// class FenceInst : public Instruction { void *operator new(size_t, unsigned) = delete; void Init(AtomicOrdering Ordering, SynchronizationScope SynchScope); protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; FenceInst *cloneImpl() const; public: // allocate space for exactly zero operands void *operator new(size_t s) { return User::operator new(s, 0); } // Ordering may only be Acquire, Release, AcquireRelease, or // SequentiallyConsistent. FenceInst(LLVMContext &C, AtomicOrdering Ordering, SynchronizationScope SynchScope = CrossThread, Instruction *InsertBefore = nullptr); FenceInst(LLVMContext &C, AtomicOrdering Ordering, SynchronizationScope SynchScope, BasicBlock *InsertAtEnd); /// Returns the ordering effect of this fence. AtomicOrdering getOrdering() const { return AtomicOrdering(getSubclassDataFromInstruction() >> 1); } /// Set the ordering constraint on this fence. May only be Acquire, Release, /// AcquireRelease, or SequentiallyConsistent. void setOrdering(AtomicOrdering Ordering) { setInstructionSubclassData((getSubclassDataFromInstruction() & 1) | (Ordering << 1)); } SynchronizationScope getSynchScope() const { return SynchronizationScope(getSubclassDataFromInstruction() & 1); } /// Specify whether this fence orders other operations with respect to all /// concurrently executing threads, or only with respect to signal handlers /// executing in the same thread. void setSynchScope(SynchronizationScope xthread) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~1) | xthread); } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::Fence; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: // Shadow Instruction::setInstructionSubclassData with a private forwarding // method so that subclasses cannot accidentally use it. void setInstructionSubclassData(unsigned short D) { Instruction::setInstructionSubclassData(D); } }; //===----------------------------------------------------------------------===// // AtomicCmpXchgInst Class //===----------------------------------------------------------------------===// /// AtomicCmpXchgInst - an instruction that atomically checks whether a /// specified value is in a memory location, and, if it is, stores a new value /// there. Returns the value that was loaded. /// class AtomicCmpXchgInst : public Instruction { void *operator new(size_t, unsigned) = delete; void Init(Value *Ptr, Value *Cmp, Value *NewVal, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, SynchronizationScope SynchScope); protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; AtomicCmpXchgInst *cloneImpl() const; public: // allocate space for exactly three operands void *operator new(size_t s) { return User::operator new(s, 3); } AtomicCmpXchgInst(Value *Ptr, Value *Cmp, Value *NewVal, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, SynchronizationScope SynchScope, Instruction *InsertBefore = nullptr); AtomicCmpXchgInst(Value *Ptr, Value *Cmp, Value *NewVal, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, SynchronizationScope SynchScope, BasicBlock *InsertAtEnd); /// isVolatile - Return true if this is a cmpxchg from a volatile memory /// location. /// bool isVolatile() const { return getSubclassDataFromInstruction() & 1; } /// setVolatile - Specify whether this is a volatile cmpxchg. /// void setVolatile(bool V) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~1) | (unsigned)V); } /// Return true if this cmpxchg may spuriously fail. bool isWeak() const { return getSubclassDataFromInstruction() & 0x100; } void setWeak(bool IsWeak) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~0x100) | (IsWeak << 8)); } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); /// Set the ordering constraint on this cmpxchg. void setSuccessOrdering(AtomicOrdering Ordering) { assert(Ordering != NotAtomic && "CmpXchg instructions can only be atomic."); setInstructionSubclassData((getSubclassDataFromInstruction() & ~0x1c) | (Ordering << 2)); } void setFailureOrdering(AtomicOrdering Ordering) { assert(Ordering != NotAtomic && "CmpXchg instructions can only be atomic."); setInstructionSubclassData((getSubclassDataFromInstruction() & ~0xe0) | (Ordering << 5)); } /// Specify whether this cmpxchg is atomic and orders other operations with /// respect to all concurrently executing threads, or only with respect to /// signal handlers executing in the same thread. void setSynchScope(SynchronizationScope SynchScope) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~2) | (SynchScope << 1)); } /// Returns the ordering constraint on this cmpxchg. AtomicOrdering getSuccessOrdering() const { return AtomicOrdering((getSubclassDataFromInstruction() >> 2) & 7); } /// Returns the ordering constraint on this cmpxchg. AtomicOrdering getFailureOrdering() const { return AtomicOrdering((getSubclassDataFromInstruction() >> 5) & 7); } /// Returns whether this cmpxchg is atomic between threads or only within a /// single thread. SynchronizationScope getSynchScope() const { return SynchronizationScope((getSubclassDataFromInstruction() & 2) >> 1); } Value *getPointerOperand() { return getOperand(0); } const Value *getPointerOperand() const { return getOperand(0); } static unsigned getPointerOperandIndex() { return 0U; } Value *getCompareOperand() { return getOperand(1); } const Value *getCompareOperand() const { return getOperand(1); } Value *getNewValOperand() { return getOperand(2); } const Value *getNewValOperand() const { return getOperand(2); } /// \brief Returns the address space of the pointer operand. unsigned getPointerAddressSpace() const { return getPointerOperand()->getType()->getPointerAddressSpace(); } /// \brief Returns the strongest permitted ordering on failure, given the /// desired ordering on success. /// /// If the comparison in a cmpxchg operation fails, there is no atomic store /// so release semantics cannot be provided. So this function drops explicit /// Release requests from the AtomicOrdering. A SequentiallyConsistent /// operation would remain SequentiallyConsistent. static AtomicOrdering getStrongestFailureOrdering(AtomicOrdering SuccessOrdering) { switch (SuccessOrdering) { default: llvm_unreachable("invalid cmpxchg success ordering"); case Release: case Monotonic: return Monotonic; case AcquireRelease: case Acquire: return Acquire; case SequentiallyConsistent: return SequentiallyConsistent; } } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::AtomicCmpXchg; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: // Shadow Instruction::setInstructionSubclassData with a private forwarding // method so that subclasses cannot accidentally use it. void setInstructionSubclassData(unsigned short D) { Instruction::setInstructionSubclassData(D); } }; template <> struct OperandTraits : public FixedNumOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(AtomicCmpXchgInst, Value) //===----------------------------------------------------------------------===// // AtomicRMWInst Class //===----------------------------------------------------------------------===// /// AtomicRMWInst - an instruction that atomically reads a memory location, /// combines it with another value, and then stores the result back. Returns /// the old value. /// class AtomicRMWInst : public Instruction { void *operator new(size_t, unsigned) = delete; protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; AtomicRMWInst *cloneImpl() const; public: /// This enumeration lists the possible modifications atomicrmw can make. In /// the descriptions, 'p' is the pointer to the instruction's memory location, /// 'old' is the initial value of *p, and 'v' is the other value passed to the /// instruction. These instructions always return 'old'. enum BinOp { /// *p = v Xchg, /// *p = old + v Add, /// *p = old - v Sub, /// *p = old & v And, /// *p = ~(old & v) Nand, /// *p = old | v Or, /// *p = old ^ v Xor, /// *p = old >signed v ? old : v Max, /// *p = old unsigned v ? old : v UMax, /// *p = old (getSubclassDataFromInstruction() >> 5); } void setOperation(BinOp Operation) { unsigned short SubclassData = getSubclassDataFromInstruction(); setInstructionSubclassData((SubclassData & 31) | (Operation << 5)); } /// isVolatile - Return true if this is a RMW on a volatile memory location. /// bool isVolatile() const { return getSubclassDataFromInstruction() & 1; } /// setVolatile - Specify whether this is a volatile RMW or not. /// void setVolatile(bool V) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~1) | (unsigned)V); } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); /// Set the ordering constraint on this RMW. void setOrdering(AtomicOrdering Ordering) { assert(Ordering != NotAtomic && "atomicrmw instructions can only be atomic."); setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 2)) | (Ordering << 2)); } /// Specify whether this RMW orders other operations with respect to all /// concurrently executing threads, or only with respect to signal handlers /// executing in the same thread. void setSynchScope(SynchronizationScope SynchScope) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~2) | (SynchScope << 1)); } /// Returns the ordering constraint on this RMW. AtomicOrdering getOrdering() const { return AtomicOrdering((getSubclassDataFromInstruction() >> 2) & 7); } /// Returns whether this RMW is atomic between threads or only within a /// single thread. SynchronizationScope getSynchScope() const { return SynchronizationScope((getSubclassDataFromInstruction() & 2) >> 1); } Value *getPointerOperand() { return getOperand(0); } const Value *getPointerOperand() const { return getOperand(0); } static unsigned getPointerOperandIndex() { return 0U; } Value *getValOperand() { return getOperand(1); } const Value *getValOperand() const { return getOperand(1); } /// \brief Returns the address space of the pointer operand. unsigned getPointerAddressSpace() const { return getPointerOperand()->getType()->getPointerAddressSpace(); } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::AtomicRMW; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: void Init(BinOp Operation, Value *Ptr, Value *Val, AtomicOrdering Ordering, SynchronizationScope SynchScope); // Shadow Instruction::setInstructionSubclassData with a private forwarding // method so that subclasses cannot accidentally use it. void setInstructionSubclassData(unsigned short D) { Instruction::setInstructionSubclassData(D); } }; template <> struct OperandTraits : public FixedNumOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(AtomicRMWInst, Value) //===----------------------------------------------------------------------===// // GetElementPtrInst Class //===----------------------------------------------------------------------===// // checkGEPType - Simple wrapper function to give a better assertion failure // message on bad indexes for a gep instruction. // inline Type *checkGEPType(Type *Ty) { assert(Ty && "Invalid GetElementPtrInst indices for type!"); return Ty; } /// GetElementPtrInst - an instruction for type-safe pointer arithmetic to /// access elements of arrays and structs /// class GetElementPtrInst : public Instruction { Type *SourceElementType; Type *ResultElementType; void anchor() override; GetElementPtrInst(const GetElementPtrInst &GEPI); void init(Value *Ptr, ArrayRef IdxList, const Twine &NameStr); /// Constructors - Create a getelementptr instruction with a base pointer an /// list of indices. The first ctor can optionally insert before an existing /// instruction, the second appends the new instruction to the specified /// BasicBlock. inline GetElementPtrInst(Type *PointeeType, Value *Ptr, ArrayRef IdxList, unsigned Values, const Twine &NameStr, Instruction *InsertBefore); inline GetElementPtrInst(Type *PointeeType, Value *Ptr, ArrayRef IdxList, unsigned Values, const Twine &NameStr, BasicBlock *InsertAtEnd); protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; GetElementPtrInst *cloneImpl() const; public: static GetElementPtrInst *Create(Type *PointeeType, Value *Ptr, ArrayRef IdxList, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { unsigned Values = 1 + unsigned(IdxList.size()); if (!PointeeType) PointeeType = cast(Ptr->getType()->getScalarType())->getElementType(); else assert( PointeeType == cast(Ptr->getType()->getScalarType())->getElementType()); return new (Values) GetElementPtrInst(PointeeType, Ptr, IdxList, Values, NameStr, InsertBefore); } static GetElementPtrInst *Create(Type *PointeeType, Value *Ptr, ArrayRef IdxList, const Twine &NameStr, BasicBlock *InsertAtEnd) { unsigned Values = 1 + unsigned(IdxList.size()); if (!PointeeType) PointeeType = cast(Ptr->getType()->getScalarType())->getElementType(); else assert( PointeeType == cast(Ptr->getType()->getScalarType())->getElementType()); return new (Values) GetElementPtrInst(PointeeType, Ptr, IdxList, Values, NameStr, InsertAtEnd); } /// Create an "inbounds" getelementptr. See the documentation for the /// "inbounds" flag in LangRef.html for details. static GetElementPtrInst *CreateInBounds(Value *Ptr, ArrayRef IdxList, const Twine &NameStr = "", Instruction *InsertBefore = nullptr){ return CreateInBounds(nullptr, Ptr, IdxList, NameStr, InsertBefore); } static GetElementPtrInst * CreateInBounds(Type *PointeeType, Value *Ptr, ArrayRef IdxList, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { GetElementPtrInst *GEP = Create(PointeeType, Ptr, IdxList, NameStr, InsertBefore); GEP->setIsInBounds(true); return GEP; } static GetElementPtrInst *CreateInBounds(Value *Ptr, ArrayRef IdxList, const Twine &NameStr, BasicBlock *InsertAtEnd) { return CreateInBounds(nullptr, Ptr, IdxList, NameStr, InsertAtEnd); } static GetElementPtrInst *CreateInBounds(Type *PointeeType, Value *Ptr, ArrayRef IdxList, const Twine &NameStr, BasicBlock *InsertAtEnd) { GetElementPtrInst *GEP = Create(PointeeType, Ptr, IdxList, NameStr, InsertAtEnd); GEP->setIsInBounds(true); return GEP; } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); // getType - Overload to return most specific sequential type. SequentialType *getType() const { return cast(Instruction::getType()); } Type *getSourceElementType() const { return SourceElementType; } void setSourceElementType(Type *Ty) { SourceElementType = Ty; } void setResultElementType(Type *Ty) { ResultElementType = Ty; } Type *getResultElementType() const { assert(ResultElementType == cast(getType()->getScalarType())->getElementType()); return ResultElementType; } /// \brief Returns the address space of this instruction's pointer type. unsigned getAddressSpace() const { // Note that this is always the same as the pointer operand's address space // and that is cheaper to compute, so cheat here. return getPointerAddressSpace(); } /// getIndexedType - Returns the type of the element that would be loaded with /// a load instruction with the specified parameters. /// /// Null is returned if the indices are invalid for the specified /// pointer type. /// static Type *getIndexedType(Type *Ty, ArrayRef IdxList); static Type *getIndexedType(Type *Ty, ArrayRef IdxList); static Type *getIndexedType(Type *Ty, ArrayRef IdxList); inline op_iterator idx_begin() { return op_begin()+1; } inline const_op_iterator idx_begin() const { return op_begin()+1; } inline op_iterator idx_end() { return op_end(); } inline const_op_iterator idx_end() const { return op_end(); } Value *getPointerOperand() { return getOperand(0); } const Value *getPointerOperand() const { return getOperand(0); } static unsigned getPointerOperandIndex() { return 0U; // get index for modifying correct operand. } /// getPointerOperandType - Method to return the pointer operand as a /// PointerType. Type *getPointerOperandType() const { return getPointerOperand()->getType(); } /// \brief Returns the address space of the pointer operand. unsigned getPointerAddressSpace() const { return getPointerOperandType()->getPointerAddressSpace(); } /// GetGEPReturnType - Returns the pointer type returned by the GEP /// instruction, which may be a vector of pointers. static Type *getGEPReturnType(Value *Ptr, ArrayRef IdxList) { return getGEPReturnType( cast(Ptr->getType()->getScalarType())->getElementType(), Ptr, IdxList); } static Type *getGEPReturnType(Type *ElTy, Value *Ptr, ArrayRef IdxList) { Type *PtrTy = PointerType::get(checkGEPType(getIndexedType(ElTy, IdxList)), Ptr->getType()->getPointerAddressSpace()); // Vector GEP if (Ptr->getType()->isVectorTy()) { unsigned NumElem = Ptr->getType()->getVectorNumElements(); return VectorType::get(PtrTy, NumElem); } for (Value *Index : IdxList) if (Index->getType()->isVectorTy()) { unsigned NumElem = Index->getType()->getVectorNumElements(); return VectorType::get(PtrTy, NumElem); } // Scalar GEP return PtrTy; } unsigned getNumIndices() const { // Note: always non-negative return getNumOperands() - 1; } bool hasIndices() const { return getNumOperands() > 1; } /// hasAllZeroIndices - Return true if all of the indices of this GEP are /// zeros. If so, the result pointer and the first operand have the same /// value, just potentially different types. bool hasAllZeroIndices() const; /// hasAllConstantIndices - Return true if all of the indices of this GEP are /// constant integers. If so, the result pointer and the first operand have /// a constant offset between them. bool hasAllConstantIndices() const; /// setIsInBounds - Set or clear the inbounds flag on this GEP instruction. /// See LangRef.html for the meaning of inbounds on a getelementptr. void setIsInBounds(bool b = true); /// isInBounds - Determine whether the GEP has the inbounds flag. bool isInBounds() const; /// \brief Accumulate the constant address offset of this GEP if possible. /// /// This routine accepts an APInt into which it will accumulate the constant /// offset of this GEP if the GEP is in fact constant. If the GEP is not /// all-constant, it returns false and the value of the offset APInt is /// undefined (it is *not* preserved!). The APInt passed into this routine /// must be at least as wide as the IntPtr type for the address space of /// the base GEP pointer. bool accumulateConstantOffset(const DataLayout &DL, APInt &Offset) const; // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return (I->getOpcode() == Instruction::GetElementPtr); } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; template <> struct OperandTraits : public VariadicOperandTraits { }; GetElementPtrInst::GetElementPtrInst(Type *PointeeType, Value *Ptr, ArrayRef IdxList, unsigned Values, const Twine &NameStr, Instruction *InsertBefore) : Instruction(getGEPReturnType(PointeeType, Ptr, IdxList), GetElementPtr, OperandTraits::op_end(this) - Values, Values, InsertBefore), SourceElementType(PointeeType), ResultElementType(getIndexedType(PointeeType, IdxList)) { assert(ResultElementType == cast(getType()->getScalarType())->getElementType()); init(Ptr, IdxList, NameStr); } GetElementPtrInst::GetElementPtrInst(Type *PointeeType, Value *Ptr, ArrayRef IdxList, unsigned Values, const Twine &NameStr, BasicBlock *InsertAtEnd) : Instruction(getGEPReturnType(PointeeType, Ptr, IdxList), GetElementPtr, OperandTraits::op_end(this) - Values, Values, InsertAtEnd), SourceElementType(PointeeType), ResultElementType(getIndexedType(PointeeType, IdxList)) { assert(ResultElementType == cast(getType()->getScalarType())->getElementType()); init(Ptr, IdxList, NameStr); } DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GetElementPtrInst, Value) //===----------------------------------------------------------------------===// // ICmpInst Class //===----------------------------------------------------------------------===// /// This instruction compares its operands according to the predicate given /// to the constructor. It only operates on integers or pointers. The operands /// must be identical types. /// \brief Represent an integer comparison operator. class ICmpInst: public CmpInst { void anchor() override; void AssertOK() { assert(getPredicate() >= CmpInst::FIRST_ICMP_PREDICATE && getPredicate() <= CmpInst::LAST_ICMP_PREDICATE && "Invalid ICmp predicate value"); assert(getOperand(0)->getType() == getOperand(1)->getType() && "Both operands to ICmp instruction are not of the same type!"); // Check that the operands are the right type assert((getOperand(0)->getType()->isIntOrIntVectorTy() || getOperand(0)->getType()->isPtrOrPtrVectorTy()) && "Invalid operand types for ICmp instruction"); } protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; /// \brief Clone an identical ICmpInst ICmpInst *cloneImpl() const; public: /// \brief Constructor with insert-before-instruction semantics. ICmpInst( Instruction *InsertBefore, ///< Where to insert Predicate pred, ///< The predicate to use for the comparison Value *LHS, ///< The left-hand-side of the expression Value *RHS, ///< The right-hand-side of the expression const Twine &NameStr = "" ///< Name of the instruction ) : CmpInst(makeCmpResultType(LHS->getType()), Instruction::ICmp, pred, LHS, RHS, NameStr, InsertBefore) { #ifndef NDEBUG AssertOK(); #endif } /// \brief Constructor with insert-at-end semantics. ICmpInst( BasicBlock &InsertAtEnd, ///< Block to insert into. Predicate pred, ///< The predicate to use for the comparison Value *LHS, ///< The left-hand-side of the expression Value *RHS, ///< The right-hand-side of the expression const Twine &NameStr = "" ///< Name of the instruction ) : CmpInst(makeCmpResultType(LHS->getType()), Instruction::ICmp, pred, LHS, RHS, NameStr, &InsertAtEnd) { #ifndef NDEBUG AssertOK(); #endif } /// \brief Constructor with no-insertion semantics ICmpInst( Predicate pred, ///< The predicate to use for the comparison Value *LHS, ///< The left-hand-side of the expression Value *RHS, ///< The right-hand-side of the expression const Twine &NameStr = "" ///< Name of the instruction ) : CmpInst(makeCmpResultType(LHS->getType()), Instruction::ICmp, pred, LHS, RHS, NameStr) { #ifndef NDEBUG AssertOK(); #endif } /// For example, EQ->EQ, SLE->SLE, UGT->SGT, etc. /// @returns the predicate that would be the result if the operand were /// regarded as signed. /// \brief Return the signed version of the predicate Predicate getSignedPredicate() const { return getSignedPredicate(getPredicate()); } /// This is a static version that you can use without an instruction. /// \brief Return the signed version of the predicate. static Predicate getSignedPredicate(Predicate pred); /// For example, EQ->EQ, SLE->ULE, UGT->UGT, etc. /// @returns the predicate that would be the result if the operand were /// regarded as unsigned. /// \brief Return the unsigned version of the predicate Predicate getUnsignedPredicate() const { return getUnsignedPredicate(getPredicate()); } /// This is a static version that you can use without an instruction. /// \brief Return the unsigned version of the predicate. static Predicate getUnsignedPredicate(Predicate pred); /// isEquality - Return true if this predicate is either EQ or NE. This also /// tests for commutativity. static bool isEquality(Predicate P) { return P == ICMP_EQ || P == ICMP_NE; } /// isEquality - Return true if this predicate is either EQ or NE. This also /// tests for commutativity. bool isEquality() const { return isEquality(getPredicate()); } /// @returns true if the predicate of this ICmpInst is commutative /// \brief Determine if this relation is commutative. bool isCommutative() const { return isEquality(); } /// isRelational - Return true if the predicate is relational (not EQ or NE). /// bool isRelational() const { return !isEquality(); } /// isRelational - Return true if the predicate is relational (not EQ or NE). /// static bool isRelational(Predicate P) { return !isEquality(P); } /// Initialize a set of values that all satisfy the predicate with C. /// \brief Make a ConstantRange for a relation with a constant value. static ConstantRange makeConstantRange(Predicate pred, const APInt &C); /// Exchange the two operands to this instruction in such a way that it does /// not modify the semantics of the instruction. The predicate value may be /// changed to retain the same result if the predicate is order dependent /// (e.g. ult). /// \brief Swap operands and adjust predicate. void swapOperands() { setPredicate(getSwappedPredicate()); Op<0>().swap(Op<1>()); } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::ICmp; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; //===----------------------------------------------------------------------===// // FCmpInst Class //===----------------------------------------------------------------------===// /// This instruction compares its operands according to the predicate given /// to the constructor. It only operates on floating point values or packed /// vectors of floating point values. The operands must be identical types. /// \brief Represents a floating point comparison operator. class FCmpInst: public CmpInst { protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; /// \brief Clone an identical FCmpInst FCmpInst *cloneImpl() const; public: /// \brief Constructor with insert-before-instruction semantics. FCmpInst( Instruction *InsertBefore, ///< Where to insert Predicate pred, ///< The predicate to use for the comparison Value *LHS, ///< The left-hand-side of the expression Value *RHS, ///< The right-hand-side of the expression const Twine &NameStr = "" ///< Name of the instruction ) : CmpInst(makeCmpResultType(LHS->getType()), Instruction::FCmp, pred, LHS, RHS, NameStr, InsertBefore) { assert(pred <= FCmpInst::LAST_FCMP_PREDICATE && "Invalid FCmp predicate value"); assert(getOperand(0)->getType() == getOperand(1)->getType() && "Both operands to FCmp instruction are not of the same type!"); // Check that the operands are the right type assert(getOperand(0)->getType()->isFPOrFPVectorTy() && "Invalid operand types for FCmp instruction"); } /// \brief Constructor with insert-at-end semantics. FCmpInst( BasicBlock &InsertAtEnd, ///< Block to insert into. Predicate pred, ///< The predicate to use for the comparison Value *LHS, ///< The left-hand-side of the expression Value *RHS, ///< The right-hand-side of the expression const Twine &NameStr = "" ///< Name of the instruction ) : CmpInst(makeCmpResultType(LHS->getType()), Instruction::FCmp, pred, LHS, RHS, NameStr, &InsertAtEnd) { assert(pred <= FCmpInst::LAST_FCMP_PREDICATE && "Invalid FCmp predicate value"); assert(getOperand(0)->getType() == getOperand(1)->getType() && "Both operands to FCmp instruction are not of the same type!"); // Check that the operands are the right type assert(getOperand(0)->getType()->isFPOrFPVectorTy() && "Invalid operand types for FCmp instruction"); } /// \brief Constructor with no-insertion semantics FCmpInst( Predicate pred, ///< The predicate to use for the comparison Value *LHS, ///< The left-hand-side of the expression Value *RHS, ///< The right-hand-side of the expression const Twine &NameStr = "" ///< Name of the instruction ) : CmpInst(makeCmpResultType(LHS->getType()), Instruction::FCmp, pred, LHS, RHS, NameStr) { assert(pred <= FCmpInst::LAST_FCMP_PREDICATE && "Invalid FCmp predicate value"); assert(getOperand(0)->getType() == getOperand(1)->getType() && "Both operands to FCmp instruction are not of the same type!"); // Check that the operands are the right type assert(getOperand(0)->getType()->isFPOrFPVectorTy() && "Invalid operand types for FCmp instruction"); } /// @returns true if the predicate of this instruction is EQ or NE. /// \brief Determine if this is an equality predicate. static bool isEquality(Predicate Pred) { return Pred == FCMP_OEQ || Pred == FCMP_ONE || Pred == FCMP_UEQ || Pred == FCMP_UNE; } /// @returns true if the predicate of this instruction is EQ or NE. /// \brief Determine if this is an equality predicate. bool isEquality() const { return isEquality(getPredicate()); } /// @returns true if the predicate of this instruction is commutative. /// \brief Determine if this is a commutative predicate. bool isCommutative() const { return isEquality() || getPredicate() == FCMP_FALSE || getPredicate() == FCMP_TRUE || getPredicate() == FCMP_ORD || getPredicate() == FCMP_UNO; } /// @returns true if the predicate is relational (not EQ or NE). /// \brief Determine if this a relational predicate. bool isRelational() const { return !isEquality(); } /// Exchange the two operands to this instruction in such a way that it does /// not modify the semantics of the instruction. The predicate value may be /// changed to retain the same result if the predicate is order dependent /// (e.g. ult). /// \brief Swap operands and adjust predicate. void swapOperands() { setPredicate(getSwappedPredicate()); Op<0>().swap(Op<1>()); } /// \brief Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::FCmp; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; //===----------------------------------------------------------------------===// /// CallInst - This class represents a function call, abstracting a target /// machine's calling convention. This class uses low bit of the SubClassData /// field to indicate whether or not this is a tail call. The rest of the bits /// hold the calling convention of the call. /// class CallInst : public Instruction, public OperandBundleUser { AttributeSet AttributeList; ///< parameter attributes for call FunctionType *FTy; CallInst(const CallInst &CI); void init(Value *Func, ArrayRef Args, ArrayRef Bundles, const Twine &NameStr) { init(cast( cast(Func->getType())->getElementType()), Func, Args, Bundles, NameStr); } void init(FunctionType *FTy, Value *Func, ArrayRef Args, ArrayRef Bundles, const Twine &NameStr); void init(Value *Func, const Twine &NameStr); /// Construct a CallInst given a range of arguments. /// \brief Construct a CallInst from a range of arguments inline CallInst(FunctionType *Ty, Value *Func, ArrayRef Args, ArrayRef Bundles, const Twine &NameStr, Instruction *InsertBefore); inline CallInst(Value *Func, ArrayRef Args, ArrayRef Bundles, const Twine &NameStr, Instruction *InsertBefore) : CallInst(cast( cast(Func->getType())->getElementType()), Func, Args, Bundles, NameStr, InsertBefore) {} inline CallInst(Value *Func, ArrayRef Args, const Twine &NameStr, Instruction *InsertBefore) : CallInst(Func, Args, None, NameStr, InsertBefore) {} /// Construct a CallInst given a range of arguments. /// \brief Construct a CallInst from a range of arguments inline CallInst(Value *Func, ArrayRef Args, ArrayRef Bundles, const Twine &NameStr, BasicBlock *InsertAtEnd); explicit CallInst(Value *F, const Twine &NameStr, Instruction *InsertBefore); CallInst(Value *F, const Twine &NameStr, BasicBlock *InsertAtEnd); friend class OperandBundleUser; bool hasDescriptor() const { return HasDescriptor; } protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; CallInst *cloneImpl() const; public: static CallInst *Create(Value *Func, ArrayRef Args, ArrayRef Bundles = None, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { return Create(cast( cast(Func->getType())->getElementType()), Func, Args, Bundles, NameStr, InsertBefore); } static CallInst *Create(Value *Func, ArrayRef Args, const Twine &NameStr, Instruction *InsertBefore = nullptr) { return Create(cast( cast(Func->getType())->getElementType()), Func, Args, None, NameStr, InsertBefore); } static CallInst *Create(FunctionType *Ty, Value *Func, ArrayRef Args, const Twine &NameStr, Instruction *InsertBefore = nullptr) { return new (unsigned(Args.size() + 1)) CallInst(Ty, Func, Args, None, NameStr, InsertBefore); } static CallInst *Create(FunctionType *Ty, Value *Func, ArrayRef Args, ArrayRef Bundles = None, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { const unsigned TotalOps = unsigned(Args.size()) + CountBundleInputs(Bundles) + 1; const unsigned DescriptorBytes = Bundles.size() * sizeof(BundleOpInfo); return new (TotalOps, DescriptorBytes) CallInst(Ty, Func, Args, Bundles, NameStr, InsertBefore); } static CallInst *Create(Value *Func, ArrayRef Args, ArrayRef Bundles, const Twine &NameStr, BasicBlock *InsertAtEnd) { const unsigned TotalOps = unsigned(Args.size()) + CountBundleInputs(Bundles) + 1; const unsigned DescriptorBytes = Bundles.size() * sizeof(BundleOpInfo); return new (TotalOps, DescriptorBytes) CallInst(Func, Args, Bundles, NameStr, InsertAtEnd); } static CallInst *Create(Value *Func, ArrayRef Args, const Twine &NameStr, BasicBlock *InsertAtEnd) { return new (unsigned(Args.size() + 1)) CallInst(Func, Args, None, NameStr, InsertAtEnd); } static CallInst *Create(Value *F, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { return new(1) CallInst(F, NameStr, InsertBefore); } static CallInst *Create(Value *F, const Twine &NameStr, BasicBlock *InsertAtEnd) { return new(1) CallInst(F, NameStr, InsertAtEnd); } /// \brief Create a clone of \p CI with a different set of operand bundles and /// insert it before \p InsertPt. /// /// The returned call instruction is identical \p CI in every way except that /// the operand bundles for the new instruction are set to the operand bundles /// in \p Bundles. static CallInst *Create(CallInst *CI, ArrayRef Bundles, Instruction *InsertPt = nullptr); /// CreateMalloc - Generate the IR for a call to malloc: /// 1. Compute the malloc call's argument as the specified type's size, /// possibly multiplied by the array size if the array size is not /// constant 1. /// 2. Call malloc with that argument. /// 3. Bitcast the result of the malloc call to the specified type. static Instruction *CreateMalloc(Instruction *InsertBefore, Type *IntPtrTy, Type *AllocTy, Value *AllocSize, Value *ArraySize = nullptr, Function* MallocF = nullptr, const Twine &Name = ""); static Instruction *CreateMalloc(BasicBlock *InsertAtEnd, Type *IntPtrTy, Type *AllocTy, Value *AllocSize, Value *ArraySize = nullptr, Function* MallocF = nullptr, const Twine &Name = ""); /// CreateFree - Generate the IR for a call to the builtin free function. static Instruction* CreateFree(Value* Source, Instruction *InsertBefore); static Instruction* CreateFree(Value* Source, BasicBlock *InsertAtEnd); ~CallInst() override; FunctionType *getFunctionType() const { return FTy; } void mutateFunctionType(FunctionType *FTy) { mutateType(FTy->getReturnType()); this->FTy = FTy; } // Note that 'musttail' implies 'tail'. enum TailCallKind { TCK_None = 0, TCK_Tail = 1, TCK_MustTail = 2, TCK_NoTail = 3 }; TailCallKind getTailCallKind() const { return TailCallKind(getSubclassDataFromInstruction() & 3); } bool isTailCall() const { unsigned Kind = getSubclassDataFromInstruction() & 3; return Kind == TCK_Tail || Kind == TCK_MustTail; } bool isMustTailCall() const { return (getSubclassDataFromInstruction() & 3) == TCK_MustTail; } bool isNoTailCall() const { return (getSubclassDataFromInstruction() & 3) == TCK_NoTail; } void setTailCall(bool isTC = true) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~3) | unsigned(isTC ? TCK_Tail : TCK_None)); } void setTailCallKind(TailCallKind TCK) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~3) | unsigned(TCK)); } /// Provide fast operand accessors DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); /// getNumArgOperands - Return the number of call arguments. /// unsigned getNumArgOperands() const { return getNumOperands() - getNumTotalBundleOperands() - 1; } /// getArgOperand/setArgOperand - Return/set the i-th call argument. /// Value *getArgOperand(unsigned i) const { assert(i < getNumArgOperands() && "Out of bounds!"); return getOperand(i); } void setArgOperand(unsigned i, Value *v) { assert(i < getNumArgOperands() && "Out of bounds!"); setOperand(i, v); } /// \brief Return the iterator pointing to the beginning of the argument list. op_iterator arg_begin() { return op_begin(); } /// \brief Return the iterator pointing to the end of the argument list. op_iterator arg_end() { // [ call args ], [ operand bundles ], callee return op_end() - getNumTotalBundleOperands() - 1; }; /// \brief Iteration adapter for range-for loops. iterator_range arg_operands() { return make_range(arg_begin(), arg_end()); } /// \brief Return the iterator pointing to the beginning of the argument list. const_op_iterator arg_begin() const { return op_begin(); } /// \brief Return the iterator pointing to the end of the argument list. const_op_iterator arg_end() const { // [ call args ], [ operand bundles ], callee return op_end() - getNumTotalBundleOperands() - 1; }; /// \brief Iteration adapter for range-for loops. iterator_range arg_operands() const { return make_range(arg_begin(), arg_end()); } /// \brief Wrappers for getting the \c Use of a call argument. const Use &getArgOperandUse(unsigned i) const { assert(i < getNumArgOperands() && "Out of bounds!"); return getOperandUse(i); } Use &getArgOperandUse(unsigned i) { assert(i < getNumArgOperands() && "Out of bounds!"); return getOperandUse(i); } /// getCallingConv/setCallingConv - Get or set the calling convention of this /// function call. CallingConv::ID getCallingConv() const { return static_cast(getSubclassDataFromInstruction() >> 2); } void setCallingConv(CallingConv::ID CC) { auto ID = static_cast(CC); assert(!(ID & ~CallingConv::MaxID) && "Unsupported calling convention"); setInstructionSubclassData((getSubclassDataFromInstruction() & 3) | (ID << 2)); } /// getAttributes - Return the parameter attributes for this call. /// const AttributeSet &getAttributes() const { return AttributeList; } /// setAttributes - Set the parameter attributes for this call. /// void setAttributes(const AttributeSet &Attrs) { AttributeList = Attrs; } /// addAttribute - adds the attribute to the list of attributes. void addAttribute(unsigned i, Attribute::AttrKind attr); /// addAttribute - adds the attribute to the list of attributes. void addAttribute(unsigned i, StringRef Kind, StringRef Value); /// removeAttribute - removes the attribute from the list of attributes. void removeAttribute(unsigned i, Attribute attr); /// \brief adds the dereferenceable attribute to the list of attributes. void addDereferenceableAttr(unsigned i, uint64_t Bytes); /// \brief adds the dereferenceable_or_null attribute to the list of /// attributes. void addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes); /// \brief Determine whether this call has the given attribute. bool hasFnAttr(Attribute::AttrKind A) const { assert(A != Attribute::NoBuiltin && "Use CallInst::isNoBuiltin() to check for Attribute::NoBuiltin"); return hasFnAttrImpl(A); } /// \brief Determine whether this call has the given attribute. bool hasFnAttr(StringRef A) const { return hasFnAttrImpl(A); } /// \brief Determine whether the call or the callee has the given attributes. bool paramHasAttr(unsigned i, Attribute::AttrKind A) const; /// \brief Return true if the data operand at index \p i has the attribute \p /// A. /// /// Data operands include call arguments and values used in operand bundles, /// but does not include the callee operand. This routine dispatches to the /// underlying AttributeList or the OperandBundleUser as appropriate. /// /// The index \p i is interpreted as /// /// \p i == Attribute::ReturnIndex -> the return value /// \p i in [1, arg_size + 1) -> argument number (\p i - 1) /// \p i in [arg_size + 1, data_operand_size + 1) -> bundle operand at index /// (\p i - 1) in the operand list. bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind A) const; /// \brief Extract the alignment for a call or parameter (0=unknown). unsigned getParamAlignment(unsigned i) const { return AttributeList.getParamAlignment(i); } /// \brief Extract the number of dereferenceable bytes for a call or /// parameter (0=unknown). uint64_t getDereferenceableBytes(unsigned i) const { return AttributeList.getDereferenceableBytes(i); } /// \brief Extract the number of dereferenceable_or_null bytes for a call or /// parameter (0=unknown). uint64_t getDereferenceableOrNullBytes(unsigned i) const { return AttributeList.getDereferenceableOrNullBytes(i); } /// @brief Determine if the parameter or return value is marked with NoAlias /// attribute. /// @param n The parameter to check. 1 is the first parameter, 0 is the return bool doesNotAlias(unsigned n) const { return AttributeList.hasAttribute(n, Attribute::NoAlias); } /// \brief Return true if the call should not be treated as a call to a /// builtin. bool isNoBuiltin() const { return hasFnAttrImpl(Attribute::NoBuiltin) && !hasFnAttrImpl(Attribute::Builtin); } /// \brief Return true if the call should not be inlined. bool isNoInline() const { return hasFnAttr(Attribute::NoInline); } void setIsNoInline() { addAttribute(AttributeSet::FunctionIndex, Attribute::NoInline); } /// \brief Return true if the call can return twice bool canReturnTwice() const { return hasFnAttr(Attribute::ReturnsTwice); } void setCanReturnTwice() { addAttribute(AttributeSet::FunctionIndex, Attribute::ReturnsTwice); } /// \brief Determine if the call does not access memory. bool doesNotAccessMemory() const { return hasFnAttr(Attribute::ReadNone); } void setDoesNotAccessMemory() { addAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone); } /// \brief Determine if the call does not access or only reads memory. bool onlyReadsMemory() const { return doesNotAccessMemory() || hasFnAttr(Attribute::ReadOnly); } void setOnlyReadsMemory() { addAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly); } /// @brief Determine if the call can access memmory only using pointers based /// on its arguments. bool onlyAccessesArgMemory() const { return hasFnAttr(Attribute::ArgMemOnly); } void setOnlyAccessesArgMemory() { addAttribute(AttributeSet::FunctionIndex, Attribute::ArgMemOnly); } /// \brief Determine if the call cannot return. bool doesNotReturn() const { return hasFnAttr(Attribute::NoReturn); } void setDoesNotReturn() { addAttribute(AttributeSet::FunctionIndex, Attribute::NoReturn); } /// \brief Determine if the call cannot unwind. bool doesNotThrow() const { return hasFnAttr(Attribute::NoUnwind); } void setDoesNotThrow() { addAttribute(AttributeSet::FunctionIndex, Attribute::NoUnwind); } /// \brief Determine if the call cannot be duplicated. bool cannotDuplicate() const {return hasFnAttr(Attribute::NoDuplicate); } void setCannotDuplicate() { addAttribute(AttributeSet::FunctionIndex, Attribute::NoDuplicate); } /// \brief Determine if the call is convergent bool isConvergent() const { return hasFnAttr(Attribute::Convergent); } void setConvergent() { addAttribute(AttributeSet::FunctionIndex, Attribute::Convergent); } /// \brief Determine if the call returns a structure through first /// pointer argument. bool hasStructRetAttr() const { if (getNumArgOperands() == 0) return false; // Be friendly and also check the callee. return paramHasAttr(1, Attribute::StructRet); } /// \brief Determine if any call argument is an aggregate passed by value. bool hasByValArgument() const { return AttributeList.hasAttrSomewhere(Attribute::ByVal); } /// getCalledFunction - Return the function called, or null if this is an /// indirect function invocation. /// Function *getCalledFunction() const { return dyn_cast(Op<-1>()); } /// getCalledValue - Get a pointer to the function that is invoked by this /// instruction. const Value *getCalledValue() const { return Op<-1>(); } Value *getCalledValue() { return Op<-1>(); } /// setCalledFunction - Set the function called. void setCalledFunction(Value* Fn) { setCalledFunction( cast(cast(Fn->getType())->getElementType()), Fn); } void setCalledFunction(FunctionType *FTy, Value *Fn) { this->FTy = FTy; assert(FTy == cast( cast(Fn->getType())->getElementType())); Op<-1>() = Fn; } /// isInlineAsm - Check if this call is an inline asm statement. bool isInlineAsm() const { return isa(Op<-1>()); } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::Call; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: template bool hasFnAttrImpl(AttrKind A) const { if (AttributeList.hasAttribute(AttributeSet::FunctionIndex, A)) return true; // Operand bundles override attributes on the called function, but don't // override attributes directly present on the call instruction. if (isFnAttrDisallowedByOpBundle(A)) return false; if (const Function *F = getCalledFunction()) return F->getAttributes().hasAttribute(AttributeSet::FunctionIndex, A); return false; } // Shadow Instruction::setInstructionSubclassData with a private forwarding // method so that subclasses cannot accidentally use it. void setInstructionSubclassData(unsigned short D) { Instruction::setInstructionSubclassData(D); } }; template <> struct OperandTraits : public VariadicOperandTraits { }; CallInst::CallInst(Value *Func, ArrayRef Args, ArrayRef Bundles, const Twine &NameStr, BasicBlock *InsertAtEnd) : Instruction( cast(cast(Func->getType()) ->getElementType())->getReturnType(), Instruction::Call, OperandTraits::op_end(this) - (Args.size() + CountBundleInputs(Bundles) + 1), unsigned(Args.size() + CountBundleInputs(Bundles) + 1), InsertAtEnd) { init(Func, Args, Bundles, NameStr); } CallInst::CallInst(FunctionType *Ty, Value *Func, ArrayRef Args, ArrayRef Bundles, const Twine &NameStr, Instruction *InsertBefore) : Instruction(Ty->getReturnType(), Instruction::Call, OperandTraits::op_end(this) - (Args.size() + CountBundleInputs(Bundles) + 1), unsigned(Args.size() + CountBundleInputs(Bundles) + 1), InsertBefore) { init(Ty, Func, Args, Bundles, NameStr); } // Note: if you get compile errors about private methods then // please update your code to use the high-level operand // interfaces. See line 943 above. DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CallInst, Value) //===----------------------------------------------------------------------===// // SelectInst Class //===----------------------------------------------------------------------===// /// SelectInst - This class represents the LLVM 'select' instruction. /// class SelectInst : public Instruction { void init(Value *C, Value *S1, Value *S2) { assert(!areInvalidOperands(C, S1, S2) && "Invalid operands for select"); Op<0>() = C; Op<1>() = S1; Op<2>() = S2; } SelectInst(Value *C, Value *S1, Value *S2, const Twine &NameStr, Instruction *InsertBefore) : Instruction(S1->getType(), Instruction::Select, &Op<0>(), 3, InsertBefore) { init(C, S1, S2); setName(NameStr); } SelectInst(Value *C, Value *S1, Value *S2, const Twine &NameStr, BasicBlock *InsertAtEnd) : Instruction(S1->getType(), Instruction::Select, &Op<0>(), 3, InsertAtEnd) { init(C, S1, S2); setName(NameStr); } protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; SelectInst *cloneImpl() const; public: static SelectInst *Create(Value *C, Value *S1, Value *S2, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { return new(3) SelectInst(C, S1, S2, NameStr, InsertBefore); } static SelectInst *Create(Value *C, Value *S1, Value *S2, const Twine &NameStr, BasicBlock *InsertAtEnd) { return new(3) SelectInst(C, S1, S2, NameStr, InsertAtEnd); } const Value *getCondition() const { return Op<0>(); } const Value *getTrueValue() const { return Op<1>(); } const Value *getFalseValue() const { return Op<2>(); } Value *getCondition() { return Op<0>(); } Value *getTrueValue() { return Op<1>(); } Value *getFalseValue() { return Op<2>(); } /// areInvalidOperands - Return a string if the specified operands are invalid /// for a select operation, otherwise return null. static const char *areInvalidOperands(Value *Cond, Value *True, Value *False); /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); OtherOps getOpcode() const { return static_cast(Instruction::getOpcode()); } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::Select; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; template <> struct OperandTraits : public FixedNumOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(SelectInst, Value) //===----------------------------------------------------------------------===// // VAArgInst Class //===----------------------------------------------------------------------===// /// VAArgInst - This class represents the va_arg llvm instruction, which returns /// an argument of the specified type given a va_list and increments that list /// class VAArgInst : public UnaryInstruction { protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; VAArgInst *cloneImpl() const; public: VAArgInst(Value *List, Type *Ty, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) : UnaryInstruction(Ty, VAArg, List, InsertBefore) { setName(NameStr); } VAArgInst(Value *List, Type *Ty, const Twine &NameStr, BasicBlock *InsertAtEnd) : UnaryInstruction(Ty, VAArg, List, InsertAtEnd) { setName(NameStr); } Value *getPointerOperand() { return getOperand(0); } const Value *getPointerOperand() const { return getOperand(0); } static unsigned getPointerOperandIndex() { return 0U; } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == VAArg; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; //===----------------------------------------------------------------------===// // ExtractElementInst Class //===----------------------------------------------------------------------===// /// ExtractElementInst - This instruction extracts a single (scalar) /// element from a VectorType value /// class ExtractElementInst : public Instruction { ExtractElementInst(Value *Vec, Value *Idx, const Twine &NameStr = "", Instruction *InsertBefore = nullptr); ExtractElementInst(Value *Vec, Value *Idx, const Twine &NameStr, BasicBlock *InsertAtEnd); protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; ExtractElementInst *cloneImpl() const; public: static ExtractElementInst *Create(Value *Vec, Value *Idx, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { return new(2) ExtractElementInst(Vec, Idx, NameStr, InsertBefore); } static ExtractElementInst *Create(Value *Vec, Value *Idx, const Twine &NameStr, BasicBlock *InsertAtEnd) { return new(2) ExtractElementInst(Vec, Idx, NameStr, InsertAtEnd); } /// isValidOperands - Return true if an extractelement instruction can be /// formed with the specified operands. static bool isValidOperands(const Value *Vec, const Value *Idx); Value *getVectorOperand() { return Op<0>(); } Value *getIndexOperand() { return Op<1>(); } const Value *getVectorOperand() const { return Op<0>(); } const Value *getIndexOperand() const { return Op<1>(); } VectorType *getVectorOperandType() const { return cast(getVectorOperand()->getType()); } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::ExtractElement; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; template <> struct OperandTraits : public FixedNumOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ExtractElementInst, Value) //===----------------------------------------------------------------------===// // InsertElementInst Class //===----------------------------------------------------------------------===// /// InsertElementInst - This instruction inserts a single (scalar) /// element into a VectorType value /// class InsertElementInst : public Instruction { InsertElementInst(Value *Vec, Value *NewElt, Value *Idx, const Twine &NameStr = "", Instruction *InsertBefore = nullptr); InsertElementInst(Value *Vec, Value *NewElt, Value *Idx, const Twine &NameStr, BasicBlock *InsertAtEnd); protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; InsertElementInst *cloneImpl() const; public: static InsertElementInst *Create(Value *Vec, Value *NewElt, Value *Idx, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { return new(3) InsertElementInst(Vec, NewElt, Idx, NameStr, InsertBefore); } static InsertElementInst *Create(Value *Vec, Value *NewElt, Value *Idx, const Twine &NameStr, BasicBlock *InsertAtEnd) { return new(3) InsertElementInst(Vec, NewElt, Idx, NameStr, InsertAtEnd); } /// isValidOperands - Return true if an insertelement instruction can be /// formed with the specified operands. static bool isValidOperands(const Value *Vec, const Value *NewElt, const Value *Idx); /// getType - Overload to return most specific vector type. /// VectorType *getType() const { return cast(Instruction::getType()); } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::InsertElement; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; template <> struct OperandTraits : public FixedNumOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(InsertElementInst, Value) //===----------------------------------------------------------------------===// // ShuffleVectorInst Class //===----------------------------------------------------------------------===// /// ShuffleVectorInst - This instruction constructs a fixed permutation of two /// input vectors. /// class ShuffleVectorInst : public Instruction { protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; ShuffleVectorInst *cloneImpl() const; public: // allocate space for exactly three operands void *operator new(size_t s) { return User::operator new(s, 3); } ShuffleVectorInst(Value *V1, Value *V2, Value *Mask, const Twine &NameStr = "", Instruction *InsertBefor = nullptr); ShuffleVectorInst(Value *V1, Value *V2, Value *Mask, const Twine &NameStr, BasicBlock *InsertAtEnd); /// isValidOperands - Return true if a shufflevector instruction can be /// formed with the specified operands. static bool isValidOperands(const Value *V1, const Value *V2, const Value *Mask); /// getType - Overload to return most specific vector type. /// VectorType *getType() const { return cast(Instruction::getType()); } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); Constant *getMask() const { return cast(getOperand(2)); } /// getMaskValue - Return the index from the shuffle mask for the specified /// output result. This is either -1 if the element is undef or a number less /// than 2*numelements. static int getMaskValue(Constant *Mask, unsigned i); int getMaskValue(unsigned i) const { return getMaskValue(getMask(), i); } /// getShuffleMask - Return the full mask for this instruction, where each /// element is the element number and undef's are returned as -1. static void getShuffleMask(Constant *Mask, SmallVectorImpl &Result); void getShuffleMask(SmallVectorImpl &Result) const { return getShuffleMask(getMask(), Result); } SmallVector getShuffleMask() const { SmallVector Mask; getShuffleMask(Mask); return Mask; } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::ShuffleVector; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; template <> struct OperandTraits : public FixedNumOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ShuffleVectorInst, Value) //===----------------------------------------------------------------------===// // ExtractValueInst Class //===----------------------------------------------------------------------===// /// ExtractValueInst - This instruction extracts a struct member or array /// element value from an aggregate value. /// class ExtractValueInst : public UnaryInstruction { SmallVector Indices; ExtractValueInst(const ExtractValueInst &EVI); void init(ArrayRef Idxs, const Twine &NameStr); /// Constructors - Create a extractvalue instruction with a base aggregate /// value and a list of indices. The first ctor can optionally insert before /// an existing instruction, the second appends the new instruction to the /// specified BasicBlock. inline ExtractValueInst(Value *Agg, ArrayRef Idxs, const Twine &NameStr, Instruction *InsertBefore); inline ExtractValueInst(Value *Agg, ArrayRef Idxs, const Twine &NameStr, BasicBlock *InsertAtEnd); // allocate space for exactly one operand void *operator new(size_t s) { return User::operator new(s, 1); } protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; ExtractValueInst *cloneImpl() const; public: static ExtractValueInst *Create(Value *Agg, ArrayRef Idxs, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { return new ExtractValueInst(Agg, Idxs, NameStr, InsertBefore); } static ExtractValueInst *Create(Value *Agg, ArrayRef Idxs, const Twine &NameStr, BasicBlock *InsertAtEnd) { return new ExtractValueInst(Agg, Idxs, NameStr, InsertAtEnd); } /// getIndexedType - Returns the type of the element that would be extracted /// with an extractvalue instruction with the specified parameters. /// /// Null is returned if the indices are invalid for the specified type. static Type *getIndexedType(Type *Agg, ArrayRef Idxs); typedef const unsigned* idx_iterator; inline idx_iterator idx_begin() const { return Indices.begin(); } inline idx_iterator idx_end() const { return Indices.end(); } inline iterator_range indices() const { return make_range(idx_begin(), idx_end()); } Value *getAggregateOperand() { return getOperand(0); } const Value *getAggregateOperand() const { return getOperand(0); } static unsigned getAggregateOperandIndex() { return 0U; // get index for modifying correct operand } ArrayRef getIndices() const { return Indices; } unsigned getNumIndices() const { return (unsigned)Indices.size(); } bool hasIndices() const { return true; } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::ExtractValue; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; ExtractValueInst::ExtractValueInst(Value *Agg, ArrayRef Idxs, const Twine &NameStr, Instruction *InsertBefore) : UnaryInstruction(checkGEPType(getIndexedType(Agg->getType(), Idxs)), ExtractValue, Agg, InsertBefore) { init(Idxs, NameStr); } ExtractValueInst::ExtractValueInst(Value *Agg, ArrayRef Idxs, const Twine &NameStr, BasicBlock *InsertAtEnd) : UnaryInstruction(checkGEPType(getIndexedType(Agg->getType(), Idxs)), ExtractValue, Agg, InsertAtEnd) { init(Idxs, NameStr); } //===----------------------------------------------------------------------===// // InsertValueInst Class //===----------------------------------------------------------------------===// /// InsertValueInst - This instruction inserts a struct field of array element /// value into an aggregate value. /// class InsertValueInst : public Instruction { SmallVector Indices; void *operator new(size_t, unsigned) = delete; InsertValueInst(const InsertValueInst &IVI); void init(Value *Agg, Value *Val, ArrayRef Idxs, const Twine &NameStr); /// Constructors - Create a insertvalue instruction with a base aggregate /// value, a value to insert, and a list of indices. The first ctor can /// optionally insert before an existing instruction, the second appends /// the new instruction to the specified BasicBlock. inline InsertValueInst(Value *Agg, Value *Val, ArrayRef Idxs, const Twine &NameStr, Instruction *InsertBefore); inline InsertValueInst(Value *Agg, Value *Val, ArrayRef Idxs, const Twine &NameStr, BasicBlock *InsertAtEnd); /// Constructors - These two constructors are convenience methods because one /// and two index insertvalue instructions are so common. InsertValueInst(Value *Agg, Value *Val, unsigned Idx, const Twine &NameStr = "", Instruction *InsertBefore = nullptr); InsertValueInst(Value *Agg, Value *Val, unsigned Idx, const Twine &NameStr, BasicBlock *InsertAtEnd); protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; InsertValueInst *cloneImpl() const; public: // allocate space for exactly two operands void *operator new(size_t s) { return User::operator new(s, 2); } static InsertValueInst *Create(Value *Agg, Value *Val, ArrayRef Idxs, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { return new InsertValueInst(Agg, Val, Idxs, NameStr, InsertBefore); } static InsertValueInst *Create(Value *Agg, Value *Val, ArrayRef Idxs, const Twine &NameStr, BasicBlock *InsertAtEnd) { return new InsertValueInst(Agg, Val, Idxs, NameStr, InsertAtEnd); } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); typedef const unsigned* idx_iterator; inline idx_iterator idx_begin() const { return Indices.begin(); } inline idx_iterator idx_end() const { return Indices.end(); } inline iterator_range indices() const { return make_range(idx_begin(), idx_end()); } Value *getAggregateOperand() { return getOperand(0); } const Value *getAggregateOperand() const { return getOperand(0); } static unsigned getAggregateOperandIndex() { return 0U; // get index for modifying correct operand } Value *getInsertedValueOperand() { return getOperand(1); } const Value *getInsertedValueOperand() const { return getOperand(1); } static unsigned getInsertedValueOperandIndex() { return 1U; // get index for modifying correct operand } ArrayRef getIndices() const { return Indices; } unsigned getNumIndices() const { return (unsigned)Indices.size(); } bool hasIndices() const { return true; } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::InsertValue; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; template <> struct OperandTraits : public FixedNumOperandTraits { }; InsertValueInst::InsertValueInst(Value *Agg, Value *Val, ArrayRef Idxs, const Twine &NameStr, Instruction *InsertBefore) : Instruction(Agg->getType(), InsertValue, OperandTraits::op_begin(this), 2, InsertBefore) { init(Agg, Val, Idxs, NameStr); } InsertValueInst::InsertValueInst(Value *Agg, Value *Val, ArrayRef Idxs, const Twine &NameStr, BasicBlock *InsertAtEnd) : Instruction(Agg->getType(), InsertValue, OperandTraits::op_begin(this), 2, InsertAtEnd) { init(Agg, Val, Idxs, NameStr); } DEFINE_TRANSPARENT_OPERAND_ACCESSORS(InsertValueInst, Value) //===----------------------------------------------------------------------===// // PHINode Class //===----------------------------------------------------------------------===// // PHINode - The PHINode class is used to represent the magical mystical PHI // node, that can not exist in nature, but can be synthesized in a computer // scientist's overactive imagination. // class PHINode : public Instruction { void anchor() override; void *operator new(size_t, unsigned) = delete; /// ReservedSpace - The number of operands actually allocated. NumOperands is /// the number actually in use. unsigned ReservedSpace; PHINode(const PHINode &PN); // allocate space for exactly zero operands void *operator new(size_t s) { return User::operator new(s); } explicit PHINode(Type *Ty, unsigned NumReservedValues, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) : Instruction(Ty, Instruction::PHI, nullptr, 0, InsertBefore), ReservedSpace(NumReservedValues) { setName(NameStr); allocHungoffUses(ReservedSpace); } PHINode(Type *Ty, unsigned NumReservedValues, const Twine &NameStr, BasicBlock *InsertAtEnd) : Instruction(Ty, Instruction::PHI, nullptr, 0, InsertAtEnd), ReservedSpace(NumReservedValues) { setName(NameStr); allocHungoffUses(ReservedSpace); } protected: // allocHungoffUses - this is more complicated than the generic // User::allocHungoffUses, because we have to allocate Uses for the incoming // values and pointers to the incoming blocks, all in one allocation. void allocHungoffUses(unsigned N) { User::allocHungoffUses(N, /* IsPhi */ true); } // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; PHINode *cloneImpl() const; public: /// Constructors - NumReservedValues is a hint for the number of incoming /// edges that this phi node will have (use 0 if you really have no idea). static PHINode *Create(Type *Ty, unsigned NumReservedValues, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { return new PHINode(Ty, NumReservedValues, NameStr, InsertBefore); } static PHINode *Create(Type *Ty, unsigned NumReservedValues, const Twine &NameStr, BasicBlock *InsertAtEnd) { return new PHINode(Ty, NumReservedValues, NameStr, InsertAtEnd); } /// Provide fast operand accessors DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); // Block iterator interface. This provides access to the list of incoming // basic blocks, which parallels the list of incoming values. typedef BasicBlock **block_iterator; typedef BasicBlock * const *const_block_iterator; block_iterator block_begin() { Use::UserRef *ref = reinterpret_cast(op_begin() + ReservedSpace); return reinterpret_cast(ref + 1); } const_block_iterator block_begin() const { const Use::UserRef *ref = reinterpret_cast(op_begin() + ReservedSpace); return reinterpret_cast(ref + 1); } block_iterator block_end() { return block_begin() + getNumOperands(); } const_block_iterator block_end() const { return block_begin() + getNumOperands(); } + iterator_range blocks() { + return make_range(block_begin(), block_end()); + } + + iterator_range blocks() const { + return make_range(block_begin(), block_end()); + } + op_range incoming_values() { return operands(); } const_op_range incoming_values() const { return operands(); } /// getNumIncomingValues - Return the number of incoming edges /// unsigned getNumIncomingValues() const { return getNumOperands(); } /// getIncomingValue - Return incoming value number x /// Value *getIncomingValue(unsigned i) const { return getOperand(i); } void setIncomingValue(unsigned i, Value *V) { assert(V && "PHI node got a null value!"); assert(getType() == V->getType() && "All operands to PHI node must be the same type as the PHI node!"); setOperand(i, V); } static unsigned getOperandNumForIncomingValue(unsigned i) { return i; } static unsigned getIncomingValueNumForOperand(unsigned i) { return i; } /// getIncomingBlock - Return incoming basic block number @p i. /// BasicBlock *getIncomingBlock(unsigned i) const { return block_begin()[i]; } /// getIncomingBlock - Return incoming basic block corresponding /// to an operand of the PHI. /// BasicBlock *getIncomingBlock(const Use &U) const { assert(this == U.getUser() && "Iterator doesn't point to PHI's Uses?"); return getIncomingBlock(unsigned(&U - op_begin())); } /// getIncomingBlock - Return incoming basic block corresponding /// to value use iterator. /// BasicBlock *getIncomingBlock(Value::const_user_iterator I) const { return getIncomingBlock(I.getUse()); } void setIncomingBlock(unsigned i, BasicBlock *BB) { assert(BB && "PHI node got a null basic block!"); block_begin()[i] = BB; } /// addIncoming - Add an incoming value to the end of the PHI list /// void addIncoming(Value *V, BasicBlock *BB) { if (getNumOperands() == ReservedSpace) growOperands(); // Get more space! // Initialize some new operands. setNumHungOffUseOperands(getNumOperands() + 1); setIncomingValue(getNumOperands() - 1, V); setIncomingBlock(getNumOperands() - 1, BB); } /// removeIncomingValue - Remove an incoming value. This is useful if a /// predecessor basic block is deleted. The value removed is returned. /// /// If the last incoming value for a PHI node is removed (and DeletePHIIfEmpty /// is true), the PHI node is destroyed and any uses of it are replaced with /// dummy values. The only time there should be zero incoming values to a PHI /// node is when the block is dead, so this strategy is sound. /// Value *removeIncomingValue(unsigned Idx, bool DeletePHIIfEmpty = true); Value *removeIncomingValue(const BasicBlock *BB, bool DeletePHIIfEmpty=true) { int Idx = getBasicBlockIndex(BB); assert(Idx >= 0 && "Invalid basic block argument to remove!"); return removeIncomingValue(Idx, DeletePHIIfEmpty); } /// getBasicBlockIndex - Return the first index of the specified basic /// block in the value list for this PHI. Returns -1 if no instance. /// int getBasicBlockIndex(const BasicBlock *BB) const { for (unsigned i = 0, e = getNumOperands(); i != e; ++i) if (block_begin()[i] == BB) return i; return -1; } Value *getIncomingValueForBlock(const BasicBlock *BB) const { int Idx = getBasicBlockIndex(BB); assert(Idx >= 0 && "Invalid basic block argument!"); return getIncomingValue(Idx); } /// hasConstantValue - If the specified PHI node always merges together the /// same value, return the value, otherwise return null. Value *hasConstantValue() const; /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::PHI; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: void growOperands(); }; template <> struct OperandTraits : public HungoffOperandTraits<2> { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(PHINode, Value) //===----------------------------------------------------------------------===// // LandingPadInst Class //===----------------------------------------------------------------------===// //===--------------------------------------------------------------------------- /// LandingPadInst - The landingpad instruction holds all of the information /// necessary to generate correct exception handling. The landingpad instruction /// cannot be moved from the top of a landing pad block, which itself is /// accessible only from the 'unwind' edge of an invoke. This uses the /// SubclassData field in Value to store whether or not the landingpad is a /// cleanup. /// class LandingPadInst : public Instruction { /// ReservedSpace - The number of operands actually allocated. NumOperands is /// the number actually in use. unsigned ReservedSpace; LandingPadInst(const LandingPadInst &LP); public: enum ClauseType { Catch, Filter }; private: void *operator new(size_t, unsigned) = delete; // Allocate space for exactly zero operands. void *operator new(size_t s) { return User::operator new(s); } void growOperands(unsigned Size); void init(unsigned NumReservedValues, const Twine &NameStr); explicit LandingPadInst(Type *RetTy, unsigned NumReservedValues, const Twine &NameStr, Instruction *InsertBefore); explicit LandingPadInst(Type *RetTy, unsigned NumReservedValues, const Twine &NameStr, BasicBlock *InsertAtEnd); protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; LandingPadInst *cloneImpl() const; public: /// Constructors - NumReservedClauses is a hint for the number of incoming /// clauses that this landingpad will have (use 0 if you really have no idea). static LandingPadInst *Create(Type *RetTy, unsigned NumReservedClauses, const Twine &NameStr = "", Instruction *InsertBefore = nullptr); static LandingPadInst *Create(Type *RetTy, unsigned NumReservedClauses, const Twine &NameStr, BasicBlock *InsertAtEnd); /// Provide fast operand accessors DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); /// isCleanup - Return 'true' if this landingpad instruction is a /// cleanup. I.e., it should be run when unwinding even if its landing pad /// doesn't catch the exception. bool isCleanup() const { return getSubclassDataFromInstruction() & 1; } /// setCleanup - Indicate that this landingpad instruction is a cleanup. void setCleanup(bool V) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~1) | (V ? 1 : 0)); } /// Add a catch or filter clause to the landing pad. void addClause(Constant *ClauseVal); /// Get the value of the clause at index Idx. Use isCatch/isFilter to /// determine what type of clause this is. Constant *getClause(unsigned Idx) const { return cast(getOperandList()[Idx]); } /// isCatch - Return 'true' if the clause and index Idx is a catch clause. bool isCatch(unsigned Idx) const { return !isa(getOperandList()[Idx]->getType()); } /// isFilter - Return 'true' if the clause and index Idx is a filter clause. bool isFilter(unsigned Idx) const { return isa(getOperandList()[Idx]->getType()); } /// getNumClauses - Get the number of clauses for this landing pad. unsigned getNumClauses() const { return getNumOperands(); } /// reserveClauses - Grow the size of the operand list to accommodate the new /// number of clauses. void reserveClauses(unsigned Size) { growOperands(Size); } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::LandingPad; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; template <> struct OperandTraits : public HungoffOperandTraits<1> { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(LandingPadInst, Value) //===----------------------------------------------------------------------===// // ReturnInst Class //===----------------------------------------------------------------------===// //===--------------------------------------------------------------------------- /// ReturnInst - Return a value (possibly void), from a function. Execution /// does not continue in this function any longer. /// class ReturnInst : public TerminatorInst { ReturnInst(const ReturnInst &RI); private: // ReturnInst constructors: // ReturnInst() - 'ret void' instruction // ReturnInst( null) - 'ret void' instruction // ReturnInst(Value* X) - 'ret X' instruction // ReturnInst( null, Inst *I) - 'ret void' instruction, insert before I // ReturnInst(Value* X, Inst *I) - 'ret X' instruction, insert before I // ReturnInst( null, BB *B) - 'ret void' instruction, insert @ end of B // ReturnInst(Value* X, BB *B) - 'ret X' instruction, insert @ end of B // // NOTE: If the Value* passed is of type void then the constructor behaves as // if it was passed NULL. explicit ReturnInst(LLVMContext &C, Value *retVal = nullptr, Instruction *InsertBefore = nullptr); ReturnInst(LLVMContext &C, Value *retVal, BasicBlock *InsertAtEnd); explicit ReturnInst(LLVMContext &C, BasicBlock *InsertAtEnd); protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; ReturnInst *cloneImpl() const; public: static ReturnInst* Create(LLVMContext &C, Value *retVal = nullptr, Instruction *InsertBefore = nullptr) { return new(!!retVal) ReturnInst(C, retVal, InsertBefore); } static ReturnInst* Create(LLVMContext &C, Value *retVal, BasicBlock *InsertAtEnd) { return new(!!retVal) ReturnInst(C, retVal, InsertAtEnd); } static ReturnInst* Create(LLVMContext &C, BasicBlock *InsertAtEnd) { return new(0) ReturnInst(C, InsertAtEnd); } ~ReturnInst() override; /// Provide fast operand accessors DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); /// Convenience accessor. Returns null if there is no return value. Value *getReturnValue() const { return getNumOperands() != 0 ? getOperand(0) : nullptr; } unsigned getNumSuccessors() const { return 0; } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return (I->getOpcode() == Instruction::Ret); } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: BasicBlock *getSuccessorV(unsigned idx) const override; unsigned getNumSuccessorsV() const override; void setSuccessorV(unsigned idx, BasicBlock *B) override; }; template <> struct OperandTraits : public VariadicOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ReturnInst, Value) //===----------------------------------------------------------------------===// // BranchInst Class //===----------------------------------------------------------------------===// //===--------------------------------------------------------------------------- /// BranchInst - Conditional or Unconditional Branch instruction. /// class BranchInst : public TerminatorInst { /// Ops list - Branches are strange. The operands are ordered: /// [Cond, FalseDest,] TrueDest. This makes some accessors faster because /// they don't have to check for cond/uncond branchness. These are mostly /// accessed relative from op_end(). BranchInst(const BranchInst &BI); void AssertOK(); // BranchInst constructors (where {B, T, F} are blocks, and C is a condition): // BranchInst(BB *B) - 'br B' // BranchInst(BB* T, BB *F, Value *C) - 'br C, T, F' // BranchInst(BB* B, Inst *I) - 'br B' insert before I // BranchInst(BB* T, BB *F, Value *C, Inst *I) - 'br C, T, F', insert before I // BranchInst(BB* B, BB *I) - 'br B' insert at end // BranchInst(BB* T, BB *F, Value *C, BB *I) - 'br C, T, F', insert at end explicit BranchInst(BasicBlock *IfTrue, Instruction *InsertBefore = nullptr); BranchInst(BasicBlock *IfTrue, BasicBlock *IfFalse, Value *Cond, Instruction *InsertBefore = nullptr); BranchInst(BasicBlock *IfTrue, BasicBlock *InsertAtEnd); BranchInst(BasicBlock *IfTrue, BasicBlock *IfFalse, Value *Cond, BasicBlock *InsertAtEnd); protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; BranchInst *cloneImpl() const; public: static BranchInst *Create(BasicBlock *IfTrue, Instruction *InsertBefore = nullptr) { return new(1) BranchInst(IfTrue, InsertBefore); } static BranchInst *Create(BasicBlock *IfTrue, BasicBlock *IfFalse, Value *Cond, Instruction *InsertBefore = nullptr) { return new(3) BranchInst(IfTrue, IfFalse, Cond, InsertBefore); } static BranchInst *Create(BasicBlock *IfTrue, BasicBlock *InsertAtEnd) { return new(1) BranchInst(IfTrue, InsertAtEnd); } static BranchInst *Create(BasicBlock *IfTrue, BasicBlock *IfFalse, Value *Cond, BasicBlock *InsertAtEnd) { return new(3) BranchInst(IfTrue, IfFalse, Cond, InsertAtEnd); } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); bool isUnconditional() const { return getNumOperands() == 1; } bool isConditional() const { return getNumOperands() == 3; } Value *getCondition() const { assert(isConditional() && "Cannot get condition of an uncond branch!"); return Op<-3>(); } void setCondition(Value *V) { assert(isConditional() && "Cannot set condition of unconditional branch!"); Op<-3>() = V; } unsigned getNumSuccessors() const { return 1+isConditional(); } BasicBlock *getSuccessor(unsigned i) const { assert(i < getNumSuccessors() && "Successor # out of range for Branch!"); return cast_or_null((&Op<-1>() - i)->get()); } void setSuccessor(unsigned idx, BasicBlock *NewSucc) { assert(idx < getNumSuccessors() && "Successor # out of range for Branch!"); *(&Op<-1>() - idx) = NewSucc; } /// \brief Swap the successors of this branch instruction. /// /// Swaps the successors of the branch instruction. This also swaps any /// branch weight metadata associated with the instruction so that it /// continues to map correctly to each operand. void swapSuccessors(); // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return (I->getOpcode() == Instruction::Br); } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: BasicBlock *getSuccessorV(unsigned idx) const override; unsigned getNumSuccessorsV() const override; void setSuccessorV(unsigned idx, BasicBlock *B) override; }; template <> struct OperandTraits : public VariadicOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BranchInst, Value) //===----------------------------------------------------------------------===// // SwitchInst Class //===----------------------------------------------------------------------===// //===--------------------------------------------------------------------------- /// SwitchInst - Multiway switch /// class SwitchInst : public TerminatorInst { void *operator new(size_t, unsigned) = delete; unsigned ReservedSpace; // Operand[0] = Value to switch on // Operand[1] = Default basic block destination // Operand[2n ] = Value to match // Operand[2n+1] = BasicBlock to go to on match SwitchInst(const SwitchInst &SI); void init(Value *Value, BasicBlock *Default, unsigned NumReserved); void growOperands(); // allocate space for exactly zero operands void *operator new(size_t s) { return User::operator new(s); } /// SwitchInst ctor - Create a new switch instruction, specifying a value to /// switch on and a default destination. The number of additional cases can /// be specified here to make memory allocation more efficient. This /// constructor can also autoinsert before another instruction. SwitchInst(Value *Value, BasicBlock *Default, unsigned NumCases, Instruction *InsertBefore); /// SwitchInst ctor - Create a new switch instruction, specifying a value to /// switch on and a default destination. The number of additional cases can /// be specified here to make memory allocation more efficient. This /// constructor also autoinserts at the end of the specified BasicBlock. SwitchInst(Value *Value, BasicBlock *Default, unsigned NumCases, BasicBlock *InsertAtEnd); protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; SwitchInst *cloneImpl() const; public: // -2 static const unsigned DefaultPseudoIndex = static_cast(~0L-1); template class CaseIteratorT { protected: SwitchInstTy *SI; unsigned Index; public: typedef CaseIteratorT Self; /// Initializes case iterator for given SwitchInst and for given /// case number. CaseIteratorT(SwitchInstTy *SI, unsigned CaseNum) { this->SI = SI; Index = CaseNum; } /// Initializes case iterator for given SwitchInst and for given /// TerminatorInst's successor index. static Self fromSuccessorIndex(SwitchInstTy *SI, unsigned SuccessorIndex) { assert(SuccessorIndex < SI->getNumSuccessors() && "Successor index # out of range!"); return SuccessorIndex != 0 ? Self(SI, SuccessorIndex - 1) : Self(SI, DefaultPseudoIndex); } /// Resolves case value for current case. ConstantIntTy *getCaseValue() { assert(Index < SI->getNumCases() && "Index out the number of cases."); return reinterpret_cast(SI->getOperand(2 + Index*2)); } /// Resolves successor for current case. BasicBlockTy *getCaseSuccessor() { assert((Index < SI->getNumCases() || Index == DefaultPseudoIndex) && "Index out the number of cases."); return SI->getSuccessor(getSuccessorIndex()); } /// Returns number of current case. unsigned getCaseIndex() const { return Index; } /// Returns TerminatorInst's successor index for current case successor. unsigned getSuccessorIndex() const { assert((Index == DefaultPseudoIndex || Index < SI->getNumCases()) && "Index out the number of cases."); return Index != DefaultPseudoIndex ? Index + 1 : 0; } Self operator++() { // Check index correctness after increment. // Note: Index == getNumCases() means end(). assert(Index+1 <= SI->getNumCases() && "Index out the number of cases."); ++Index; return *this; } Self operator++(int) { Self tmp = *this; ++(*this); return tmp; } Self operator--() { // Check index correctness after decrement. // Note: Index == getNumCases() means end(). // Also allow "-1" iterator here. That will became valid after ++. assert((Index == 0 || Index-1 <= SI->getNumCases()) && "Index out the number of cases."); --Index; return *this; } Self operator--(int) { Self tmp = *this; --(*this); return tmp; } bool operator==(const Self& RHS) const { assert(RHS.SI == SI && "Incompatible operators."); return RHS.Index == Index; } bool operator!=(const Self& RHS) const { assert(RHS.SI == SI && "Incompatible operators."); return RHS.Index != Index; } Self &operator*() { return *this; } }; typedef CaseIteratorT ConstCaseIt; class CaseIt : public CaseIteratorT { typedef CaseIteratorT ParentTy; public: CaseIt(const ParentTy &Src) : ParentTy(Src) {} CaseIt(SwitchInst *SI, unsigned CaseNum) : ParentTy(SI, CaseNum) {} /// Sets the new value for current case. void setValue(ConstantInt *V) { assert(Index < SI->getNumCases() && "Index out the number of cases."); SI->setOperand(2 + Index*2, reinterpret_cast(V)); } /// Sets the new successor for current case. void setSuccessor(BasicBlock *S) { SI->setSuccessor(getSuccessorIndex(), S); } }; static SwitchInst *Create(Value *Value, BasicBlock *Default, unsigned NumCases, Instruction *InsertBefore = nullptr) { return new SwitchInst(Value, Default, NumCases, InsertBefore); } static SwitchInst *Create(Value *Value, BasicBlock *Default, unsigned NumCases, BasicBlock *InsertAtEnd) { return new SwitchInst(Value, Default, NumCases, InsertAtEnd); } /// Provide fast operand accessors DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); // Accessor Methods for Switch stmt Value *getCondition() const { return getOperand(0); } void setCondition(Value *V) { setOperand(0, V); } BasicBlock *getDefaultDest() const { return cast(getOperand(1)); } void setDefaultDest(BasicBlock *DefaultCase) { setOperand(1, reinterpret_cast(DefaultCase)); } /// getNumCases - return the number of 'cases' in this switch instruction, /// except the default case unsigned getNumCases() const { return getNumOperands()/2 - 1; } /// Returns a read/write iterator that points to the first /// case in SwitchInst. CaseIt case_begin() { return CaseIt(this, 0); } /// Returns a read-only iterator that points to the first /// case in the SwitchInst. ConstCaseIt case_begin() const { return ConstCaseIt(this, 0); } /// Returns a read/write iterator that points one past the last /// in the SwitchInst. CaseIt case_end() { return CaseIt(this, getNumCases()); } /// Returns a read-only iterator that points one past the last /// in the SwitchInst. ConstCaseIt case_end() const { return ConstCaseIt(this, getNumCases()); } /// cases - iteration adapter for range-for loops. iterator_range cases() { return make_range(case_begin(), case_end()); } /// cases - iteration adapter for range-for loops. iterator_range cases() const { return make_range(case_begin(), case_end()); } /// Returns an iterator that points to the default case. /// Note: this iterator allows to resolve successor only. Attempt /// to resolve case value causes an assertion. /// Also note, that increment and decrement also causes an assertion and /// makes iterator invalid. CaseIt case_default() { return CaseIt(this, DefaultPseudoIndex); } ConstCaseIt case_default() const { return ConstCaseIt(this, DefaultPseudoIndex); } /// findCaseValue - Search all of the case values for the specified constant. /// If it is explicitly handled, return the case iterator of it, otherwise /// return default case iterator to indicate /// that it is handled by the default handler. CaseIt findCaseValue(const ConstantInt *C) { for (CaseIt i = case_begin(), e = case_end(); i != e; ++i) if (i.getCaseValue() == C) return i; return case_default(); } ConstCaseIt findCaseValue(const ConstantInt *C) const { for (ConstCaseIt i = case_begin(), e = case_end(); i != e; ++i) if (i.getCaseValue() == C) return i; return case_default(); } /// findCaseDest - Finds the unique case value for a given successor. Returns /// null if the successor is not found, not unique, or is the default case. ConstantInt *findCaseDest(BasicBlock *BB) { if (BB == getDefaultDest()) return nullptr; ConstantInt *CI = nullptr; for (CaseIt i = case_begin(), e = case_end(); i != e; ++i) { if (i.getCaseSuccessor() == BB) { if (CI) return nullptr; // Multiple cases lead to BB. else CI = i.getCaseValue(); } } return CI; } /// addCase - Add an entry to the switch instruction... /// Note: /// This action invalidates case_end(). Old case_end() iterator will /// point to the added case. void addCase(ConstantInt *OnVal, BasicBlock *Dest); /// removeCase - This method removes the specified case and its successor /// from the switch instruction. Note that this operation may reorder the /// remaining cases at index idx and above. /// Note: /// This action invalidates iterators for all cases following the one removed, /// including the case_end() iterator. void removeCase(CaseIt i); unsigned getNumSuccessors() const { return getNumOperands()/2; } BasicBlock *getSuccessor(unsigned idx) const { assert(idx < getNumSuccessors() &&"Successor idx out of range for switch!"); return cast(getOperand(idx*2+1)); } void setSuccessor(unsigned idx, BasicBlock *NewSucc) { assert(idx < getNumSuccessors() && "Successor # out of range for switch!"); setOperand(idx * 2 + 1, NewSucc); } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::Switch; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: BasicBlock *getSuccessorV(unsigned idx) const override; unsigned getNumSuccessorsV() const override; void setSuccessorV(unsigned idx, BasicBlock *B) override; }; template <> struct OperandTraits : public HungoffOperandTraits<2> { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(SwitchInst, Value) //===----------------------------------------------------------------------===// // IndirectBrInst Class //===----------------------------------------------------------------------===// //===--------------------------------------------------------------------------- /// IndirectBrInst - Indirect Branch Instruction. /// class IndirectBrInst : public TerminatorInst { void *operator new(size_t, unsigned) = delete; unsigned ReservedSpace; // Operand[0] = Value to switch on // Operand[1] = Default basic block destination // Operand[2n ] = Value to match // Operand[2n+1] = BasicBlock to go to on match IndirectBrInst(const IndirectBrInst &IBI); void init(Value *Address, unsigned NumDests); void growOperands(); // allocate space for exactly zero operands void *operator new(size_t s) { return User::operator new(s); } /// IndirectBrInst ctor - Create a new indirectbr instruction, specifying an /// Address to jump to. The number of expected destinations can be specified /// here to make memory allocation more efficient. This constructor can also /// autoinsert before another instruction. IndirectBrInst(Value *Address, unsigned NumDests, Instruction *InsertBefore); /// IndirectBrInst ctor - Create a new indirectbr instruction, specifying an /// Address to jump to. The number of expected destinations can be specified /// here to make memory allocation more efficient. This constructor also /// autoinserts at the end of the specified BasicBlock. IndirectBrInst(Value *Address, unsigned NumDests, BasicBlock *InsertAtEnd); protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; IndirectBrInst *cloneImpl() const; public: static IndirectBrInst *Create(Value *Address, unsigned NumDests, Instruction *InsertBefore = nullptr) { return new IndirectBrInst(Address, NumDests, InsertBefore); } static IndirectBrInst *Create(Value *Address, unsigned NumDests, BasicBlock *InsertAtEnd) { return new IndirectBrInst(Address, NumDests, InsertAtEnd); } /// Provide fast operand accessors. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); // Accessor Methods for IndirectBrInst instruction. Value *getAddress() { return getOperand(0); } const Value *getAddress() const { return getOperand(0); } void setAddress(Value *V) { setOperand(0, V); } /// getNumDestinations - return the number of possible destinations in this /// indirectbr instruction. unsigned getNumDestinations() const { return getNumOperands()-1; } /// getDestination - Return the specified destination. BasicBlock *getDestination(unsigned i) { return getSuccessor(i); } const BasicBlock *getDestination(unsigned i) const { return getSuccessor(i); } /// addDestination - Add a destination. /// void addDestination(BasicBlock *Dest); /// removeDestination - This method removes the specified successor from the /// indirectbr instruction. void removeDestination(unsigned i); unsigned getNumSuccessors() const { return getNumOperands()-1; } BasicBlock *getSuccessor(unsigned i) const { return cast(getOperand(i+1)); } void setSuccessor(unsigned i, BasicBlock *NewSucc) { setOperand(i + 1, NewSucc); } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::IndirectBr; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: BasicBlock *getSuccessorV(unsigned idx) const override; unsigned getNumSuccessorsV() const override; void setSuccessorV(unsigned idx, BasicBlock *B) override; }; template <> struct OperandTraits : public HungoffOperandTraits<1> { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(IndirectBrInst, Value) //===----------------------------------------------------------------------===// // InvokeInst Class //===----------------------------------------------------------------------===// /// InvokeInst - Invoke instruction. The SubclassData field is used to hold the /// calling convention of the call. /// class InvokeInst : public TerminatorInst, public OperandBundleUser { AttributeSet AttributeList; FunctionType *FTy; InvokeInst(const InvokeInst &BI); void init(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef Args, ArrayRef Bundles, const Twine &NameStr) { init(cast( cast(Func->getType())->getElementType()), Func, IfNormal, IfException, Args, Bundles, NameStr); } void init(FunctionType *FTy, Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef Args, ArrayRef Bundles, const Twine &NameStr); /// Construct an InvokeInst given a range of arguments. /// /// \brief Construct an InvokeInst from a range of arguments inline InvokeInst(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef Args, ArrayRef Bundles, unsigned Values, const Twine &NameStr, Instruction *InsertBefore) : InvokeInst(cast( cast(Func->getType())->getElementType()), Func, IfNormal, IfException, Args, Bundles, Values, NameStr, InsertBefore) {} inline InvokeInst(FunctionType *Ty, Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef Args, ArrayRef Bundles, unsigned Values, const Twine &NameStr, Instruction *InsertBefore); /// Construct an InvokeInst given a range of arguments. /// /// \brief Construct an InvokeInst from a range of arguments inline InvokeInst(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef Args, ArrayRef Bundles, unsigned Values, const Twine &NameStr, BasicBlock *InsertAtEnd); friend class OperandBundleUser; bool hasDescriptor() const { return HasDescriptor; } protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; InvokeInst *cloneImpl() const; public: static InvokeInst *Create(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef Args, const Twine &NameStr, Instruction *InsertBefore = nullptr) { return Create(cast( cast(Func->getType())->getElementType()), Func, IfNormal, IfException, Args, None, NameStr, InsertBefore); } static InvokeInst *Create(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef Args, ArrayRef Bundles = None, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { return Create(cast( cast(Func->getType())->getElementType()), Func, IfNormal, IfException, Args, Bundles, NameStr, InsertBefore); } static InvokeInst *Create(FunctionType *Ty, Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef Args, const Twine &NameStr, Instruction *InsertBefore = nullptr) { unsigned Values = unsigned(Args.size()) + 3; return new (Values) InvokeInst(Ty, Func, IfNormal, IfException, Args, None, Values, NameStr, InsertBefore); } static InvokeInst *Create(FunctionType *Ty, Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef Args, ArrayRef Bundles = None, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { unsigned Values = unsigned(Args.size()) + CountBundleInputs(Bundles) + 3; unsigned DescriptorBytes = Bundles.size() * sizeof(BundleOpInfo); return new (Values, DescriptorBytes) InvokeInst(Ty, Func, IfNormal, IfException, Args, Bundles, Values, NameStr, InsertBefore); } static InvokeInst *Create(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef Args, const Twine &NameStr, BasicBlock *InsertAtEnd) { unsigned Values = unsigned(Args.size()) + 3; return new (Values) InvokeInst(Func, IfNormal, IfException, Args, None, Values, NameStr, InsertAtEnd); } static InvokeInst *Create(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef Args, ArrayRef Bundles, const Twine &NameStr, BasicBlock *InsertAtEnd) { unsigned Values = unsigned(Args.size()) + CountBundleInputs(Bundles) + 3; unsigned DescriptorBytes = Bundles.size() * sizeof(BundleOpInfo); return new (Values, DescriptorBytes) InvokeInst(Func, IfNormal, IfException, Args, Bundles, Values, NameStr, InsertAtEnd); } /// \brief Create a clone of \p II with a different set of operand bundles and /// insert it before \p InsertPt. /// /// The returned invoke instruction is identical to \p II in every way except /// that the operand bundles for the new instruction are set to the operand /// bundles in \p Bundles. static InvokeInst *Create(InvokeInst *II, ArrayRef Bundles, Instruction *InsertPt = nullptr); /// Provide fast operand accessors DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); FunctionType *getFunctionType() const { return FTy; } void mutateFunctionType(FunctionType *FTy) { mutateType(FTy->getReturnType()); this->FTy = FTy; } /// getNumArgOperands - Return the number of invoke arguments. /// unsigned getNumArgOperands() const { return getNumOperands() - getNumTotalBundleOperands() - 3; } /// getArgOperand/setArgOperand - Return/set the i-th invoke argument. /// Value *getArgOperand(unsigned i) const { assert(i < getNumArgOperands() && "Out of bounds!"); return getOperand(i); } void setArgOperand(unsigned i, Value *v) { assert(i < getNumArgOperands() && "Out of bounds!"); setOperand(i, v); } /// \brief Return the iterator pointing to the beginning of the argument list. op_iterator arg_begin() { return op_begin(); } /// \brief Return the iterator pointing to the end of the argument list. op_iterator arg_end() { // [ invoke args ], [ operand bundles ], normal dest, unwind dest, callee return op_end() - getNumTotalBundleOperands() - 3; }; /// \brief Iteration adapter for range-for loops. iterator_range arg_operands() { return make_range(arg_begin(), arg_end()); } /// \brief Return the iterator pointing to the beginning of the argument list. const_op_iterator arg_begin() const { return op_begin(); } /// \brief Return the iterator pointing to the end of the argument list. const_op_iterator arg_end() const { // [ invoke args ], [ operand bundles ], normal dest, unwind dest, callee return op_end() - getNumTotalBundleOperands() - 3; }; /// \brief Iteration adapter for range-for loops. iterator_range arg_operands() const { return make_range(arg_begin(), arg_end()); } /// \brief Wrappers for getting the \c Use of a invoke argument. const Use &getArgOperandUse(unsigned i) const { assert(i < getNumArgOperands() && "Out of bounds!"); return getOperandUse(i); } Use &getArgOperandUse(unsigned i) { assert(i < getNumArgOperands() && "Out of bounds!"); return getOperandUse(i); } /// getCallingConv/setCallingConv - Get or set the calling convention of this /// function call. CallingConv::ID getCallingConv() const { return static_cast(getSubclassDataFromInstruction()); } void setCallingConv(CallingConv::ID CC) { auto ID = static_cast(CC); assert(!(ID & ~CallingConv::MaxID) && "Unsupported calling convention"); setInstructionSubclassData(ID); } /// getAttributes - Return the parameter attributes for this invoke. /// const AttributeSet &getAttributes() const { return AttributeList; } /// setAttributes - Set the parameter attributes for this invoke. /// void setAttributes(const AttributeSet &Attrs) { AttributeList = Attrs; } /// addAttribute - adds the attribute to the list of attributes. void addAttribute(unsigned i, Attribute::AttrKind attr); /// removeAttribute - removes the attribute from the list of attributes. void removeAttribute(unsigned i, Attribute attr); /// \brief adds the dereferenceable attribute to the list of attributes. void addDereferenceableAttr(unsigned i, uint64_t Bytes); /// \brief adds the dereferenceable_or_null attribute to the list of /// attributes. void addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes); /// \brief Determine whether this call has the given attribute. bool hasFnAttr(Attribute::AttrKind A) const { assert(A != Attribute::NoBuiltin && "Use CallInst::isNoBuiltin() to check for Attribute::NoBuiltin"); return hasFnAttrImpl(A); } /// \brief Determine whether this call has the given attribute. bool hasFnAttr(StringRef A) const { return hasFnAttrImpl(A); } /// \brief Determine whether the call or the callee has the given attributes. bool paramHasAttr(unsigned i, Attribute::AttrKind A) const; /// \brief Return true if the data operand at index \p i has the attribute \p /// A. /// /// Data operands include invoke arguments and values used in operand bundles, /// but does not include the invokee operand, or the two successor blocks. /// This routine dispatches to the underlying AttributeList or the /// OperandBundleUser as appropriate. /// /// The index \p i is interpreted as /// /// \p i == Attribute::ReturnIndex -> the return value /// \p i in [1, arg_size + 1) -> argument number (\p i - 1) /// \p i in [arg_size + 1, data_operand_size + 1) -> bundle operand at index /// (\p i - 1) in the operand list. bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind A) const; /// \brief Extract the alignment for a call or parameter (0=unknown). unsigned getParamAlignment(unsigned i) const { return AttributeList.getParamAlignment(i); } /// \brief Extract the number of dereferenceable bytes for a call or /// parameter (0=unknown). uint64_t getDereferenceableBytes(unsigned i) const { return AttributeList.getDereferenceableBytes(i); } /// \brief Extract the number of dereferenceable_or_null bytes for a call or /// parameter (0=unknown). uint64_t getDereferenceableOrNullBytes(unsigned i) const { return AttributeList.getDereferenceableOrNullBytes(i); } /// @brief Determine if the parameter or return value is marked with NoAlias /// attribute. /// @param n The parameter to check. 1 is the first parameter, 0 is the return bool doesNotAlias(unsigned n) const { return AttributeList.hasAttribute(n, Attribute::NoAlias); } /// \brief Return true if the call should not be treated as a call to a /// builtin. bool isNoBuiltin() const { // We assert in hasFnAttr if one passes in Attribute::NoBuiltin, so we have // to check it by hand. return hasFnAttrImpl(Attribute::NoBuiltin) && !hasFnAttrImpl(Attribute::Builtin); } /// \brief Return true if the call should not be inlined. bool isNoInline() const { return hasFnAttr(Attribute::NoInline); } void setIsNoInline() { addAttribute(AttributeSet::FunctionIndex, Attribute::NoInline); } /// \brief Determine if the call does not access memory. bool doesNotAccessMemory() const { return hasFnAttr(Attribute::ReadNone); } void setDoesNotAccessMemory() { addAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone); } /// \brief Determine if the call does not access or only reads memory. bool onlyReadsMemory() const { return doesNotAccessMemory() || hasFnAttr(Attribute::ReadOnly); } void setOnlyReadsMemory() { addAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly); } /// @brief Determine if the call access memmory only using it's pointer /// arguments. bool onlyAccessesArgMemory() const { return hasFnAttr(Attribute::ArgMemOnly); } void setOnlyAccessesArgMemory() { addAttribute(AttributeSet::FunctionIndex, Attribute::ArgMemOnly); } /// \brief Determine if the call cannot return. bool doesNotReturn() const { return hasFnAttr(Attribute::NoReturn); } void setDoesNotReturn() { addAttribute(AttributeSet::FunctionIndex, Attribute::NoReturn); } /// \brief Determine if the call cannot unwind. bool doesNotThrow() const { return hasFnAttr(Attribute::NoUnwind); } void setDoesNotThrow() { addAttribute(AttributeSet::FunctionIndex, Attribute::NoUnwind); } /// \brief Determine if the invoke cannot be duplicated. bool cannotDuplicate() const {return hasFnAttr(Attribute::NoDuplicate); } void setCannotDuplicate() { addAttribute(AttributeSet::FunctionIndex, Attribute::NoDuplicate); } /// \brief Determine if the call returns a structure through first /// pointer argument. bool hasStructRetAttr() const { if (getNumArgOperands() == 0) return false; // Be friendly and also check the callee. return paramHasAttr(1, Attribute::StructRet); } /// \brief Determine if any call argument is an aggregate passed by value. bool hasByValArgument() const { return AttributeList.hasAttrSomewhere(Attribute::ByVal); } /// getCalledFunction - Return the function called, or null if this is an /// indirect function invocation. /// Function *getCalledFunction() const { return dyn_cast(Op<-3>()); } /// getCalledValue - Get a pointer to the function that is invoked by this /// instruction const Value *getCalledValue() const { return Op<-3>(); } Value *getCalledValue() { return Op<-3>(); } /// setCalledFunction - Set the function called. void setCalledFunction(Value* Fn) { setCalledFunction( cast(cast(Fn->getType())->getElementType()), Fn); } void setCalledFunction(FunctionType *FTy, Value *Fn) { this->FTy = FTy; assert(FTy == cast( cast(Fn->getType())->getElementType())); Op<-3>() = Fn; } // get*Dest - Return the destination basic blocks... BasicBlock *getNormalDest() const { return cast(Op<-2>()); } BasicBlock *getUnwindDest() const { return cast(Op<-1>()); } void setNormalDest(BasicBlock *B) { Op<-2>() = reinterpret_cast(B); } void setUnwindDest(BasicBlock *B) { Op<-1>() = reinterpret_cast(B); } /// getLandingPadInst - Get the landingpad instruction from the landing pad /// block (the unwind destination). LandingPadInst *getLandingPadInst() const; BasicBlock *getSuccessor(unsigned i) const { assert(i < 2 && "Successor # out of range for invoke!"); return i == 0 ? getNormalDest() : getUnwindDest(); } void setSuccessor(unsigned idx, BasicBlock *NewSucc) { assert(idx < 2 && "Successor # out of range for invoke!"); *(&Op<-2>() + idx) = reinterpret_cast(NewSucc); } unsigned getNumSuccessors() const { return 2; } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return (I->getOpcode() == Instruction::Invoke); } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: BasicBlock *getSuccessorV(unsigned idx) const override; unsigned getNumSuccessorsV() const override; void setSuccessorV(unsigned idx, BasicBlock *B) override; template bool hasFnAttrImpl(AttrKind A) const { if (AttributeList.hasAttribute(AttributeSet::FunctionIndex, A)) return true; // Operand bundles override attributes on the called function, but don't // override attributes directly present on the invoke instruction. if (isFnAttrDisallowedByOpBundle(A)) return false; if (const Function *F = getCalledFunction()) return F->getAttributes().hasAttribute(AttributeSet::FunctionIndex, A); return false; } // Shadow Instruction::setInstructionSubclassData with a private forwarding // method so that subclasses cannot accidentally use it. void setInstructionSubclassData(unsigned short D) { Instruction::setInstructionSubclassData(D); } }; template <> struct OperandTraits : public VariadicOperandTraits { }; InvokeInst::InvokeInst(FunctionType *Ty, Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef Args, ArrayRef Bundles, unsigned Values, const Twine &NameStr, Instruction *InsertBefore) : TerminatorInst(Ty->getReturnType(), Instruction::Invoke, OperandTraits::op_end(this) - Values, Values, InsertBefore) { init(Ty, Func, IfNormal, IfException, Args, Bundles, NameStr); } InvokeInst::InvokeInst(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef Args, ArrayRef Bundles, unsigned Values, const Twine &NameStr, BasicBlock *InsertAtEnd) : TerminatorInst( cast(cast(Func->getType()) ->getElementType())->getReturnType(), Instruction::Invoke, OperandTraits::op_end(this) - Values, Values, InsertAtEnd) { init(Func, IfNormal, IfException, Args, Bundles, NameStr); } DEFINE_TRANSPARENT_OPERAND_ACCESSORS(InvokeInst, Value) //===----------------------------------------------------------------------===// // ResumeInst Class //===----------------------------------------------------------------------===// //===--------------------------------------------------------------------------- /// ResumeInst - Resume the propagation of an exception. /// class ResumeInst : public TerminatorInst { ResumeInst(const ResumeInst &RI); explicit ResumeInst(Value *Exn, Instruction *InsertBefore=nullptr); ResumeInst(Value *Exn, BasicBlock *InsertAtEnd); protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; ResumeInst *cloneImpl() const; public: static ResumeInst *Create(Value *Exn, Instruction *InsertBefore = nullptr) { return new(1) ResumeInst(Exn, InsertBefore); } static ResumeInst *Create(Value *Exn, BasicBlock *InsertAtEnd) { return new(1) ResumeInst(Exn, InsertAtEnd); } /// Provide fast operand accessors DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); /// Convenience accessor. Value *getValue() const { return Op<0>(); } unsigned getNumSuccessors() const { return 0; } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::Resume; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: BasicBlock *getSuccessorV(unsigned idx) const override; unsigned getNumSuccessorsV() const override; void setSuccessorV(unsigned idx, BasicBlock *B) override; }; template <> struct OperandTraits : public FixedNumOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ResumeInst, Value) //===----------------------------------------------------------------------===// // CatchSwitchInst Class //===----------------------------------------------------------------------===// class CatchSwitchInst : public TerminatorInst { void *operator new(size_t, unsigned) = delete; /// ReservedSpace - The number of operands actually allocated. NumOperands is /// the number actually in use. unsigned ReservedSpace; // Operand[0] = Outer scope // Operand[1] = Unwind block destination // Operand[n] = BasicBlock to go to on match CatchSwitchInst(const CatchSwitchInst &CSI); void init(Value *ParentPad, BasicBlock *UnwindDest, unsigned NumReserved); void growOperands(unsigned Size); // allocate space for exactly zero operands void *operator new(size_t s) { return User::operator new(s); } /// CatchSwitchInst ctor - Create a new switch instruction, specifying a /// default destination. The number of additional handlers can be specified /// here to make memory allocation more efficient. /// This constructor can also autoinsert before another instruction. CatchSwitchInst(Value *ParentPad, BasicBlock *UnwindDest, unsigned NumHandlers, const Twine &NameStr, Instruction *InsertBefore); /// CatchSwitchInst ctor - Create a new switch instruction, specifying a /// default destination. The number of additional handlers can be specified /// here to make memory allocation more efficient. /// This constructor also autoinserts at the end of the specified BasicBlock. CatchSwitchInst(Value *ParentPad, BasicBlock *UnwindDest, unsigned NumHandlers, const Twine &NameStr, BasicBlock *InsertAtEnd); protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; CatchSwitchInst *cloneImpl() const; public: static CatchSwitchInst *Create(Value *ParentPad, BasicBlock *UnwindDest, unsigned NumHandlers, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { return new CatchSwitchInst(ParentPad, UnwindDest, NumHandlers, NameStr, InsertBefore); } static CatchSwitchInst *Create(Value *ParentPad, BasicBlock *UnwindDest, unsigned NumHandlers, const Twine &NameStr, BasicBlock *InsertAtEnd) { return new CatchSwitchInst(ParentPad, UnwindDest, NumHandlers, NameStr, InsertAtEnd); } /// Provide fast operand accessors DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); // Accessor Methods for CatchSwitch stmt Value *getParentPad() const { return getOperand(0); } void setParentPad(Value *ParentPad) { setOperand(0, ParentPad); } // Accessor Methods for CatchSwitch stmt bool hasUnwindDest() const { return getSubclassDataFromInstruction() & 1; } bool unwindsToCaller() const { return !hasUnwindDest(); } BasicBlock *getUnwindDest() const { if (hasUnwindDest()) return cast(getOperand(1)); return nullptr; } void setUnwindDest(BasicBlock *UnwindDest) { assert(UnwindDest); assert(hasUnwindDest()); setOperand(1, UnwindDest); } /// getNumHandlers - return the number of 'handlers' in this catchswitch /// instruction, except the default handler unsigned getNumHandlers() const { if (hasUnwindDest()) return getNumOperands() - 2; return getNumOperands() - 1; } private: static BasicBlock *handler_helper(Value *V) { return cast(V); } static const BasicBlock *handler_helper(const Value *V) { return cast(V); } public: typedef std::pointer_to_unary_function DerefFnTy; typedef mapped_iterator handler_iterator; typedef iterator_range handler_range; typedef std::pointer_to_unary_function ConstDerefFnTy; typedef mapped_iterator const_handler_iterator; typedef iterator_range const_handler_range; /// Returns an iterator that points to the first handler in CatchSwitchInst. handler_iterator handler_begin() { op_iterator It = op_begin() + 1; if (hasUnwindDest()) ++It; return handler_iterator(It, DerefFnTy(handler_helper)); } /// Returns an iterator that points to the first handler in the /// CatchSwitchInst. const_handler_iterator handler_begin() const { const_op_iterator It = op_begin() + 1; if (hasUnwindDest()) ++It; return const_handler_iterator(It, ConstDerefFnTy(handler_helper)); } /// Returns a read-only iterator that points one past the last /// handler in the CatchSwitchInst. handler_iterator handler_end() { return handler_iterator(op_end(), DerefFnTy(handler_helper)); } /// Returns an iterator that points one past the last handler in the /// CatchSwitchInst. const_handler_iterator handler_end() const { return const_handler_iterator(op_end(), ConstDerefFnTy(handler_helper)); } /// handlers - iteration adapter for range-for loops. handler_range handlers() { return make_range(handler_begin(), handler_end()); } /// handlers - iteration adapter for range-for loops. const_handler_range handlers() const { return make_range(handler_begin(), handler_end()); } /// addHandler - Add an entry to the switch instruction... /// Note: /// This action invalidates handler_end(). Old handler_end() iterator will /// point to the added handler. void addHandler(BasicBlock *Dest); void removeHandler(handler_iterator HI); unsigned getNumSuccessors() const { return getNumOperands() - 1; } BasicBlock *getSuccessor(unsigned Idx) const { assert(Idx < getNumSuccessors() && "Successor # out of range for catchswitch!"); return cast(getOperand(Idx + 1)); } void setSuccessor(unsigned Idx, BasicBlock *NewSucc) { assert(Idx < getNumSuccessors() && "Successor # out of range for catchswitch!"); setOperand(Idx + 1, NewSucc); } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::CatchSwitch; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: BasicBlock *getSuccessorV(unsigned Idx) const override; unsigned getNumSuccessorsV() const override; void setSuccessorV(unsigned Idx, BasicBlock *B) override; }; template <> struct OperandTraits : public HungoffOperandTraits<2> {}; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CatchSwitchInst, Value) //===----------------------------------------------------------------------===// // CleanupPadInst Class //===----------------------------------------------------------------------===// class CleanupPadInst : public FuncletPadInst { private: explicit CleanupPadInst(Value *ParentPad, ArrayRef Args, unsigned Values, const Twine &NameStr, Instruction *InsertBefore) : FuncletPadInst(Instruction::CleanupPad, ParentPad, Args, Values, NameStr, InsertBefore) {} explicit CleanupPadInst(Value *ParentPad, ArrayRef Args, unsigned Values, const Twine &NameStr, BasicBlock *InsertAtEnd) : FuncletPadInst(Instruction::CleanupPad, ParentPad, Args, Values, NameStr, InsertAtEnd) {} public: static CleanupPadInst *Create(Value *ParentPad, ArrayRef Args = None, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { unsigned Values = 1 + Args.size(); return new (Values) CleanupPadInst(ParentPad, Args, Values, NameStr, InsertBefore); } static CleanupPadInst *Create(Value *ParentPad, ArrayRef Args, const Twine &NameStr, BasicBlock *InsertAtEnd) { unsigned Values = 1 + Args.size(); return new (Values) CleanupPadInst(ParentPad, Args, Values, NameStr, InsertAtEnd); } /// \brief Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::CleanupPad; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; //===----------------------------------------------------------------------===// // CatchPadInst Class //===----------------------------------------------------------------------===// class CatchPadInst : public FuncletPadInst { private: explicit CatchPadInst(Value *CatchSwitch, ArrayRef Args, unsigned Values, const Twine &NameStr, Instruction *InsertBefore) : FuncletPadInst(Instruction::CatchPad, CatchSwitch, Args, Values, NameStr, InsertBefore) {} explicit CatchPadInst(Value *CatchSwitch, ArrayRef Args, unsigned Values, const Twine &NameStr, BasicBlock *InsertAtEnd) : FuncletPadInst(Instruction::CatchPad, CatchSwitch, Args, Values, NameStr, InsertAtEnd) {} public: static CatchPadInst *Create(Value *CatchSwitch, ArrayRef Args, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { unsigned Values = 1 + Args.size(); return new (Values) CatchPadInst(CatchSwitch, Args, Values, NameStr, InsertBefore); } static CatchPadInst *Create(Value *CatchSwitch, ArrayRef Args, const Twine &NameStr, BasicBlock *InsertAtEnd) { unsigned Values = 1 + Args.size(); return new (Values) CatchPadInst(CatchSwitch, Args, Values, NameStr, InsertAtEnd); } /// Convenience accessors CatchSwitchInst *getCatchSwitch() const { return cast(Op<-1>()); } void setCatchSwitch(Value *CatchSwitch) { assert(CatchSwitch); Op<-1>() = CatchSwitch; } /// \brief Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::CatchPad; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; //===----------------------------------------------------------------------===// // CatchReturnInst Class //===----------------------------------------------------------------------===// class CatchReturnInst : public TerminatorInst { CatchReturnInst(const CatchReturnInst &RI); void init(Value *CatchPad, BasicBlock *BB); CatchReturnInst(Value *CatchPad, BasicBlock *BB, Instruction *InsertBefore); CatchReturnInst(Value *CatchPad, BasicBlock *BB, BasicBlock *InsertAtEnd); protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; CatchReturnInst *cloneImpl() const; public: static CatchReturnInst *Create(Value *CatchPad, BasicBlock *BB, Instruction *InsertBefore = nullptr) { assert(CatchPad); assert(BB); return new (2) CatchReturnInst(CatchPad, BB, InsertBefore); } static CatchReturnInst *Create(Value *CatchPad, BasicBlock *BB, BasicBlock *InsertAtEnd) { assert(CatchPad); assert(BB); return new (2) CatchReturnInst(CatchPad, BB, InsertAtEnd); } /// Provide fast operand accessors DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); /// Convenience accessors. CatchPadInst *getCatchPad() const { return cast(Op<0>()); } void setCatchPad(CatchPadInst *CatchPad) { assert(CatchPad); Op<0>() = CatchPad; } BasicBlock *getSuccessor() const { return cast(Op<1>()); } void setSuccessor(BasicBlock *NewSucc) { assert(NewSucc); Op<1>() = NewSucc; } unsigned getNumSuccessors() const { return 1; } Value *getParentPad() const { return getCatchPad()->getCatchSwitch()->getParentPad(); } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return (I->getOpcode() == Instruction::CatchRet); } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: BasicBlock *getSuccessorV(unsigned Idx) const override; unsigned getNumSuccessorsV() const override; void setSuccessorV(unsigned Idx, BasicBlock *B) override; }; template <> struct OperandTraits : public FixedNumOperandTraits {}; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CatchReturnInst, Value) //===----------------------------------------------------------------------===// // CleanupReturnInst Class //===----------------------------------------------------------------------===// class CleanupReturnInst : public TerminatorInst { private: CleanupReturnInst(const CleanupReturnInst &RI); void init(Value *CleanupPad, BasicBlock *UnwindBB); CleanupReturnInst(Value *CleanupPad, BasicBlock *UnwindBB, unsigned Values, Instruction *InsertBefore = nullptr); CleanupReturnInst(Value *CleanupPad, BasicBlock *UnwindBB, unsigned Values, BasicBlock *InsertAtEnd); protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; CleanupReturnInst *cloneImpl() const; public: static CleanupReturnInst *Create(Value *CleanupPad, BasicBlock *UnwindBB = nullptr, Instruction *InsertBefore = nullptr) { assert(CleanupPad); unsigned Values = 1; if (UnwindBB) ++Values; return new (Values) CleanupReturnInst(CleanupPad, UnwindBB, Values, InsertBefore); } static CleanupReturnInst *Create(Value *CleanupPad, BasicBlock *UnwindBB, BasicBlock *InsertAtEnd) { assert(CleanupPad); unsigned Values = 1; if (UnwindBB) ++Values; return new (Values) CleanupReturnInst(CleanupPad, UnwindBB, Values, InsertAtEnd); } /// Provide fast operand accessors DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); bool hasUnwindDest() const { return getSubclassDataFromInstruction() & 1; } bool unwindsToCaller() const { return !hasUnwindDest(); } /// Convenience accessor. CleanupPadInst *getCleanupPad() const { return cast(Op<0>()); } void setCleanupPad(CleanupPadInst *CleanupPad) { assert(CleanupPad); Op<0>() = CleanupPad; } unsigned getNumSuccessors() const { return hasUnwindDest() ? 1 : 0; } BasicBlock *getUnwindDest() const { return hasUnwindDest() ? cast(Op<1>()) : nullptr; } void setUnwindDest(BasicBlock *NewDest) { assert(NewDest); assert(hasUnwindDest()); Op<1>() = NewDest; } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return (I->getOpcode() == Instruction::CleanupRet); } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: BasicBlock *getSuccessorV(unsigned Idx) const override; unsigned getNumSuccessorsV() const override; void setSuccessorV(unsigned Idx, BasicBlock *B) override; // Shadow Instruction::setInstructionSubclassData with a private forwarding // method so that subclasses cannot accidentally use it. void setInstructionSubclassData(unsigned short D) { Instruction::setInstructionSubclassData(D); } }; template <> struct OperandTraits : public VariadicOperandTraits {}; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CleanupReturnInst, Value) //===----------------------------------------------------------------------===// // UnreachableInst Class //===----------------------------------------------------------------------===// //===--------------------------------------------------------------------------- /// UnreachableInst - This function has undefined behavior. In particular, the /// presence of this instruction indicates some higher level knowledge that the /// end of the block cannot be reached. /// class UnreachableInst : public TerminatorInst { void *operator new(size_t, unsigned) = delete; protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; UnreachableInst *cloneImpl() const; public: // allocate space for exactly zero operands void *operator new(size_t s) { return User::operator new(s, 0); } explicit UnreachableInst(LLVMContext &C, Instruction *InsertBefore = nullptr); explicit UnreachableInst(LLVMContext &C, BasicBlock *InsertAtEnd); unsigned getNumSuccessors() const { return 0; } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::Unreachable; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: BasicBlock *getSuccessorV(unsigned idx) const override; unsigned getNumSuccessorsV() const override; void setSuccessorV(unsigned idx, BasicBlock *B) override; }; //===----------------------------------------------------------------------===// // TruncInst Class //===----------------------------------------------------------------------===// /// \brief This class represents a truncation of integer types. class TruncInst : public CastInst { protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; /// \brief Clone an identical TruncInst TruncInst *cloneImpl() const; public: /// \brief Constructor with insert-before-instruction semantics TruncInst( Value *S, ///< The value to be truncated Type *Ty, ///< The (smaller) type to truncate to const Twine &NameStr = "", ///< A name for the new instruction Instruction *InsertBefore = nullptr ///< Where to insert the new instruction ); /// \brief Constructor with insert-at-end-of-block semantics TruncInst( Value *S, ///< The value to be truncated Type *Ty, ///< The (smaller) type to truncate to const Twine &NameStr, ///< A name for the new instruction BasicBlock *InsertAtEnd ///< The block to insert the instruction into ); /// \brief Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Trunc; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; //===----------------------------------------------------------------------===// // ZExtInst Class //===----------------------------------------------------------------------===// /// \brief This class represents zero extension of integer types. class ZExtInst : public CastInst { protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; /// \brief Clone an identical ZExtInst ZExtInst *cloneImpl() const; public: /// \brief Constructor with insert-before-instruction semantics ZExtInst( Value *S, ///< The value to be zero extended Type *Ty, ///< The type to zero extend to const Twine &NameStr = "", ///< A name for the new instruction Instruction *InsertBefore = nullptr ///< Where to insert the new instruction ); /// \brief Constructor with insert-at-end semantics. ZExtInst( Value *S, ///< The value to be zero extended Type *Ty, ///< The type to zero extend to const Twine &NameStr, ///< A name for the new instruction BasicBlock *InsertAtEnd ///< The block to insert the instruction into ); /// \brief Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == ZExt; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; //===----------------------------------------------------------------------===// // SExtInst Class //===----------------------------------------------------------------------===// /// \brief This class represents a sign extension of integer types. class SExtInst : public CastInst { protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; /// \brief Clone an identical SExtInst SExtInst *cloneImpl() const; public: /// \brief Constructor with insert-before-instruction semantics SExtInst( Value *S, ///< The value to be sign extended Type *Ty, ///< The type to sign extend to const Twine &NameStr = "", ///< A name for the new instruction Instruction *InsertBefore = nullptr ///< Where to insert the new instruction ); /// \brief Constructor with insert-at-end-of-block semantics SExtInst( Value *S, ///< The value to be sign extended Type *Ty, ///< The type to sign extend to const Twine &NameStr, ///< A name for the new instruction BasicBlock *InsertAtEnd ///< The block to insert the instruction into ); /// \brief Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == SExt; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; //===----------------------------------------------------------------------===// // FPTruncInst Class //===----------------------------------------------------------------------===// /// \brief This class represents a truncation of floating point types. class FPTruncInst : public CastInst { protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; /// \brief Clone an identical FPTruncInst FPTruncInst *cloneImpl() const; public: /// \brief Constructor with insert-before-instruction semantics FPTruncInst( Value *S, ///< The value to be truncated Type *Ty, ///< The type to truncate to const Twine &NameStr = "", ///< A name for the new instruction Instruction *InsertBefore = nullptr ///< Where to insert the new instruction ); /// \brief Constructor with insert-before-instruction semantics FPTruncInst( Value *S, ///< The value to be truncated Type *Ty, ///< The type to truncate to const Twine &NameStr, ///< A name for the new instruction BasicBlock *InsertAtEnd ///< The block to insert the instruction into ); /// \brief Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == FPTrunc; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; //===----------------------------------------------------------------------===// // FPExtInst Class //===----------------------------------------------------------------------===// /// \brief This class represents an extension of floating point types. class FPExtInst : public CastInst { protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; /// \brief Clone an identical FPExtInst FPExtInst *cloneImpl() const; public: /// \brief Constructor with insert-before-instruction semantics FPExtInst( Value *S, ///< The value to be extended Type *Ty, ///< The type to extend to const Twine &NameStr = "", ///< A name for the new instruction Instruction *InsertBefore = nullptr ///< Where to insert the new instruction ); /// \brief Constructor with insert-at-end-of-block semantics FPExtInst( Value *S, ///< The value to be extended Type *Ty, ///< The type to extend to const Twine &NameStr, ///< A name for the new instruction BasicBlock *InsertAtEnd ///< The block to insert the instruction into ); /// \brief Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == FPExt; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; //===----------------------------------------------------------------------===// // UIToFPInst Class //===----------------------------------------------------------------------===// /// \brief This class represents a cast unsigned integer to floating point. class UIToFPInst : public CastInst { protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; /// \brief Clone an identical UIToFPInst UIToFPInst *cloneImpl() const; public: /// \brief Constructor with insert-before-instruction semantics UIToFPInst( Value *S, ///< The value to be converted Type *Ty, ///< The type to convert to const Twine &NameStr = "", ///< A name for the new instruction Instruction *InsertBefore = nullptr ///< Where to insert the new instruction ); /// \brief Constructor with insert-at-end-of-block semantics UIToFPInst( Value *S, ///< The value to be converted Type *Ty, ///< The type to convert to const Twine &NameStr, ///< A name for the new instruction BasicBlock *InsertAtEnd ///< The block to insert the instruction into ); /// \brief Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == UIToFP; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; //===----------------------------------------------------------------------===// // SIToFPInst Class //===----------------------------------------------------------------------===// /// \brief This class represents a cast from signed integer to floating point. class SIToFPInst : public CastInst { protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; /// \brief Clone an identical SIToFPInst SIToFPInst *cloneImpl() const; public: /// \brief Constructor with insert-before-instruction semantics SIToFPInst( Value *S, ///< The value to be converted Type *Ty, ///< The type to convert to const Twine &NameStr = "", ///< A name for the new instruction Instruction *InsertBefore = nullptr ///< Where to insert the new instruction ); /// \brief Constructor with insert-at-end-of-block semantics SIToFPInst( Value *S, ///< The value to be converted Type *Ty, ///< The type to convert to const Twine &NameStr, ///< A name for the new instruction BasicBlock *InsertAtEnd ///< The block to insert the instruction into ); /// \brief Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == SIToFP; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; //===----------------------------------------------------------------------===// // FPToUIInst Class //===----------------------------------------------------------------------===// /// \brief This class represents a cast from floating point to unsigned integer class FPToUIInst : public CastInst { protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; /// \brief Clone an identical FPToUIInst FPToUIInst *cloneImpl() const; public: /// \brief Constructor with insert-before-instruction semantics FPToUIInst( Value *S, ///< The value to be converted Type *Ty, ///< The type to convert to const Twine &NameStr = "", ///< A name for the new instruction Instruction *InsertBefore = nullptr ///< Where to insert the new instruction ); /// \brief Constructor with insert-at-end-of-block semantics FPToUIInst( Value *S, ///< The value to be converted Type *Ty, ///< The type to convert to const Twine &NameStr, ///< A name for the new instruction BasicBlock *InsertAtEnd ///< Where to insert the new instruction ); /// \brief Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == FPToUI; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; //===----------------------------------------------------------------------===// // FPToSIInst Class //===----------------------------------------------------------------------===// /// \brief This class represents a cast from floating point to signed integer. class FPToSIInst : public CastInst { protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; /// \brief Clone an identical FPToSIInst FPToSIInst *cloneImpl() const; public: /// \brief Constructor with insert-before-instruction semantics FPToSIInst( Value *S, ///< The value to be converted Type *Ty, ///< The type to convert to const Twine &NameStr = "", ///< A name for the new instruction Instruction *InsertBefore = nullptr ///< Where to insert the new instruction ); /// \brief Constructor with insert-at-end-of-block semantics FPToSIInst( Value *S, ///< The value to be converted Type *Ty, ///< The type to convert to const Twine &NameStr, ///< A name for the new instruction BasicBlock *InsertAtEnd ///< The block to insert the instruction into ); /// \brief Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == FPToSI; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; //===----------------------------------------------------------------------===// // IntToPtrInst Class //===----------------------------------------------------------------------===// /// \brief This class represents a cast from an integer to a pointer. class IntToPtrInst : public CastInst { public: /// \brief Constructor with insert-before-instruction semantics IntToPtrInst( Value *S, ///< The value to be converted Type *Ty, ///< The type to convert to const Twine &NameStr = "", ///< A name for the new instruction Instruction *InsertBefore = nullptr ///< Where to insert the new instruction ); /// \brief Constructor with insert-at-end-of-block semantics IntToPtrInst( Value *S, ///< The value to be converted Type *Ty, ///< The type to convert to const Twine &NameStr, ///< A name for the new instruction BasicBlock *InsertAtEnd ///< The block to insert the instruction into ); // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; /// \brief Clone an identical IntToPtrInst IntToPtrInst *cloneImpl() const; /// \brief Returns the address space of this instruction's pointer type. unsigned getAddressSpace() const { return getType()->getPointerAddressSpace(); } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == IntToPtr; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; //===----------------------------------------------------------------------===// // PtrToIntInst Class //===----------------------------------------------------------------------===// /// \brief This class represents a cast from a pointer to an integer class PtrToIntInst : public CastInst { protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; /// \brief Clone an identical PtrToIntInst PtrToIntInst *cloneImpl() const; public: /// \brief Constructor with insert-before-instruction semantics PtrToIntInst( Value *S, ///< The value to be converted Type *Ty, ///< The type to convert to const Twine &NameStr = "", ///< A name for the new instruction Instruction *InsertBefore = nullptr ///< Where to insert the new instruction ); /// \brief Constructor with insert-at-end-of-block semantics PtrToIntInst( Value *S, ///< The value to be converted Type *Ty, ///< The type to convert to const Twine &NameStr, ///< A name for the new instruction BasicBlock *InsertAtEnd ///< The block to insert the instruction into ); /// \brief Gets the pointer operand. Value *getPointerOperand() { return getOperand(0); } /// \brief Gets the pointer operand. const Value *getPointerOperand() const { return getOperand(0); } /// \brief Gets the operand index of the pointer operand. static unsigned getPointerOperandIndex() { return 0U; } /// \brief Returns the address space of the pointer operand. unsigned getPointerAddressSpace() const { return getPointerOperand()->getType()->getPointerAddressSpace(); } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == PtrToInt; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; //===----------------------------------------------------------------------===// // BitCastInst Class //===----------------------------------------------------------------------===// /// \brief This class represents a no-op cast from one type to another. class BitCastInst : public CastInst { protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; /// \brief Clone an identical BitCastInst BitCastInst *cloneImpl() const; public: /// \brief Constructor with insert-before-instruction semantics BitCastInst( Value *S, ///< The value to be casted Type *Ty, ///< The type to casted to const Twine &NameStr = "", ///< A name for the new instruction Instruction *InsertBefore = nullptr ///< Where to insert the new instruction ); /// \brief Constructor with insert-at-end-of-block semantics BitCastInst( Value *S, ///< The value to be casted Type *Ty, ///< The type to casted to const Twine &NameStr, ///< A name for the new instruction BasicBlock *InsertAtEnd ///< The block to insert the instruction into ); // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == BitCast; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; //===----------------------------------------------------------------------===// // AddrSpaceCastInst Class //===----------------------------------------------------------------------===// /// \brief This class represents a conversion between pointers from /// one address space to another. class AddrSpaceCastInst : public CastInst { protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; /// \brief Clone an identical AddrSpaceCastInst AddrSpaceCastInst *cloneImpl() const; public: /// \brief Constructor with insert-before-instruction semantics AddrSpaceCastInst( Value *S, ///< The value to be casted Type *Ty, ///< The type to casted to const Twine &NameStr = "", ///< A name for the new instruction Instruction *InsertBefore = nullptr ///< Where to insert the new instruction ); /// \brief Constructor with insert-at-end-of-block semantics AddrSpaceCastInst( Value *S, ///< The value to be casted Type *Ty, ///< The type to casted to const Twine &NameStr, ///< A name for the new instruction BasicBlock *InsertAtEnd ///< The block to insert the instruction into ); // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == AddrSpaceCast; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } }; } // End llvm namespace #endif Index: projects/clang380-import/contrib/llvm/lib/CodeGen/CalcSpillWeights.cpp =================================================================== --- projects/clang380-import/contrib/llvm/lib/CodeGen/CalcSpillWeights.cpp (revision 295858) +++ projects/clang380-import/contrib/llvm/lib/CodeGen/CalcSpillWeights.cpp (revision 295859) @@ -1,230 +1,233 @@ //===------------------------ CalcSpillWeights.cpp ------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/CodeGen/VirtRegMap.h" #include "llvm/CodeGen/CalcSpillWeights.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetSubtargetInfo.h" using namespace llvm; #define DEBUG_TYPE "calcspillweights" void llvm::calculateSpillWeightsAndHints(LiveIntervals &LIS, MachineFunction &MF, VirtRegMap *VRM, const MachineLoopInfo &MLI, const MachineBlockFrequencyInfo &MBFI, VirtRegAuxInfo::NormalizingFn norm) { DEBUG(dbgs() << "********** Compute Spill Weights **********\n" << "********** Function: " << MF.getName() << '\n'); MachineRegisterInfo &MRI = MF.getRegInfo(); VirtRegAuxInfo VRAI(MF, LIS, VRM, MLI, MBFI, norm); for (unsigned i = 0, e = MRI.getNumVirtRegs(); i != e; ++i) { unsigned Reg = TargetRegisterInfo::index2VirtReg(i); if (MRI.reg_nodbg_empty(Reg)) continue; VRAI.calculateSpillWeightAndHint(LIS.getInterval(Reg)); } } // Return the preferred allocation register for reg, given a COPY instruction. static unsigned copyHint(const MachineInstr *mi, unsigned reg, const TargetRegisterInfo &tri, const MachineRegisterInfo &mri) { unsigned sub, hreg, hsub; if (mi->getOperand(0).getReg() == reg) { sub = mi->getOperand(0).getSubReg(); hreg = mi->getOperand(1).getReg(); hsub = mi->getOperand(1).getSubReg(); } else { sub = mi->getOperand(1).getSubReg(); hreg = mi->getOperand(0).getReg(); hsub = mi->getOperand(0).getSubReg(); } if (!hreg) return 0; if (TargetRegisterInfo::isVirtualRegister(hreg)) return sub == hsub ? hreg : 0; const TargetRegisterClass *rc = mri.getRegClass(reg); // Only allow physreg hints in rc. if (sub == 0) return rc->contains(hreg) ? hreg : 0; // reg:sub should match the physreg hreg. return tri.getMatchingSuperReg(hreg, sub, rc); } // Check if all values in LI are rematerializable static bool isRematerializable(const LiveInterval &LI, const LiveIntervals &LIS, VirtRegMap *VRM, const TargetInstrInfo &TII) { unsigned Reg = LI.reg; unsigned Original = VRM ? VRM->getOriginal(Reg) : 0; for (LiveInterval::const_vni_iterator I = LI.vni_begin(), E = LI.vni_end(); I != E; ++I) { const VNInfo *VNI = *I; if (VNI->isUnused()) continue; if (VNI->isPHIDef()) return false; MachineInstr *MI = LIS.getInstructionFromIndex(VNI->def); assert(MI && "Dead valno in interval"); // Trace copies introduced by live range splitting. The inline // spiller can rematerialize through these copies, so the spill // weight must reflect this. if (VRM) { while (MI->isFullCopy()) { // The copy destination must match the interval register. if (MI->getOperand(0).getReg() != Reg) return false; // Get the source register. Reg = MI->getOperand(1).getReg(); // If the original (pre-splitting) registers match this // copy came from a split. if (!TargetRegisterInfo::isVirtualRegister(Reg) || VRM->getOriginal(Reg) != Original) return false; // Follow the copy live-in value. const LiveInterval &SrcLI = LIS.getInterval(Reg); LiveQueryResult SrcQ = SrcLI.Query(VNI->def); VNI = SrcQ.valueIn(); assert(VNI && "Copy from non-existing value"); if (VNI->isPHIDef()) return false; MI = LIS.getInstructionFromIndex(VNI->def); assert(MI && "Dead valno in interval"); } } if (!TII.isTriviallyReMaterializable(MI, LIS.getAliasAnalysis())) return false; } return true; } void VirtRegAuxInfo::calculateSpillWeightAndHint(LiveInterval &li) { MachineRegisterInfo &mri = MF.getRegInfo(); const TargetRegisterInfo &tri = *MF.getSubtarget().getRegisterInfo(); MachineBasicBlock *mbb = nullptr; MachineLoop *loop = nullptr; bool isExiting = false; float totalWeight = 0; unsigned numInstr = 0; // Number of instructions using li SmallPtrSet visited; // Find the best physreg hint and the best virtreg hint. float bestPhys = 0, bestVirt = 0; unsigned hintPhys = 0, hintVirt = 0; // Don't recompute a target specific hint. bool noHint = mri.getRegAllocationHint(li.reg).first != 0; // Don't recompute spill weight for an unspillable register. bool Spillable = li.isSpillable(); for (MachineRegisterInfo::reg_instr_iterator I = mri.reg_instr_begin(li.reg), E = mri.reg_instr_end(); I != E; ) { MachineInstr *mi = &*(I++); numInstr++; if (mi->isIdentityCopy() || mi->isImplicitDef() || mi->isDebugValue()) continue; if (!visited.insert(mi).second) continue; float weight = 1.0f; if (Spillable) { // Get loop info for mi. if (mi->getParent() != mbb) { mbb = mi->getParent(); loop = Loops.getLoopFor(mbb); isExiting = loop ? loop->isLoopExiting(mbb) : false; } // Calculate instr weight. bool reads, writes; std::tie(reads, writes) = mi->readsWritesVirtualRegister(li.reg); weight = LiveIntervals::getSpillWeight( writes, reads, &MBFI, mi); // Give extra weight to what looks like a loop induction variable update. if (writes && isExiting && LIS.isLiveOutOfMBB(li, mbb)) weight *= 3; totalWeight += weight; } // Get allocation hints from copies. if (noHint || !mi->isCopy()) continue; unsigned hint = copyHint(mi, li.reg, tri, mri); if (!hint) continue; // Force hweight onto the stack so that x86 doesn't add hidden precision, // making the comparison incorrectly pass (i.e., 1 > 1 == true??). // // FIXME: we probably shouldn't use floats at all. volatile float hweight = Hint[hint] += weight; if (TargetRegisterInfo::isPhysicalRegister(hint)) { if (hweight > bestPhys && mri.isAllocatable(hint)) bestPhys = hweight, hintPhys = hint; } else { if (hweight > bestVirt) bestVirt = hweight, hintVirt = hint; } } Hint.clear(); // Always prefer the physreg hint. if (unsigned hint = hintPhys ? hintPhys : hintVirt) { mri.setRegAllocationHint(li.reg, 0, hint); // Weakly boost the spill weight of hinted registers. totalWeight *= 1.01F; } // If the live interval was already unspillable, leave it that way. if (!Spillable) return; - // Mark li as unspillable if all live ranges are tiny. - if (li.isZeroLength(LIS.getSlotIndexes())) { + // Mark li as unspillable if all live ranges are tiny and the interval + // is not live at any reg mask. If the interval is live at a reg mask + // spilling may be required. + if (li.isZeroLength(LIS.getSlotIndexes()) && + !li.isLiveAtIndexes(LIS.getRegMaskSlots())) { li.markNotSpillable(); return; } // If all of the definitions of the interval are re-materializable, // it is a preferred candidate for spilling. // FIXME: this gets much more complicated once we support non-trivial // re-materialization. if (isRematerializable(li, LIS, VRM, *MF.getSubtarget().getInstrInfo())) totalWeight *= 0.5F; li.weight = normalize(totalWeight, li.getSize(), numInstr); } Index: projects/clang380-import/contrib/llvm/lib/CodeGen/LiveInterval.cpp =================================================================== --- projects/clang380-import/contrib/llvm/lib/CodeGen/LiveInterval.cpp (revision 295858) +++ projects/clang380-import/contrib/llvm/lib/CodeGen/LiveInterval.cpp (revision 295859) @@ -1,1468 +1,1502 @@ //===-- LiveInterval.cpp - Live Interval Representation -------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the LiveRange and LiveInterval classes. Given some // numbering of each the machine instructions an interval [i, j) is said to be a // live range for register v if there is no instruction with number j' >= j // such that v is live at j' and there is no instruction with number i' < i such // that v is live at i'. In this implementation ranges can have holes, // i.e. a range might look like [1,20), [50,65), [1000,1001). Each // individual segment is represented as an instance of LiveRange::Segment, // and the whole range is represented as an instance of LiveRange. // //===----------------------------------------------------------------------===// #include "llvm/CodeGen/LiveInterval.h" #include "RegisterCoalescer.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallSet.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetRegisterInfo.h" #include using namespace llvm; namespace { //===----------------------------------------------------------------------===// // Implementation of various methods necessary for calculation of live ranges. // The implementation of the methods abstracts from the concrete type of the // segment collection. // // Implementation of the class follows the Template design pattern. The base // class contains generic algorithms that call collection-specific methods, // which are provided in concrete subclasses. In order to avoid virtual calls // these methods are provided by means of C++ template instantiation. // The base class calls the methods of the subclass through method impl(), // which casts 'this' pointer to the type of the subclass. // //===----------------------------------------------------------------------===// template class CalcLiveRangeUtilBase { protected: LiveRange *LR; protected: CalcLiveRangeUtilBase(LiveRange *LR) : LR(LR) {} public: typedef LiveRange::Segment Segment; typedef IteratorT iterator; VNInfo *createDeadDef(SlotIndex Def, VNInfo::Allocator &VNInfoAllocator) { assert(!Def.isDead() && "Cannot define a value at the dead slot"); iterator I = impl().find(Def); if (I == segments().end()) { VNInfo *VNI = LR->getNextValue(Def, VNInfoAllocator); impl().insertAtEnd(Segment(Def, Def.getDeadSlot(), VNI)); return VNI; } Segment *S = segmentAt(I); if (SlotIndex::isSameInstr(Def, S->start)) { assert(S->valno->def == S->start && "Inconsistent existing value def"); // It is possible to have both normal and early-clobber defs of the same // register on an instruction. It doesn't make a lot of sense, but it is // possible to specify in inline assembly. // // Just convert everything to early-clobber. Def = std::min(Def, S->start); if (Def != S->start) S->start = S->valno->def = Def; return S->valno; } assert(SlotIndex::isEarlierInstr(Def, S->start) && "Already live at def"); VNInfo *VNI = LR->getNextValue(Def, VNInfoAllocator); segments().insert(I, Segment(Def, Def.getDeadSlot(), VNI)); return VNI; } VNInfo *extendInBlock(SlotIndex StartIdx, SlotIndex Use) { if (segments().empty()) return nullptr; iterator I = impl().findInsertPos(Segment(Use.getPrevSlot(), Use, nullptr)); if (I == segments().begin()) return nullptr; --I; if (I->end <= StartIdx) return nullptr; if (I->end < Use) extendSegmentEndTo(I, Use); return I->valno; } /// This method is used when we want to extend the segment specified /// by I to end at the specified endpoint. To do this, we should /// merge and eliminate all segments that this will overlap /// with. The iterator is not invalidated. void extendSegmentEndTo(iterator I, SlotIndex NewEnd) { assert(I != segments().end() && "Not a valid segment!"); Segment *S = segmentAt(I); VNInfo *ValNo = I->valno; // Search for the first segment that we can't merge with. iterator MergeTo = std::next(I); for (; MergeTo != segments().end() && NewEnd >= MergeTo->end; ++MergeTo) assert(MergeTo->valno == ValNo && "Cannot merge with differing values!"); // If NewEnd was in the middle of a segment, make sure to get its endpoint. S->end = std::max(NewEnd, std::prev(MergeTo)->end); // If the newly formed segment now touches the segment after it and if they // have the same value number, merge the two segments into one segment. if (MergeTo != segments().end() && MergeTo->start <= I->end && MergeTo->valno == ValNo) { S->end = MergeTo->end; ++MergeTo; } // Erase any dead segments. segments().erase(std::next(I), MergeTo); } /// This method is used when we want to extend the segment specified /// by I to start at the specified endpoint. To do this, we should /// merge and eliminate all segments that this will overlap with. iterator extendSegmentStartTo(iterator I, SlotIndex NewStart) { assert(I != segments().end() && "Not a valid segment!"); Segment *S = segmentAt(I); VNInfo *ValNo = I->valno; // Search for the first segment that we can't merge with. iterator MergeTo = I; do { if (MergeTo == segments().begin()) { S->start = NewStart; segments().erase(MergeTo, I); return I; } assert(MergeTo->valno == ValNo && "Cannot merge with differing values!"); --MergeTo; } while (NewStart <= MergeTo->start); // If we start in the middle of another segment, just delete a range and // extend that segment. if (MergeTo->end >= NewStart && MergeTo->valno == ValNo) { segmentAt(MergeTo)->end = S->end; } else { // Otherwise, extend the segment right after. ++MergeTo; Segment *MergeToSeg = segmentAt(MergeTo); MergeToSeg->start = NewStart; MergeToSeg->end = S->end; } segments().erase(std::next(MergeTo), std::next(I)); return MergeTo; } iterator addSegment(Segment S) { SlotIndex Start = S.start, End = S.end; iterator I = impl().findInsertPos(S); // If the inserted segment starts in the middle or right at the end of // another segment, just extend that segment to contain the segment of S. if (I != segments().begin()) { iterator B = std::prev(I); if (S.valno == B->valno) { if (B->start <= Start && B->end >= Start) { extendSegmentEndTo(B, End); return B; } } else { // Check to make sure that we are not overlapping two live segments with // different valno's. assert(B->end <= Start && "Cannot overlap two segments with differing ValID's" " (did you def the same reg twice in a MachineInstr?)"); } } // Otherwise, if this segment ends in the middle of, or right next // to, another segment, merge it into that segment. if (I != segments().end()) { if (S.valno == I->valno) { if (I->start <= End) { I = extendSegmentStartTo(I, Start); // If S is a complete superset of a segment, we may need to grow its // endpoint as well. if (End > I->end) extendSegmentEndTo(I, End); return I; } } else { // Check to make sure that we are not overlapping two live segments with // different valno's. assert(I->start >= End && "Cannot overlap two segments with differing ValID's"); } } // Otherwise, this is just a new segment that doesn't interact with // anything. // Insert it. return segments().insert(I, S); } private: ImplT &impl() { return *static_cast(this); } CollectionT &segments() { return impl().segmentsColl(); } Segment *segmentAt(iterator I) { return const_cast(&(*I)); } }; //===----------------------------------------------------------------------===// // Instantiation of the methods for calculation of live ranges // based on a segment vector. //===----------------------------------------------------------------------===// class CalcLiveRangeUtilVector; typedef CalcLiveRangeUtilBase CalcLiveRangeUtilVectorBase; class CalcLiveRangeUtilVector : public CalcLiveRangeUtilVectorBase { public: CalcLiveRangeUtilVector(LiveRange *LR) : CalcLiveRangeUtilVectorBase(LR) {} private: friend CalcLiveRangeUtilVectorBase; LiveRange::Segments &segmentsColl() { return LR->segments; } void insertAtEnd(const Segment &S) { LR->segments.push_back(S); } iterator find(SlotIndex Pos) { return LR->find(Pos); } iterator findInsertPos(Segment S) { return std::upper_bound(LR->begin(), LR->end(), S.start); } }; //===----------------------------------------------------------------------===// // Instantiation of the methods for calculation of live ranges // based on a segment set. //===----------------------------------------------------------------------===// class CalcLiveRangeUtilSet; typedef CalcLiveRangeUtilBase CalcLiveRangeUtilSetBase; class CalcLiveRangeUtilSet : public CalcLiveRangeUtilSetBase { public: CalcLiveRangeUtilSet(LiveRange *LR) : CalcLiveRangeUtilSetBase(LR) {} private: friend CalcLiveRangeUtilSetBase; LiveRange::SegmentSet &segmentsColl() { return *LR->segmentSet; } void insertAtEnd(const Segment &S) { LR->segmentSet->insert(LR->segmentSet->end(), S); } iterator find(SlotIndex Pos) { iterator I = LR->segmentSet->upper_bound(Segment(Pos, Pos.getNextSlot(), nullptr)); if (I == LR->segmentSet->begin()) return I; iterator PrevI = std::prev(I); if (Pos < (*PrevI).end) return PrevI; return I; } iterator findInsertPos(Segment S) { iterator I = LR->segmentSet->upper_bound(S); if (I != LR->segmentSet->end() && !(S.start < *I)) ++I; return I; } }; } // namespace //===----------------------------------------------------------------------===// // LiveRange methods //===----------------------------------------------------------------------===// LiveRange::iterator LiveRange::find(SlotIndex Pos) { // This algorithm is basically std::upper_bound. // Unfortunately, std::upper_bound cannot be used with mixed types until we // adopt C++0x. Many libraries can do it, but not all. if (empty() || Pos >= endIndex()) return end(); iterator I = begin(); size_t Len = size(); do { size_t Mid = Len >> 1; if (Pos < I[Mid].end) Len = Mid; else I += Mid + 1, Len -= Mid + 1; } while (Len); return I; } VNInfo *LiveRange::createDeadDef(SlotIndex Def, VNInfo::Allocator &VNInfoAllocator) { // Use the segment set, if it is available. if (segmentSet != nullptr) return CalcLiveRangeUtilSet(this).createDeadDef(Def, VNInfoAllocator); // Otherwise use the segment vector. return CalcLiveRangeUtilVector(this).createDeadDef(Def, VNInfoAllocator); } // overlaps - Return true if the intersection of the two live ranges is // not empty. // // An example for overlaps(): // // 0: A = ... // 4: B = ... // 8: C = A + B ;; last use of A // // The live ranges should look like: // // A = [3, 11) // B = [7, x) // C = [11, y) // // A->overlaps(C) should return false since we want to be able to join // A and C. // bool LiveRange::overlapsFrom(const LiveRange& other, const_iterator StartPos) const { assert(!empty() && "empty range"); const_iterator i = begin(); const_iterator ie = end(); const_iterator j = StartPos; const_iterator je = other.end(); assert((StartPos->start <= i->start || StartPos == other.begin()) && StartPos != other.end() && "Bogus start position hint!"); if (i->start < j->start) { i = std::upper_bound(i, ie, j->start); if (i != begin()) --i; } else if (j->start < i->start) { ++StartPos; if (StartPos != other.end() && StartPos->start <= i->start) { assert(StartPos < other.end() && i < end()); j = std::upper_bound(j, je, i->start); if (j != other.begin()) --j; } } else { return true; } if (j == je) return false; while (i != ie) { if (i->start > j->start) { std::swap(i, j); std::swap(ie, je); } if (i->end > j->start) return true; ++i; } return false; } bool LiveRange::overlaps(const LiveRange &Other, const CoalescerPair &CP, const SlotIndexes &Indexes) const { assert(!empty() && "empty range"); if (Other.empty()) return false; // Use binary searches to find initial positions. const_iterator I = find(Other.beginIndex()); const_iterator IE = end(); if (I == IE) return false; const_iterator J = Other.find(I->start); const_iterator JE = Other.end(); if (J == JE) return false; for (;;) { // J has just been advanced to satisfy: assert(J->end >= I->start); // Check for an overlap. if (J->start < I->end) { // I and J are overlapping. Find the later start. SlotIndex Def = std::max(I->start, J->start); // Allow the overlap if Def is a coalescable copy. if (Def.isBlock() || !CP.isCoalescable(Indexes.getInstructionFromIndex(Def))) return true; } // Advance the iterator that ends first to check for more overlaps. if (J->end > I->end) { std::swap(I, J); std::swap(IE, JE); } // Advance J until J->end >= I->start. do if (++J == JE) return false; while (J->end < I->start); } } /// overlaps - Return true if the live range overlaps an interval specified /// by [Start, End). bool LiveRange::overlaps(SlotIndex Start, SlotIndex End) const { assert(Start < End && "Invalid range"); const_iterator I = std::lower_bound(begin(), end(), End); return I != begin() && (--I)->end > Start; } bool LiveRange::covers(const LiveRange &Other) const { if (empty()) return Other.empty(); const_iterator I = begin(); for (const Segment &O : Other.segments) { I = advanceTo(I, O.start); if (I == end() || I->start > O.start) return false; // Check adjacent live segments and see if we can get behind O.end. while (I->end < O.end) { const_iterator Last = I; // Get next segment and abort if it was not adjacent. ++I; if (I == end() || Last->end != I->start) return false; } } return true; } /// ValNo is dead, remove it. If it is the largest value number, just nuke it /// (and any other deleted values neighboring it), otherwise mark it as ~1U so /// it can be nuked later. void LiveRange::markValNoForDeletion(VNInfo *ValNo) { if (ValNo->id == getNumValNums()-1) { do { valnos.pop_back(); } while (!valnos.empty() && valnos.back()->isUnused()); } else { ValNo->markUnused(); } } /// RenumberValues - Renumber all values in order of appearance and delete the /// remaining unused values. void LiveRange::RenumberValues() { SmallPtrSet Seen; valnos.clear(); for (const Segment &S : segments) { VNInfo *VNI = S.valno; if (!Seen.insert(VNI).second) continue; assert(!VNI->isUnused() && "Unused valno used by live segment"); VNI->id = (unsigned)valnos.size(); valnos.push_back(VNI); } } void LiveRange::addSegmentToSet(Segment S) { CalcLiveRangeUtilSet(this).addSegment(S); } LiveRange::iterator LiveRange::addSegment(Segment S) { // Use the segment set, if it is available. if (segmentSet != nullptr) { addSegmentToSet(S); return end(); } // Otherwise use the segment vector. return CalcLiveRangeUtilVector(this).addSegment(S); } void LiveRange::append(const Segment S) { // Check that the segment belongs to the back of the list. assert(segments.empty() || segments.back().end <= S.start); segments.push_back(S); } /// extendInBlock - If this range is live before Kill in the basic /// block that starts at StartIdx, extend it to be live up to Kill and return /// the value. If there is no live range before Kill, return NULL. VNInfo *LiveRange::extendInBlock(SlotIndex StartIdx, SlotIndex Kill) { // Use the segment set, if it is available. if (segmentSet != nullptr) return CalcLiveRangeUtilSet(this).extendInBlock(StartIdx, Kill); // Otherwise use the segment vector. return CalcLiveRangeUtilVector(this).extendInBlock(StartIdx, Kill); } /// Remove the specified segment from this range. Note that the segment must /// be in a single Segment in its entirety. void LiveRange::removeSegment(SlotIndex Start, SlotIndex End, bool RemoveDeadValNo) { // Find the Segment containing this span. iterator I = find(Start); assert(I != end() && "Segment is not in range!"); assert(I->containsInterval(Start, End) && "Segment is not entirely in range!"); // If the span we are removing is at the start of the Segment, adjust it. VNInfo *ValNo = I->valno; if (I->start == Start) { if (I->end == End) { if (RemoveDeadValNo) { // Check if val# is dead. bool isDead = true; for (const_iterator II = begin(), EE = end(); II != EE; ++II) if (II != I && II->valno == ValNo) { isDead = false; break; } if (isDead) { // Now that ValNo is dead, remove it. markValNoForDeletion(ValNo); } } segments.erase(I); // Removed the whole Segment. } else I->start = End; return; } // Otherwise if the span we are removing is at the end of the Segment, // adjust the other way. if (I->end == End) { I->end = Start; return; } // Otherwise, we are splitting the Segment into two pieces. SlotIndex OldEnd = I->end; I->end = Start; // Trim the old segment. // Insert the new one. segments.insert(std::next(I), Segment(End, OldEnd, ValNo)); } /// removeValNo - Remove all the segments defined by the specified value#. /// Also remove the value# from value# list. void LiveRange::removeValNo(VNInfo *ValNo) { if (empty()) return; segments.erase(std::remove_if(begin(), end(), [ValNo](const Segment &S) { return S.valno == ValNo; }), end()); // Now that ValNo is dead, remove it. markValNoForDeletion(ValNo); } void LiveRange::join(LiveRange &Other, const int *LHSValNoAssignments, const int *RHSValNoAssignments, SmallVectorImpl &NewVNInfo) { verify(); // Determine if any of our values are mapped. This is uncommon, so we want // to avoid the range scan if not. bool MustMapCurValNos = false; unsigned NumVals = getNumValNums(); unsigned NumNewVals = NewVNInfo.size(); for (unsigned i = 0; i != NumVals; ++i) { unsigned LHSValID = LHSValNoAssignments[i]; if (i != LHSValID || (NewVNInfo[LHSValID] && NewVNInfo[LHSValID] != getValNumInfo(i))) { MustMapCurValNos = true; break; } } // If we have to apply a mapping to our base range assignment, rewrite it now. if (MustMapCurValNos && !empty()) { // Map the first live range. iterator OutIt = begin(); OutIt->valno = NewVNInfo[LHSValNoAssignments[OutIt->valno->id]]; for (iterator I = std::next(OutIt), E = end(); I != E; ++I) { VNInfo* nextValNo = NewVNInfo[LHSValNoAssignments[I->valno->id]]; assert(nextValNo && "Huh?"); // If this live range has the same value # as its immediate predecessor, // and if they are neighbors, remove one Segment. This happens when we // have [0,4:0)[4,7:1) and map 0/1 onto the same value #. if (OutIt->valno == nextValNo && OutIt->end == I->start) { OutIt->end = I->end; } else { // Didn't merge. Move OutIt to the next segment, ++OutIt; OutIt->valno = nextValNo; if (OutIt != I) { OutIt->start = I->start; OutIt->end = I->end; } } } // If we merge some segments, chop off the end. ++OutIt; segments.erase(OutIt, end()); } // Rewrite Other values before changing the VNInfo ids. // This can leave Other in an invalid state because we're not coalescing // touching segments that now have identical values. That's OK since Other is // not supposed to be valid after calling join(); for (Segment &S : Other.segments) S.valno = NewVNInfo[RHSValNoAssignments[S.valno->id]]; // Update val# info. Renumber them and make sure they all belong to this // LiveRange now. Also remove dead val#'s. unsigned NumValNos = 0; for (unsigned i = 0; i < NumNewVals; ++i) { VNInfo *VNI = NewVNInfo[i]; if (VNI) { if (NumValNos >= NumVals) valnos.push_back(VNI); else valnos[NumValNos] = VNI; VNI->id = NumValNos++; // Renumber val#. } } if (NumNewVals < NumVals) valnos.resize(NumNewVals); // shrinkify // Okay, now insert the RHS live segments into the LHS. LiveRangeUpdater Updater(this); for (Segment &S : Other.segments) Updater.add(S); } /// Merge all of the segments in RHS into this live range as the specified /// value number. The segments in RHS are allowed to overlap with segments in /// the current range, but only if the overlapping segments have the /// specified value number. void LiveRange::MergeSegmentsInAsValue(const LiveRange &RHS, VNInfo *LHSValNo) { LiveRangeUpdater Updater(this); for (const Segment &S : RHS.segments) Updater.add(S.start, S.end, LHSValNo); } /// MergeValueInAsValue - Merge all of the live segments of a specific val# /// in RHS into this live range as the specified value number. /// The segments in RHS are allowed to overlap with segments in the /// current range, it will replace the value numbers of the overlaped /// segments with the specified value number. void LiveRange::MergeValueInAsValue(const LiveRange &RHS, const VNInfo *RHSValNo, VNInfo *LHSValNo) { LiveRangeUpdater Updater(this); for (const Segment &S : RHS.segments) if (S.valno == RHSValNo) Updater.add(S.start, S.end, LHSValNo); } /// MergeValueNumberInto - This method is called when two value nubmers /// are found to be equivalent. This eliminates V1, replacing all /// segments with the V1 value number with the V2 value number. This can /// cause merging of V1/V2 values numbers and compaction of the value space. VNInfo *LiveRange::MergeValueNumberInto(VNInfo *V1, VNInfo *V2) { assert(V1 != V2 && "Identical value#'s are always equivalent!"); // This code actually merges the (numerically) larger value number into the // smaller value number, which is likely to allow us to compactify the value // space. The only thing we have to be careful of is to preserve the // instruction that defines the result value. // Make sure V2 is smaller than V1. if (V1->id < V2->id) { V1->copyFrom(*V2); std::swap(V1, V2); } // Merge V1 segments into V2. for (iterator I = begin(); I != end(); ) { iterator S = I++; if (S->valno != V1) continue; // Not a V1 Segment. // Okay, we found a V1 live range. If it had a previous, touching, V2 live // range, extend it. if (S != begin()) { iterator Prev = S-1; if (Prev->valno == V2 && Prev->end == S->start) { Prev->end = S->end; // Erase this live-range. segments.erase(S); I = Prev+1; S = Prev; } } // Okay, now we have a V1 or V2 live range that is maximally merged forward. // Ensure that it is a V2 live-range. S->valno = V2; // If we can merge it into later V2 segments, do so now. We ignore any // following V1 segments, as they will be merged in subsequent iterations // of the loop. if (I != end()) { if (I->start == S->end && I->valno == V2) { S->end = I->end; segments.erase(I); I = S+1; } } } // Now that V1 is dead, remove it. markValNoForDeletion(V1); return V2; } void LiveRange::flushSegmentSet() { assert(segmentSet != nullptr && "segment set must have been created"); assert( segments.empty() && "segment set can be used only initially before switching to the array"); segments.append(segmentSet->begin(), segmentSet->end()); segmentSet = nullptr; verify(); } +bool LiveRange::isLiveAtIndexes(ArrayRef Slots) const { + ArrayRef::iterator SlotI = Slots.begin(); + ArrayRef::iterator SlotE = Slots.end(); + + // If there are no regmask slots, we have nothing to search. + if (SlotI == SlotE) + return false; + + // Start our search at the first segment that ends after the first slot. + const_iterator SegmentI = find(*SlotI); + const_iterator SegmentE = end(); + + // If there are no segments that end after the first slot, we're done. + if (SegmentI == SegmentE) + return false; + + // Look for each slot in the live range. + for ( ; SlotI != SlotE; ++SlotI) { + // Go to the next segment that ends after the current slot. + // The slot may be within a hole in the range. + SegmentI = advanceTo(SegmentI, *SlotI); + if (SegmentI == SegmentE) + return false; + + // If this segment contains the slot, we're done. + if (SegmentI->contains(*SlotI)) + return true; + // Otherwise, look for the next slot. + } + + // We didn't find a segment containing any of the slots. + return false; +} + void LiveInterval::freeSubRange(SubRange *S) { S->~SubRange(); // Memory was allocated with BumpPtr allocator and is not freed here. } void LiveInterval::removeEmptySubRanges() { SubRange **NextPtr = &SubRanges; SubRange *I = *NextPtr; while (I != nullptr) { if (!I->empty()) { NextPtr = &I->Next; I = *NextPtr; continue; } // Skip empty subranges until we find the first nonempty one. do { SubRange *Next = I->Next; freeSubRange(I); I = Next; } while (I != nullptr && I->empty()); *NextPtr = I; } } void LiveInterval::clearSubRanges() { for (SubRange *I = SubRanges, *Next; I != nullptr; I = Next) { Next = I->Next; freeSubRange(I); } SubRanges = nullptr; } /// Helper function for constructMainRangeFromSubranges(): Search the CFG /// backwards until we find a place covered by a LiveRange segment that actually /// has a valno set. static VNInfo *searchForVNI(const SlotIndexes &Indexes, LiveRange &LR, const MachineBasicBlock *MBB, SmallPtrSetImpl &Visited) { // We start the search at the end of MBB. SlotIndex EndIdx = Indexes.getMBBEndIdx(MBB); // In our use case we can't live the area covered by the live segments without // finding an actual VNI def. LiveRange::iterator I = LR.find(EndIdx.getPrevSlot()); assert(I != LR.end()); LiveRange::Segment &S = *I; if (S.valno != nullptr) return S.valno; VNInfo *VNI = nullptr; // Continue at predecessors (we could even go to idom with domtree available). for (const MachineBasicBlock *Pred : MBB->predecessors()) { // Avoid going in circles. if (!Visited.insert(Pred).second) continue; VNI = searchForVNI(Indexes, LR, Pred, Visited); if (VNI != nullptr) { S.valno = VNI; break; } } return VNI; } static void determineMissingVNIs(const SlotIndexes &Indexes, LiveInterval &LI) { SmallPtrSet Visited; LiveRange::iterator OutIt; VNInfo *PrevValNo = nullptr; for (LiveRange::iterator I = LI.begin(), E = LI.end(); I != E; ++I) { LiveRange::Segment &S = *I; // Determine final VNI if necessary. if (S.valno == nullptr) { // This can only happen at the begin of a basic block. assert(S.start.isBlock() && "valno should only be missing at block begin"); Visited.clear(); const MachineBasicBlock *MBB = Indexes.getMBBFromIndex(S.start); for (const MachineBasicBlock *Pred : MBB->predecessors()) { VNInfo *VNI = searchForVNI(Indexes, LI, Pred, Visited); if (VNI != nullptr) { S.valno = VNI; break; } } assert(S.valno != nullptr && "could not determine valno"); } // Merge with previous segment if it has the same VNI. if (PrevValNo == S.valno && OutIt->end == S.start) { OutIt->end = S.end; } else { // Didn't merge. Move OutIt to next segment. if (PrevValNo == nullptr) OutIt = LI.begin(); else ++OutIt; if (OutIt != I) *OutIt = *I; PrevValNo = S.valno; } } // If we merged some segments chop off the end. ++OutIt; LI.segments.erase(OutIt, LI.end()); } void LiveInterval::constructMainRangeFromSubranges( const SlotIndexes &Indexes, VNInfo::Allocator &VNIAllocator) { // The basic observations on which this algorithm is based: // - Each Def/ValNo in a subrange must have a corresponding def on the main // range, but not further defs/valnos are necessary. // - If any of the subranges is live at a point the main liverange has to be // live too, conversily if no subrange is live the main range mustn't be // live either. // We do this by scanning through all the subranges simultaneously creating new // segments in the main range as segments start/ends come up in the subranges. assert(hasSubRanges() && "expected subranges to be present"); assert(segments.empty() && valnos.empty() && "expected empty main range"); // Collect subrange, iterator pairs for the walk and determine first and last // SlotIndex involved. SmallVector, 4> SRs; SlotIndex First; SlotIndex Last; for (const SubRange &SR : subranges()) { if (SR.empty()) continue; SRs.push_back(std::make_pair(&SR, SR.begin())); if (!First.isValid() || SR.segments.front().start < First) First = SR.segments.front().start; if (!Last.isValid() || SR.segments.back().end > Last) Last = SR.segments.back().end; } // Walk over all subranges simultaneously. Segment CurrentSegment; bool ConstructingSegment = false; bool NeedVNIFixup = false; LaneBitmask ActiveMask = 0; SlotIndex Pos = First; while (true) { SlotIndex NextPos = Last; enum { NOTHING, BEGIN_SEGMENT, END_SEGMENT, } Event = NOTHING; // Which subregister lanes are affected by the current event. LaneBitmask EventMask = 0; // Whether a BEGIN_SEGMENT is also a valno definition point. bool IsDef = false; // Find the next begin or end of a subrange segment. Combine masks if we // have multiple begins/ends at the same position. Ends take precedence over // Begins. for (auto &SRP : SRs) { const SubRange &SR = *SRP.first; const_iterator &I = SRP.second; // Advance iterator of subrange to a segment involving Pos; the earlier // segments are already merged at this point. while (I != SR.end() && (I->end < Pos || (I->end == Pos && (ActiveMask & SR.LaneMask) == 0))) ++I; if (I == SR.end()) continue; if ((ActiveMask & SR.LaneMask) == 0 && Pos <= I->start && I->start <= NextPos) { // Merge multiple begins at the same position. if (I->start == NextPos && Event == BEGIN_SEGMENT) { EventMask |= SR.LaneMask; IsDef |= I->valno->def == I->start; } else if (I->start < NextPos || Event != END_SEGMENT) { Event = BEGIN_SEGMENT; NextPos = I->start; EventMask = SR.LaneMask; IsDef = I->valno->def == I->start; } } if ((ActiveMask & SR.LaneMask) != 0 && Pos <= I->end && I->end <= NextPos) { // Merge multiple ends at the same position. if (I->end == NextPos && Event == END_SEGMENT) EventMask |= SR.LaneMask; else { Event = END_SEGMENT; NextPos = I->end; EventMask = SR.LaneMask; } } } // Advance scan position. Pos = NextPos; if (Event == BEGIN_SEGMENT) { if (ConstructingSegment && IsDef) { // Finish previous segment because we have to start a new one. CurrentSegment.end = Pos; append(CurrentSegment); ConstructingSegment = false; } // Start a new segment if necessary. if (!ConstructingSegment) { // Determine value number for the segment. VNInfo *VNI; if (IsDef) { VNI = getNextValue(Pos, VNIAllocator); } else { // We have to reuse an existing value number, if we are lucky // then we already passed one of the predecessor blocks and determined // its value number (with blocks in reverse postorder this would be // always true but we have no such guarantee). assert(Pos.isBlock()); const MachineBasicBlock *MBB = Indexes.getMBBFromIndex(Pos); // See if any of the predecessor blocks has a lower number and a VNI for (const MachineBasicBlock *Pred : MBB->predecessors()) { SlotIndex PredEnd = Indexes.getMBBEndIdx(Pred); VNI = getVNInfoBefore(PredEnd); if (VNI != nullptr) break; } // Def will come later: We have to do an extra fixup pass. if (VNI == nullptr) NeedVNIFixup = true; } // In rare cases we can produce adjacent segments with the same value // number (if they come from different subranges, but happen to have // the same defining instruction). VNIFixup will fix those cases. if (!empty() && segments.back().end == Pos && segments.back().valno == VNI) NeedVNIFixup = true; CurrentSegment.start = Pos; CurrentSegment.valno = VNI; ConstructingSegment = true; } ActiveMask |= EventMask; } else if (Event == END_SEGMENT) { assert(ConstructingSegment); // Finish segment if no lane is active anymore. ActiveMask &= ~EventMask; if (ActiveMask == 0) { CurrentSegment.end = Pos; append(CurrentSegment); ConstructingSegment = false; } } else { // We reached the end of the last subranges and can stop. assert(Event == NOTHING); break; } } // We might not be able to assign new valnos for all segments if the basic // block containing the definition comes after a segment using the valno. // Do a fixup pass for this uncommon case. if (NeedVNIFixup) determineMissingVNIs(Indexes, *this); assert(ActiveMask == 0 && !ConstructingSegment && "all segments ended"); verify(); } unsigned LiveInterval::getSize() const { unsigned Sum = 0; for (const Segment &S : segments) Sum += S.start.distance(S.end); return Sum; } raw_ostream& llvm::operator<<(raw_ostream& os, const LiveRange::Segment &S) { return os << '[' << S.start << ',' << S.end << ':' << S.valno->id << ")"; } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) void LiveRange::Segment::dump() const { dbgs() << *this << "\n"; } #endif void LiveRange::print(raw_ostream &OS) const { if (empty()) OS << "EMPTY"; else { for (const Segment &S : segments) { OS << S; assert(S.valno == getValNumInfo(S.valno->id) && "Bad VNInfo"); } } // Print value number info. if (getNumValNums()) { OS << " "; unsigned vnum = 0; for (const_vni_iterator i = vni_begin(), e = vni_end(); i != e; ++i, ++vnum) { const VNInfo *vni = *i; if (vnum) OS << " "; OS << vnum << "@"; if (vni->isUnused()) { OS << "x"; } else { OS << vni->def; if (vni->isPHIDef()) OS << "-phi"; } } } } void LiveInterval::print(raw_ostream &OS) const { OS << PrintReg(reg) << ' '; super::print(OS); // Print subranges for (const SubRange &SR : subranges()) { OS << " L" << PrintLaneMask(SR.LaneMask) << ' ' << SR; } } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) void LiveRange::dump() const { dbgs() << *this << "\n"; } void LiveInterval::dump() const { dbgs() << *this << "\n"; } #endif #ifndef NDEBUG void LiveRange::verify() const { for (const_iterator I = begin(), E = end(); I != E; ++I) { assert(I->start.isValid()); assert(I->end.isValid()); assert(I->start < I->end); assert(I->valno != nullptr); assert(I->valno->id < valnos.size()); assert(I->valno == valnos[I->valno->id]); if (std::next(I) != E) { assert(I->end <= std::next(I)->start); if (I->end == std::next(I)->start) assert(I->valno != std::next(I)->valno); } } } void LiveInterval::verify(const MachineRegisterInfo *MRI) const { super::verify(); // Make sure SubRanges are fine and LaneMasks are disjunct. LaneBitmask Mask = 0; LaneBitmask MaxMask = MRI != nullptr ? MRI->getMaxLaneMaskForVReg(reg) : ~0u; for (const SubRange &SR : subranges()) { // Subrange lanemask should be disjunct to any previous subrange masks. assert((Mask & SR.LaneMask) == 0); Mask |= SR.LaneMask; // subrange mask should not contained in maximum lane mask for the vreg. assert((Mask & ~MaxMask) == 0); // empty subranges must be removed. assert(!SR.empty()); SR.verify(); // Main liverange should cover subrange. assert(covers(SR)); } } #endif //===----------------------------------------------------------------------===// // LiveRangeUpdater class //===----------------------------------------------------------------------===// // // The LiveRangeUpdater class always maintains these invariants: // // - When LastStart is invalid, Spills is empty and the iterators are invalid. // This is the initial state, and the state created by flush(). // In this state, isDirty() returns false. // // Otherwise, segments are kept in three separate areas: // // 1. [begin; WriteI) at the front of LR. // 2. [ReadI; end) at the back of LR. // 3. Spills. // // - LR.begin() <= WriteI <= ReadI <= LR.end(). // - Segments in all three areas are fully ordered and coalesced. // - Segments in area 1 precede and can't coalesce with segments in area 2. // - Segments in Spills precede and can't coalesce with segments in area 2. // - No coalescing is possible between segments in Spills and segments in area // 1, and there are no overlapping segments. // // The segments in Spills are not ordered with respect to the segments in area // 1. They need to be merged. // // When they exist, Spills.back().start <= LastStart, // and WriteI[-1].start <= LastStart. void LiveRangeUpdater::print(raw_ostream &OS) const { if (!isDirty()) { if (LR) OS << "Clean updater: " << *LR << '\n'; else OS << "Null updater.\n"; return; } assert(LR && "Can't have null LR in dirty updater."); OS << " updater with gap = " << (ReadI - WriteI) << ", last start = " << LastStart << ":\n Area 1:"; for (const auto &S : make_range(LR->begin(), WriteI)) OS << ' ' << S; OS << "\n Spills:"; for (unsigned I = 0, E = Spills.size(); I != E; ++I) OS << ' ' << Spills[I]; OS << "\n Area 2:"; for (const auto &S : make_range(ReadI, LR->end())) OS << ' ' << S; OS << '\n'; } void LiveRangeUpdater::dump() const { print(errs()); } // Determine if A and B should be coalesced. static inline bool coalescable(const LiveRange::Segment &A, const LiveRange::Segment &B) { assert(A.start <= B.start && "Unordered live segments."); if (A.end == B.start) return A.valno == B.valno; if (A.end < B.start) return false; assert(A.valno == B.valno && "Cannot overlap different values"); return true; } void LiveRangeUpdater::add(LiveRange::Segment Seg) { assert(LR && "Cannot add to a null destination"); // Fall back to the regular add method if the live range // is using the segment set instead of the segment vector. if (LR->segmentSet != nullptr) { LR->addSegmentToSet(Seg); return; } // Flush the state if Start moves backwards. if (!LastStart.isValid() || LastStart > Seg.start) { if (isDirty()) flush(); // This brings us to an uninitialized state. Reinitialize. assert(Spills.empty() && "Leftover spilled segments"); WriteI = ReadI = LR->begin(); } // Remember start for next time. LastStart = Seg.start; // Advance ReadI until it ends after Seg.start. LiveRange::iterator E = LR->end(); if (ReadI != E && ReadI->end <= Seg.start) { // First try to close the gap between WriteI and ReadI with spills. if (ReadI != WriteI) mergeSpills(); // Then advance ReadI. if (ReadI == WriteI) ReadI = WriteI = LR->find(Seg.start); else while (ReadI != E && ReadI->end <= Seg.start) *WriteI++ = *ReadI++; } assert(ReadI == E || ReadI->end > Seg.start); // Check if the ReadI segment begins early. if (ReadI != E && ReadI->start <= Seg.start) { assert(ReadI->valno == Seg.valno && "Cannot overlap different values"); // Bail if Seg is completely contained in ReadI. if (ReadI->end >= Seg.end) return; // Coalesce into Seg. Seg.start = ReadI->start; ++ReadI; } // Coalesce as much as possible from ReadI into Seg. while (ReadI != E && coalescable(Seg, *ReadI)) { Seg.end = std::max(Seg.end, ReadI->end); ++ReadI; } // Try coalescing Spills.back() into Seg. if (!Spills.empty() && coalescable(Spills.back(), Seg)) { Seg.start = Spills.back().start; Seg.end = std::max(Spills.back().end, Seg.end); Spills.pop_back(); } // Try coalescing Seg into WriteI[-1]. if (WriteI != LR->begin() && coalescable(WriteI[-1], Seg)) { WriteI[-1].end = std::max(WriteI[-1].end, Seg.end); return; } // Seg doesn't coalesce with anything, and needs to be inserted somewhere. if (WriteI != ReadI) { *WriteI++ = Seg; return; } // Finally, append to LR or Spills. if (WriteI == E) { LR->segments.push_back(Seg); WriteI = ReadI = LR->end(); } else Spills.push_back(Seg); } // Merge as many spilled segments as possible into the gap between WriteI // and ReadI. Advance WriteI to reflect the inserted instructions. void LiveRangeUpdater::mergeSpills() { // Perform a backwards merge of Spills and [SpillI;WriteI). size_t GapSize = ReadI - WriteI; size_t NumMoved = std::min(Spills.size(), GapSize); LiveRange::iterator Src = WriteI; LiveRange::iterator Dst = Src + NumMoved; LiveRange::iterator SpillSrc = Spills.end(); LiveRange::iterator B = LR->begin(); // This is the new WriteI position after merging spills. WriteI = Dst; // Now merge Src and Spills backwards. while (Src != Dst) { if (Src != B && Src[-1].start > SpillSrc[-1].start) *--Dst = *--Src; else *--Dst = *--SpillSrc; } assert(NumMoved == size_t(Spills.end() - SpillSrc)); Spills.erase(SpillSrc, Spills.end()); } void LiveRangeUpdater::flush() { if (!isDirty()) return; // Clear the dirty state. LastStart = SlotIndex(); assert(LR && "Cannot add to a null destination"); // Nothing to merge? if (Spills.empty()) { LR->segments.erase(WriteI, ReadI); LR->verify(); return; } // Resize the WriteI - ReadI gap to match Spills. size_t GapSize = ReadI - WriteI; if (GapSize < Spills.size()) { // The gap is too small. Make some room. size_t WritePos = WriteI - LR->begin(); LR->segments.insert(ReadI, Spills.size() - GapSize, LiveRange::Segment()); // This also invalidated ReadI, but it is recomputed below. WriteI = LR->begin() + WritePos; } else { // Shrink the gap if necessary. LR->segments.erase(WriteI + Spills.size(), ReadI); } ReadI = WriteI + Spills.size(); mergeSpills(); LR->verify(); } unsigned ConnectedVNInfoEqClasses::Classify(const LiveRange &LR) { // Create initial equivalence classes. EqClass.clear(); EqClass.grow(LR.getNumValNums()); const VNInfo *used = nullptr, *unused = nullptr; // Determine connections. for (const VNInfo *VNI : LR.valnos) { // Group all unused values into one class. if (VNI->isUnused()) { if (unused) EqClass.join(unused->id, VNI->id); unused = VNI; continue; } used = VNI; if (VNI->isPHIDef()) { const MachineBasicBlock *MBB = LIS.getMBBFromIndex(VNI->def); assert(MBB && "Phi-def has no defining MBB"); // Connect to values live out of predecessors. for (MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), PE = MBB->pred_end(); PI != PE; ++PI) if (const VNInfo *PVNI = LR.getVNInfoBefore(LIS.getMBBEndIdx(*PI))) EqClass.join(VNI->id, PVNI->id); } else { // Normal value defined by an instruction. Check for two-addr redef. // FIXME: This could be coincidental. Should we really check for a tied // operand constraint? // Note that VNI->def may be a use slot for an early clobber def. if (const VNInfo *UVNI = LR.getVNInfoBefore(VNI->def)) EqClass.join(VNI->id, UVNI->id); } } // Lump all the unused values in with the last used value. if (used && unused) EqClass.join(used->id, unused->id); EqClass.compress(); return EqClass.getNumClasses(); } template static void DistributeRange(LiveRangeT &LR, LiveRangeT *SplitLRs[], EqClassesT VNIClasses) { // Move segments to new intervals. LiveRange::iterator J = LR.begin(), E = LR.end(); while (J != E && VNIClasses[J->valno->id] == 0) ++J; for (LiveRange::iterator I = J; I != E; ++I) { if (unsigned eq = VNIClasses[I->valno->id]) { assert((SplitLRs[eq-1]->empty() || SplitLRs[eq-1]->expiredAt(I->start)) && "New intervals should be empty"); SplitLRs[eq-1]->segments.push_back(*I); } else *J++ = *I; } LR.segments.erase(J, E); // Transfer VNInfos to their new owners and renumber them. unsigned j = 0, e = LR.getNumValNums(); while (j != e && VNIClasses[j] == 0) ++j; for (unsigned i = j; i != e; ++i) { VNInfo *VNI = LR.getValNumInfo(i); if (unsigned eq = VNIClasses[i]) { VNI->id = SplitLRs[eq-1]->getNumValNums(); SplitLRs[eq-1]->valnos.push_back(VNI); } else { VNI->id = j; LR.valnos[j++] = VNI; } } LR.valnos.resize(j); } void ConnectedVNInfoEqClasses::Distribute(LiveInterval &LI, LiveInterval *LIV[], MachineRegisterInfo &MRI) { // Rewrite instructions. for (MachineRegisterInfo::reg_iterator RI = MRI.reg_begin(LI.reg), RE = MRI.reg_end(); RI != RE;) { MachineOperand &MO = *RI; MachineInstr *MI = RI->getParent(); ++RI; // DBG_VALUE instructions don't have slot indexes, so get the index of the // instruction before them. // Normally, DBG_VALUE instructions are removed before this function is // called, but it is not a requirement. SlotIndex Idx; if (MI->isDebugValue()) Idx = LIS.getSlotIndexes()->getIndexBefore(MI); else Idx = LIS.getInstructionIndex(MI); LiveQueryResult LRQ = LI.Query(Idx); const VNInfo *VNI = MO.readsReg() ? LRQ.valueIn() : LRQ.valueDefined(); // In the case of an use that isn't tied to any def, VNI will be // NULL. If the use is tied to a def, VNI will be the defined value. if (!VNI) continue; if (unsigned EqClass = getEqClass(VNI)) MO.setReg(LIV[EqClass-1]->reg); } // Distribute subregister liveranges. if (LI.hasSubRanges()) { unsigned NumComponents = EqClass.getNumClasses(); SmallVector VNIMapping; SmallVector SubRanges; BumpPtrAllocator &Allocator = LIS.getVNInfoAllocator(); for (LiveInterval::SubRange &SR : LI.subranges()) { // Create new subranges in the split intervals and construct a mapping // for the VNInfos in the subrange. unsigned NumValNos = SR.valnos.size(); VNIMapping.clear(); VNIMapping.reserve(NumValNos); SubRanges.clear(); SubRanges.resize(NumComponents-1, nullptr); for (unsigned I = 0; I < NumValNos; ++I) { const VNInfo &VNI = *SR.valnos[I]; const VNInfo *MainRangeVNI = LI.getVNInfoAt(VNI.def); assert(MainRangeVNI != nullptr && "SubRange def must have corresponding main range def"); unsigned ComponentNum = getEqClass(MainRangeVNI); VNIMapping.push_back(ComponentNum); if (ComponentNum > 0 && SubRanges[ComponentNum-1] == nullptr) { SubRanges[ComponentNum-1] = LIV[ComponentNum-1]->createSubRange(Allocator, SR.LaneMask); } } DistributeRange(SR, SubRanges.data(), VNIMapping); } LI.removeEmptySubRanges(); } // Distribute main liverange. DistributeRange(LI, LIV, EqClass); } Index: projects/clang380-import/contrib/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp =================================================================== --- projects/clang380-import/contrib/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp (revision 295858) +++ projects/clang380-import/contrib/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp (revision 295859) @@ -1,4681 +1,4707 @@ //===-- LegalizeDAG.cpp - Implement SelectionDAG::Legalize ----------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the SelectionDAG::Legalize method. // //===----------------------------------------------------------------------===// #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Triple.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetSubtargetInfo.h" using namespace llvm; #define DEBUG_TYPE "legalizedag" namespace { struct FloatSignAsInt; //===----------------------------------------------------------------------===// /// This takes an arbitrary SelectionDAG as input and /// hacks on it until the target machine can handle it. This involves /// eliminating value sizes the machine cannot handle (promoting small sizes to /// large sizes or splitting up large values into small values) as well as /// eliminating operations the machine cannot handle. /// /// This code also does a small amount of optimization and recognition of idioms /// as part of its processing. For example, if a target does not support a /// 'setcc' instruction efficiently, but does support 'brcc' instruction, this /// will attempt merge setcc and brc instructions into brcc's. /// class SelectionDAGLegalize { const TargetMachine &TM; const TargetLowering &TLI; SelectionDAG &DAG; /// \brief The set of nodes which have already been legalized. We hold a /// reference to it in order to update as necessary on node deletion. SmallPtrSetImpl &LegalizedNodes; /// \brief A set of all the nodes updated during legalization. SmallSetVector *UpdatedNodes; EVT getSetCCResultType(EVT VT) const { return TLI.getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT); } // Libcall insertion helpers. public: SelectionDAGLegalize(SelectionDAG &DAG, SmallPtrSetImpl &LegalizedNodes, SmallSetVector *UpdatedNodes = nullptr) : TM(DAG.getTarget()), TLI(DAG.getTargetLoweringInfo()), DAG(DAG), LegalizedNodes(LegalizedNodes), UpdatedNodes(UpdatedNodes) {} /// \brief Legalizes the given operation. void LegalizeOp(SDNode *Node); private: SDValue OptimizeFloatStore(StoreSDNode *ST); void LegalizeLoadOps(SDNode *Node); void LegalizeStoreOps(SDNode *Node); /// Some targets cannot handle a variable /// insertion index for the INSERT_VECTOR_ELT instruction. In this case, it /// is necessary to spill the vector being inserted into to memory, perform /// the insert there, and then read the result back. SDValue PerformInsertVectorEltInMemory(SDValue Vec, SDValue Val, SDValue Idx, SDLoc dl); SDValue ExpandINSERT_VECTOR_ELT(SDValue Vec, SDValue Val, SDValue Idx, SDLoc dl); /// Return a vector shuffle operation which /// performs the same shuffe in terms of order or result bytes, but on a type /// whose vector element type is narrower than the original shuffle type. /// e.g. <0, 1, 0, 1> -> v8i16 <0, 1, 2, 3, 0, 1, 2, 3> SDValue ShuffleWithNarrowerEltType(EVT NVT, EVT VT, SDLoc dl, SDValue N1, SDValue N2, ArrayRef Mask) const; bool LegalizeSetCCCondCode(EVT VT, SDValue &LHS, SDValue &RHS, SDValue &CC, bool &NeedInvert, SDLoc dl); SDValue ExpandLibCall(RTLIB::Libcall LC, SDNode *Node, bool isSigned); SDValue ExpandLibCall(RTLIB::Libcall LC, EVT RetVT, const SDValue *Ops, unsigned NumOps, bool isSigned, SDLoc dl); std::pair ExpandChainLibCall(RTLIB::Libcall LC, SDNode *Node, bool isSigned); SDValue ExpandFPLibCall(SDNode *Node, RTLIB::Libcall Call_F32, RTLIB::Libcall Call_F64, RTLIB::Libcall Call_F80, RTLIB::Libcall Call_F128, RTLIB::Libcall Call_PPCF128); SDValue ExpandIntLibCall(SDNode *Node, bool isSigned, RTLIB::Libcall Call_I8, RTLIB::Libcall Call_I16, RTLIB::Libcall Call_I32, RTLIB::Libcall Call_I64, RTLIB::Libcall Call_I128); void ExpandDivRemLibCall(SDNode *Node, SmallVectorImpl &Results); void ExpandSinCosLibCall(SDNode *Node, SmallVectorImpl &Results); SDValue EmitStackConvert(SDValue SrcOp, EVT SlotVT, EVT DestVT, SDLoc dl); SDValue ExpandBUILD_VECTOR(SDNode *Node); SDValue ExpandSCALAR_TO_VECTOR(SDNode *Node); void ExpandDYNAMIC_STACKALLOC(SDNode *Node, SmallVectorImpl &Results); void getSignAsIntValue(FloatSignAsInt &State, SDLoc DL, SDValue Value) const; SDValue modifySignAsInt(const FloatSignAsInt &State, SDLoc DL, SDValue NewIntValue) const; SDValue ExpandFCOPYSIGN(SDNode *Node) const; SDValue ExpandFABS(SDNode *Node) const; SDValue ExpandLegalINT_TO_FP(bool isSigned, SDValue LegalOp, EVT DestVT, SDLoc dl); SDValue PromoteLegalINT_TO_FP(SDValue LegalOp, EVT DestVT, bool isSigned, SDLoc dl); SDValue PromoteLegalFP_TO_INT(SDValue LegalOp, EVT DestVT, bool isSigned, SDLoc dl); SDValue ExpandBITREVERSE(SDValue Op, SDLoc dl); SDValue ExpandBSWAP(SDValue Op, SDLoc dl); SDValue ExpandBitCount(unsigned Opc, SDValue Op, SDLoc dl); SDValue ExpandExtractFromVectorThroughStack(SDValue Op); SDValue ExpandInsertToVectorThroughStack(SDValue Op); SDValue ExpandVectorBuildThroughStack(SDNode* Node); SDValue ExpandConstantFP(ConstantFPSDNode *CFP, bool UseCP); SDValue ExpandConstant(ConstantSDNode *CP); // if ExpandNode returns false, LegalizeOp falls back to ConvertNodeToLibcall bool ExpandNode(SDNode *Node); void ConvertNodeToLibcall(SDNode *Node); void PromoteNode(SDNode *Node); public: // Node replacement helpers void ReplacedNode(SDNode *N) { LegalizedNodes.erase(N); if (UpdatedNodes) UpdatedNodes->insert(N); } void ReplaceNode(SDNode *Old, SDNode *New) { DEBUG(dbgs() << " ... replacing: "; Old->dump(&DAG); dbgs() << " with: "; New->dump(&DAG)); assert(Old->getNumValues() == New->getNumValues() && "Replacing one node with another that produces a different number " "of values!"); DAG.ReplaceAllUsesWith(Old, New); for (unsigned i = 0, e = Old->getNumValues(); i != e; ++i) DAG.TransferDbgValues(SDValue(Old, i), SDValue(New, i)); if (UpdatedNodes) UpdatedNodes->insert(New); ReplacedNode(Old); } void ReplaceNode(SDValue Old, SDValue New) { DEBUG(dbgs() << " ... replacing: "; Old->dump(&DAG); dbgs() << " with: "; New->dump(&DAG)); DAG.ReplaceAllUsesWith(Old, New); DAG.TransferDbgValues(Old, New); if (UpdatedNodes) UpdatedNodes->insert(New.getNode()); ReplacedNode(Old.getNode()); } void ReplaceNode(SDNode *Old, const SDValue *New) { DEBUG(dbgs() << " ... replacing: "; Old->dump(&DAG)); DAG.ReplaceAllUsesWith(Old, New); for (unsigned i = 0, e = Old->getNumValues(); i != e; ++i) { DEBUG(dbgs() << (i == 0 ? " with: " : " and: "); New[i]->dump(&DAG)); DAG.TransferDbgValues(SDValue(Old, i), New[i]); if (UpdatedNodes) UpdatedNodes->insert(New[i].getNode()); } ReplacedNode(Old); } }; } /// Return a vector shuffle operation which /// performs the same shuffe in terms of order or result bytes, but on a type /// whose vector element type is narrower than the original shuffle type. /// e.g. <0, 1, 0, 1> -> v8i16 <0, 1, 2, 3, 0, 1, 2, 3> SDValue SelectionDAGLegalize::ShuffleWithNarrowerEltType(EVT NVT, EVT VT, SDLoc dl, SDValue N1, SDValue N2, ArrayRef Mask) const { unsigned NumMaskElts = VT.getVectorNumElements(); unsigned NumDestElts = NVT.getVectorNumElements(); unsigned NumEltsGrowth = NumDestElts / NumMaskElts; assert(NumEltsGrowth && "Cannot promote to vector type with fewer elts!"); if (NumEltsGrowth == 1) return DAG.getVectorShuffle(NVT, dl, N1, N2, &Mask[0]); SmallVector NewMask; for (unsigned i = 0; i != NumMaskElts; ++i) { int Idx = Mask[i]; for (unsigned j = 0; j != NumEltsGrowth; ++j) { if (Idx < 0) NewMask.push_back(-1); else NewMask.push_back(Idx * NumEltsGrowth + j); } } assert(NewMask.size() == NumDestElts && "Non-integer NumEltsGrowth?"); assert(TLI.isShuffleMaskLegal(NewMask, NVT) && "Shuffle not legal?"); return DAG.getVectorShuffle(NVT, dl, N1, N2, &NewMask[0]); } /// Expands the ConstantFP node to an integer constant or /// a load from the constant pool. SDValue SelectionDAGLegalize::ExpandConstantFP(ConstantFPSDNode *CFP, bool UseCP) { bool Extend = false; SDLoc dl(CFP); // If a FP immediate is precise when represented as a float and if the // target can do an extending load from float to double, we put it into // the constant pool as a float, even if it's is statically typed as a // double. This shrinks FP constants and canonicalizes them for targets where // an FP extending load is the same cost as a normal load (such as on the x87 // fp stack or PPC FP unit). EVT VT = CFP->getValueType(0); ConstantFP *LLVMC = const_cast(CFP->getConstantFPValue()); if (!UseCP) { assert((VT == MVT::f64 || VT == MVT::f32) && "Invalid type expansion"); return DAG.getConstant(LLVMC->getValueAPF().bitcastToAPInt(), dl, (VT == MVT::f64) ? MVT::i64 : MVT::i32); } EVT OrigVT = VT; EVT SVT = VT; while (SVT != MVT::f32 && SVT != MVT::f16) { SVT = (MVT::SimpleValueType)(SVT.getSimpleVT().SimpleTy - 1); if (ConstantFPSDNode::isValueValidForType(SVT, CFP->getValueAPF()) && // Only do this if the target has a native EXTLOAD instruction from // smaller type. TLI.isLoadExtLegal(ISD::EXTLOAD, OrigVT, SVT) && TLI.ShouldShrinkFPConstant(OrigVT)) { Type *SType = SVT.getTypeForEVT(*DAG.getContext()); LLVMC = cast(ConstantExpr::getFPTrunc(LLVMC, SType)); VT = SVT; Extend = true; } } SDValue CPIdx = DAG.getConstantPool(LLVMC, TLI.getPointerTy(DAG.getDataLayout())); unsigned Alignment = cast(CPIdx)->getAlignment(); if (Extend) { SDValue Result = DAG.getExtLoad( ISD::EXTLOAD, dl, OrigVT, DAG.getEntryNode(), CPIdx, MachinePointerInfo::getConstantPool(DAG.getMachineFunction()), VT, false, false, false, Alignment); return Result; } SDValue Result = DAG.getLoad(OrigVT, dl, DAG.getEntryNode(), CPIdx, MachinePointerInfo::getConstantPool(DAG.getMachineFunction()), false, false, false, Alignment); return Result; } /// Expands the Constant node to a load from the constant pool. SDValue SelectionDAGLegalize::ExpandConstant(ConstantSDNode *CP) { SDLoc dl(CP); EVT VT = CP->getValueType(0); SDValue CPIdx = DAG.getConstantPool(CP->getConstantIntValue(), TLI.getPointerTy(DAG.getDataLayout())); unsigned Alignment = cast(CPIdx)->getAlignment(); SDValue Result = DAG.getLoad(VT, dl, DAG.getEntryNode(), CPIdx, MachinePointerInfo::getConstantPool(DAG.getMachineFunction()), false, false, false, Alignment); return Result; } /// Expands an unaligned store to 2 half-size stores. static void ExpandUnalignedStore(StoreSDNode *ST, SelectionDAG &DAG, const TargetLowering &TLI, SelectionDAGLegalize *DAGLegalize) { assert(ST->getAddressingMode() == ISD::UNINDEXED && "unaligned indexed stores not implemented!"); SDValue Chain = ST->getChain(); SDValue Ptr = ST->getBasePtr(); SDValue Val = ST->getValue(); EVT VT = Val.getValueType(); int Alignment = ST->getAlignment(); unsigned AS = ST->getAddressSpace(); SDLoc dl(ST); if (ST->getMemoryVT().isFloatingPoint() || ST->getMemoryVT().isVector()) { EVT intVT = EVT::getIntegerVT(*DAG.getContext(), VT.getSizeInBits()); if (TLI.isTypeLegal(intVT)) { // Expand to a bitconvert of the value to the integer type of the // same size, then a (misaligned) int store. // FIXME: Does not handle truncating floating point stores! SDValue Result = DAG.getNode(ISD::BITCAST, dl, intVT, Val); Result = DAG.getStore(Chain, dl, Result, Ptr, ST->getPointerInfo(), ST->isVolatile(), ST->isNonTemporal(), Alignment); DAGLegalize->ReplaceNode(SDValue(ST, 0), Result); return; } // Do a (aligned) store to a stack slot, then copy from the stack slot // to the final destination using (unaligned) integer loads and stores. EVT StoredVT = ST->getMemoryVT(); MVT RegVT = TLI.getRegisterType(*DAG.getContext(), EVT::getIntegerVT(*DAG.getContext(), StoredVT.getSizeInBits())); unsigned StoredBytes = StoredVT.getSizeInBits() / 8; unsigned RegBytes = RegVT.getSizeInBits() / 8; unsigned NumRegs = (StoredBytes + RegBytes - 1) / RegBytes; // Make sure the stack slot is also aligned for the register type. SDValue StackPtr = DAG.CreateStackTemporary(StoredVT, RegVT); // Perform the original store, only redirected to the stack slot. SDValue Store = DAG.getTruncStore(Chain, dl, Val, StackPtr, MachinePointerInfo(), StoredVT, false, false, 0); SDValue Increment = DAG.getConstant( RegBytes, dl, TLI.getPointerTy(DAG.getDataLayout(), AS)); SmallVector Stores; unsigned Offset = 0; // Do all but one copies using the full register width. for (unsigned i = 1; i < NumRegs; i++) { // Load one integer register's worth from the stack slot. SDValue Load = DAG.getLoad(RegVT, dl, Store, StackPtr, MachinePointerInfo(), false, false, false, 0); // Store it to the final location. Remember the store. Stores.push_back(DAG.getStore(Load.getValue(1), dl, Load, Ptr, ST->getPointerInfo().getWithOffset(Offset), ST->isVolatile(), ST->isNonTemporal(), MinAlign(ST->getAlignment(), Offset))); // Increment the pointers. Offset += RegBytes; StackPtr = DAG.getNode(ISD::ADD, dl, StackPtr.getValueType(), StackPtr, Increment); Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, Increment); } // The last store may be partial. Do a truncating store. On big-endian // machines this requires an extending load from the stack slot to ensure // that the bits are in the right place. EVT MemVT = EVT::getIntegerVT(*DAG.getContext(), 8 * (StoredBytes - Offset)); // Load from the stack slot. SDValue Load = DAG.getExtLoad(ISD::EXTLOAD, dl, RegVT, Store, StackPtr, MachinePointerInfo(), MemVT, false, false, false, 0); Stores.push_back(DAG.getTruncStore(Load.getValue(1), dl, Load, Ptr, ST->getPointerInfo() .getWithOffset(Offset), MemVT, ST->isVolatile(), ST->isNonTemporal(), MinAlign(ST->getAlignment(), Offset), ST->getAAInfo())); // The order of the stores doesn't matter - say it with a TokenFactor. SDValue Result = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Stores); DAGLegalize->ReplaceNode(SDValue(ST, 0), Result); return; } assert(ST->getMemoryVT().isInteger() && !ST->getMemoryVT().isVector() && "Unaligned store of unknown type."); // Get the half-size VT EVT NewStoredVT = ST->getMemoryVT().getHalfSizedIntegerVT(*DAG.getContext()); int NumBits = NewStoredVT.getSizeInBits(); int IncrementSize = NumBits / 8; // Divide the stored value in two parts. SDValue ShiftAmount = DAG.getConstant(NumBits, dl, TLI.getShiftAmountTy(Val.getValueType(), DAG.getDataLayout())); SDValue Lo = Val; SDValue Hi = DAG.getNode(ISD::SRL, dl, VT, Val, ShiftAmount); // Store the two parts SDValue Store1, Store2; Store1 = DAG.getTruncStore(Chain, dl, DAG.getDataLayout().isLittleEndian() ? Lo : Hi, Ptr, ST->getPointerInfo(), NewStoredVT, ST->isVolatile(), ST->isNonTemporal(), Alignment); Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getConstant(IncrementSize, dl, TLI.getPointerTy(DAG.getDataLayout(), AS))); Alignment = MinAlign(Alignment, IncrementSize); Store2 = DAG.getTruncStore( Chain, dl, DAG.getDataLayout().isLittleEndian() ? Hi : Lo, Ptr, ST->getPointerInfo().getWithOffset(IncrementSize), NewStoredVT, ST->isVolatile(), ST->isNonTemporal(), Alignment, ST->getAAInfo()); SDValue Result = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Store1, Store2); DAGLegalize->ReplaceNode(SDValue(ST, 0), Result); } /// Expands an unaligned load to 2 half-size loads. static void ExpandUnalignedLoad(LoadSDNode *LD, SelectionDAG &DAG, const TargetLowering &TLI, SDValue &ValResult, SDValue &ChainResult) { assert(LD->getAddressingMode() == ISD::UNINDEXED && "unaligned indexed loads not implemented!"); SDValue Chain = LD->getChain(); SDValue Ptr = LD->getBasePtr(); EVT VT = LD->getValueType(0); EVT LoadedVT = LD->getMemoryVT(); SDLoc dl(LD); if (VT.isFloatingPoint() || VT.isVector()) { EVT intVT = EVT::getIntegerVT(*DAG.getContext(), LoadedVT.getSizeInBits()); if (TLI.isTypeLegal(intVT) && TLI.isTypeLegal(LoadedVT)) { // Expand to a (misaligned) integer load of the same size, // then bitconvert to floating point or vector. SDValue newLoad = DAG.getLoad(intVT, dl, Chain, Ptr, LD->getMemOperand()); SDValue Result = DAG.getNode(ISD::BITCAST, dl, LoadedVT, newLoad); if (LoadedVT != VT) Result = DAG.getNode(VT.isFloatingPoint() ? ISD::FP_EXTEND : ISD::ANY_EXTEND, dl, VT, Result); ValResult = Result; ChainResult = newLoad.getValue(1); return; } // Copy the value to a (aligned) stack slot using (unaligned) integer // loads and stores, then do a (aligned) load from the stack slot. MVT RegVT = TLI.getRegisterType(*DAG.getContext(), intVT); unsigned LoadedBytes = LoadedVT.getSizeInBits() / 8; unsigned RegBytes = RegVT.getSizeInBits() / 8; unsigned NumRegs = (LoadedBytes + RegBytes - 1) / RegBytes; // Make sure the stack slot is also aligned for the register type. SDValue StackBase = DAG.CreateStackTemporary(LoadedVT, RegVT); SDValue Increment = DAG.getConstant(RegBytes, dl, TLI.getPointerTy(DAG.getDataLayout())); SmallVector Stores; SDValue StackPtr = StackBase; unsigned Offset = 0; // Do all but one copies using the full register width. for (unsigned i = 1; i < NumRegs; i++) { // Load one integer register's worth from the original location. SDValue Load = DAG.getLoad(RegVT, dl, Chain, Ptr, LD->getPointerInfo().getWithOffset(Offset), LD->isVolatile(), LD->isNonTemporal(), LD->isInvariant(), MinAlign(LD->getAlignment(), Offset), LD->getAAInfo()); // Follow the load with a store to the stack slot. Remember the store. Stores.push_back(DAG.getStore(Load.getValue(1), dl, Load, StackPtr, MachinePointerInfo(), false, false, 0)); // Increment the pointers. Offset += RegBytes; Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, Increment); StackPtr = DAG.getNode(ISD::ADD, dl, StackPtr.getValueType(), StackPtr, Increment); } // The last copy may be partial. Do an extending load. EVT MemVT = EVT::getIntegerVT(*DAG.getContext(), 8 * (LoadedBytes - Offset)); SDValue Load = DAG.getExtLoad(ISD::EXTLOAD, dl, RegVT, Chain, Ptr, LD->getPointerInfo().getWithOffset(Offset), MemVT, LD->isVolatile(), LD->isNonTemporal(), LD->isInvariant(), MinAlign(LD->getAlignment(), Offset), LD->getAAInfo()); // Follow the load with a store to the stack slot. Remember the store. // On big-endian machines this requires a truncating store to ensure // that the bits end up in the right place. Stores.push_back(DAG.getTruncStore(Load.getValue(1), dl, Load, StackPtr, MachinePointerInfo(), MemVT, false, false, 0)); // The order of the stores doesn't matter - say it with a TokenFactor. SDValue TF = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Stores); // Finally, perform the original load only redirected to the stack slot. Load = DAG.getExtLoad(LD->getExtensionType(), dl, VT, TF, StackBase, MachinePointerInfo(), LoadedVT, false,false, false, 0); // Callers expect a MERGE_VALUES node. ValResult = Load; ChainResult = TF; return; } assert(LoadedVT.isInteger() && !LoadedVT.isVector() && "Unaligned load of unsupported type."); // Compute the new VT that is half the size of the old one. This is an // integer MVT. unsigned NumBits = LoadedVT.getSizeInBits(); EVT NewLoadedVT; NewLoadedVT = EVT::getIntegerVT(*DAG.getContext(), NumBits/2); NumBits >>= 1; unsigned Alignment = LD->getAlignment(); unsigned IncrementSize = NumBits / 8; ISD::LoadExtType HiExtType = LD->getExtensionType(); // If the original load is NON_EXTLOAD, the hi part load must be ZEXTLOAD. if (HiExtType == ISD::NON_EXTLOAD) HiExtType = ISD::ZEXTLOAD; // Load the value in two parts SDValue Lo, Hi; if (DAG.getDataLayout().isLittleEndian()) { Lo = DAG.getExtLoad(ISD::ZEXTLOAD, dl, VT, Chain, Ptr, LD->getPointerInfo(), NewLoadedVT, LD->isVolatile(), LD->isNonTemporal(), LD->isInvariant(), Alignment, LD->getAAInfo()); Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getConstant(IncrementSize, dl, Ptr.getValueType())); Hi = DAG.getExtLoad(HiExtType, dl, VT, Chain, Ptr, LD->getPointerInfo().getWithOffset(IncrementSize), NewLoadedVT, LD->isVolatile(), LD->isNonTemporal(),LD->isInvariant(), MinAlign(Alignment, IncrementSize), LD->getAAInfo()); } else { Hi = DAG.getExtLoad(HiExtType, dl, VT, Chain, Ptr, LD->getPointerInfo(), NewLoadedVT, LD->isVolatile(), LD->isNonTemporal(), LD->isInvariant(), Alignment, LD->getAAInfo()); Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getConstant(IncrementSize, dl, Ptr.getValueType())); Lo = DAG.getExtLoad(ISD::ZEXTLOAD, dl, VT, Chain, Ptr, LD->getPointerInfo().getWithOffset(IncrementSize), NewLoadedVT, LD->isVolatile(), LD->isNonTemporal(), LD->isInvariant(), MinAlign(Alignment, IncrementSize), LD->getAAInfo()); } // aggregate the two parts SDValue ShiftAmount = DAG.getConstant(NumBits, dl, TLI.getShiftAmountTy(Hi.getValueType(), DAG.getDataLayout())); SDValue Result = DAG.getNode(ISD::SHL, dl, VT, Hi, ShiftAmount); Result = DAG.getNode(ISD::OR, dl, VT, Result, Lo); SDValue TF = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo.getValue(1), Hi.getValue(1)); ValResult = Result; ChainResult = TF; } /// Some target cannot handle a variable insertion index for the /// INSERT_VECTOR_ELT instruction. In this case, it /// is necessary to spill the vector being inserted into to memory, perform /// the insert there, and then read the result back. SDValue SelectionDAGLegalize:: PerformInsertVectorEltInMemory(SDValue Vec, SDValue Val, SDValue Idx, SDLoc dl) { SDValue Tmp1 = Vec; SDValue Tmp2 = Val; SDValue Tmp3 = Idx; // If the target doesn't support this, we have to spill the input vector // to a temporary stack slot, update the element, then reload it. This is // badness. We could also load the value into a vector register (either // with a "move to register" or "extload into register" instruction, then // permute it into place, if the idx is a constant and if the idx is // supported by the target. EVT VT = Tmp1.getValueType(); EVT EltVT = VT.getVectorElementType(); EVT IdxVT = Tmp3.getValueType(); EVT PtrVT = TLI.getPointerTy(DAG.getDataLayout()); SDValue StackPtr = DAG.CreateStackTemporary(VT); int SPFI = cast(StackPtr.getNode())->getIndex(); // Store the vector. SDValue Ch = DAG.getStore( DAG.getEntryNode(), dl, Tmp1, StackPtr, MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), SPFI), false, false, 0); // Truncate or zero extend offset to target pointer type. Tmp3 = DAG.getZExtOrTrunc(Tmp3, dl, PtrVT); // Add the offset to the index. unsigned EltSize = EltVT.getSizeInBits()/8; Tmp3 = DAG.getNode(ISD::MUL, dl, IdxVT, Tmp3, DAG.getConstant(EltSize, dl, IdxVT)); SDValue StackPtr2 = DAG.getNode(ISD::ADD, dl, IdxVT, Tmp3, StackPtr); // Store the scalar value. Ch = DAG.getTruncStore(Ch, dl, Tmp2, StackPtr2, MachinePointerInfo(), EltVT, false, false, 0); // Load the updated vector. return DAG.getLoad(VT, dl, Ch, StackPtr, MachinePointerInfo::getFixedStack( DAG.getMachineFunction(), SPFI), false, false, false, 0); } SDValue SelectionDAGLegalize:: ExpandINSERT_VECTOR_ELT(SDValue Vec, SDValue Val, SDValue Idx, SDLoc dl) { if (ConstantSDNode *InsertPos = dyn_cast(Idx)) { // SCALAR_TO_VECTOR requires that the type of the value being inserted // match the element type of the vector being created, except for // integers in which case the inserted value can be over width. EVT EltVT = Vec.getValueType().getVectorElementType(); if (Val.getValueType() == EltVT || (EltVT.isInteger() && Val.getValueType().bitsGE(EltVT))) { SDValue ScVec = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, Vec.getValueType(), Val); unsigned NumElts = Vec.getValueType().getVectorNumElements(); // We generate a shuffle of InVec and ScVec, so the shuffle mask // should be 0,1,2,3,4,5... with the appropriate element replaced with // elt 0 of the RHS. SmallVector ShufOps; for (unsigned i = 0; i != NumElts; ++i) ShufOps.push_back(i != InsertPos->getZExtValue() ? i : NumElts); return DAG.getVectorShuffle(Vec.getValueType(), dl, Vec, ScVec, &ShufOps[0]); } } return PerformInsertVectorEltInMemory(Vec, Val, Idx, dl); } SDValue SelectionDAGLegalize::OptimizeFloatStore(StoreSDNode* ST) { // Turn 'store float 1.0, Ptr' -> 'store int 0x12345678, Ptr' // FIXME: We shouldn't do this for TargetConstantFP's. // FIXME: move this to the DAG Combiner! Note that we can't regress due // to phase ordering between legalized code and the dag combiner. This // probably means that we need to integrate dag combiner and legalizer // together. // We generally can't do this one for long doubles. SDValue Chain = ST->getChain(); SDValue Ptr = ST->getBasePtr(); unsigned Alignment = ST->getAlignment(); bool isVolatile = ST->isVolatile(); bool isNonTemporal = ST->isNonTemporal(); AAMDNodes AAInfo = ST->getAAInfo(); SDLoc dl(ST); if (ConstantFPSDNode *CFP = dyn_cast(ST->getValue())) { if (CFP->getValueType(0) == MVT::f32 && TLI.isTypeLegal(MVT::i32)) { SDValue Con = DAG.getConstant(CFP->getValueAPF(). bitcastToAPInt().zextOrTrunc(32), SDLoc(CFP), MVT::i32); return DAG.getStore(Chain, dl, Con, Ptr, ST->getPointerInfo(), isVolatile, isNonTemporal, Alignment, AAInfo); } if (CFP->getValueType(0) == MVT::f64) { // If this target supports 64-bit registers, do a single 64-bit store. if (TLI.isTypeLegal(MVT::i64)) { SDValue Con = DAG.getConstant(CFP->getValueAPF().bitcastToAPInt(). zextOrTrunc(64), SDLoc(CFP), MVT::i64); return DAG.getStore(Chain, dl, Con, Ptr, ST->getPointerInfo(), isVolatile, isNonTemporal, Alignment, AAInfo); } if (TLI.isTypeLegal(MVT::i32) && !ST->isVolatile()) { // Otherwise, if the target supports 32-bit registers, use 2 32-bit // stores. If the target supports neither 32- nor 64-bits, this // xform is certainly not worth it. const APInt &IntVal = CFP->getValueAPF().bitcastToAPInt(); SDValue Lo = DAG.getConstant(IntVal.trunc(32), dl, MVT::i32); SDValue Hi = DAG.getConstant(IntVal.lshr(32).trunc(32), dl, MVT::i32); if (DAG.getDataLayout().isBigEndian()) std::swap(Lo, Hi); Lo = DAG.getStore(Chain, dl, Lo, Ptr, ST->getPointerInfo(), isVolatile, isNonTemporal, Alignment, AAInfo); Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getConstant(4, dl, Ptr.getValueType())); Hi = DAG.getStore(Chain, dl, Hi, Ptr, ST->getPointerInfo().getWithOffset(4), isVolatile, isNonTemporal, MinAlign(Alignment, 4U), AAInfo); return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo, Hi); } } } return SDValue(nullptr, 0); } void SelectionDAGLegalize::LegalizeStoreOps(SDNode *Node) { StoreSDNode *ST = cast(Node); SDValue Chain = ST->getChain(); SDValue Ptr = ST->getBasePtr(); SDLoc dl(Node); unsigned Alignment = ST->getAlignment(); bool isVolatile = ST->isVolatile(); bool isNonTemporal = ST->isNonTemporal(); AAMDNodes AAInfo = ST->getAAInfo(); if (!ST->isTruncatingStore()) { if (SDNode *OptStore = OptimizeFloatStore(ST).getNode()) { ReplaceNode(ST, OptStore); return; } { SDValue Value = ST->getValue(); MVT VT = Value.getSimpleValueType(); switch (TLI.getOperationAction(ISD::STORE, VT)) { default: llvm_unreachable("This action is not supported yet!"); case TargetLowering::Legal: { // If this is an unaligned store and the target doesn't support it, // expand it. EVT MemVT = ST->getMemoryVT(); unsigned AS = ST->getAddressSpace(); unsigned Align = ST->getAlignment(); const DataLayout &DL = DAG.getDataLayout(); if (!TLI.allowsMemoryAccess(*DAG.getContext(), DL, MemVT, AS, Align)) ExpandUnalignedStore(cast(Node), DAG, TLI, this); break; } case TargetLowering::Custom: { SDValue Res = TLI.LowerOperation(SDValue(Node, 0), DAG); if (Res && Res != SDValue(Node, 0)) ReplaceNode(SDValue(Node, 0), Res); return; } case TargetLowering::Promote: { MVT NVT = TLI.getTypeToPromoteTo(ISD::STORE, VT); assert(NVT.getSizeInBits() == VT.getSizeInBits() && "Can only promote stores to same size type"); Value = DAG.getNode(ISD::BITCAST, dl, NVT, Value); SDValue Result = DAG.getStore(Chain, dl, Value, Ptr, ST->getPointerInfo(), isVolatile, isNonTemporal, Alignment, AAInfo); ReplaceNode(SDValue(Node, 0), Result); break; } } return; } } else { SDValue Value = ST->getValue(); EVT StVT = ST->getMemoryVT(); unsigned StWidth = StVT.getSizeInBits(); auto &DL = DAG.getDataLayout(); if (StWidth != StVT.getStoreSizeInBits()) { // Promote to a byte-sized store with upper bits zero if not // storing an integral number of bytes. For example, promote // TRUNCSTORE:i1 X -> TRUNCSTORE:i8 (and X, 1) EVT NVT = EVT::getIntegerVT(*DAG.getContext(), StVT.getStoreSizeInBits()); Value = DAG.getZeroExtendInReg(Value, dl, StVT); SDValue Result = DAG.getTruncStore(Chain, dl, Value, Ptr, ST->getPointerInfo(), NVT, isVolatile, isNonTemporal, Alignment, AAInfo); ReplaceNode(SDValue(Node, 0), Result); } else if (StWidth & (StWidth - 1)) { // If not storing a power-of-2 number of bits, expand as two stores. assert(!StVT.isVector() && "Unsupported truncstore!"); unsigned RoundWidth = 1 << Log2_32(StWidth); assert(RoundWidth < StWidth); unsigned ExtraWidth = StWidth - RoundWidth; assert(ExtraWidth < RoundWidth); assert(!(RoundWidth % 8) && !(ExtraWidth % 8) && "Store size not an integral number of bytes!"); EVT RoundVT = EVT::getIntegerVT(*DAG.getContext(), RoundWidth); EVT ExtraVT = EVT::getIntegerVT(*DAG.getContext(), ExtraWidth); SDValue Lo, Hi; unsigned IncrementSize; if (DL.isLittleEndian()) { // TRUNCSTORE:i24 X -> TRUNCSTORE:i16 X, TRUNCSTORE@+2:i8 (srl X, 16) // Store the bottom RoundWidth bits. Lo = DAG.getTruncStore(Chain, dl, Value, Ptr, ST->getPointerInfo(), RoundVT, isVolatile, isNonTemporal, Alignment, AAInfo); // Store the remaining ExtraWidth bits. IncrementSize = RoundWidth / 8; Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getConstant(IncrementSize, dl, Ptr.getValueType())); Hi = DAG.getNode( ISD::SRL, dl, Value.getValueType(), Value, DAG.getConstant(RoundWidth, dl, TLI.getShiftAmountTy(Value.getValueType(), DL))); Hi = DAG.getTruncStore(Chain, dl, Hi, Ptr, ST->getPointerInfo().getWithOffset(IncrementSize), ExtraVT, isVolatile, isNonTemporal, MinAlign(Alignment, IncrementSize), AAInfo); } else { // Big endian - avoid unaligned stores. // TRUNCSTORE:i24 X -> TRUNCSTORE:i16 (srl X, 8), TRUNCSTORE@+2:i8 X // Store the top RoundWidth bits. Hi = DAG.getNode( ISD::SRL, dl, Value.getValueType(), Value, DAG.getConstant(ExtraWidth, dl, TLI.getShiftAmountTy(Value.getValueType(), DL))); Hi = DAG.getTruncStore(Chain, dl, Hi, Ptr, ST->getPointerInfo(), RoundVT, isVolatile, isNonTemporal, Alignment, AAInfo); // Store the remaining ExtraWidth bits. IncrementSize = RoundWidth / 8; Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getConstant(IncrementSize, dl, Ptr.getValueType())); Lo = DAG.getTruncStore(Chain, dl, Value, Ptr, ST->getPointerInfo().getWithOffset(IncrementSize), ExtraVT, isVolatile, isNonTemporal, MinAlign(Alignment, IncrementSize), AAInfo); } // The order of the stores doesn't matter. SDValue Result = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo, Hi); ReplaceNode(SDValue(Node, 0), Result); } else { switch (TLI.getTruncStoreAction(ST->getValue().getValueType(), StVT)) { default: llvm_unreachable("This action is not supported yet!"); case TargetLowering::Legal: { EVT MemVT = ST->getMemoryVT(); unsigned AS = ST->getAddressSpace(); unsigned Align = ST->getAlignment(); // If this is an unaligned store and the target doesn't support it, // expand it. if (!TLI.allowsMemoryAccess(*DAG.getContext(), DL, MemVT, AS, Align)) ExpandUnalignedStore(cast(Node), DAG, TLI, this); break; } case TargetLowering::Custom: { SDValue Res = TLI.LowerOperation(SDValue(Node, 0), DAG); if (Res && Res != SDValue(Node, 0)) ReplaceNode(SDValue(Node, 0), Res); return; } case TargetLowering::Expand: assert(!StVT.isVector() && "Vector Stores are handled in LegalizeVectorOps"); // TRUNCSTORE:i16 i32 -> STORE i16 assert(TLI.isTypeLegal(StVT) && "Do not know how to expand this store!"); Value = DAG.getNode(ISD::TRUNCATE, dl, StVT, Value); SDValue Result = DAG.getStore(Chain, dl, Value, Ptr, ST->getPointerInfo(), isVolatile, isNonTemporal, Alignment, AAInfo); ReplaceNode(SDValue(Node, 0), Result); break; } } } } void SelectionDAGLegalize::LegalizeLoadOps(SDNode *Node) { LoadSDNode *LD = cast(Node); SDValue Chain = LD->getChain(); // The chain. SDValue Ptr = LD->getBasePtr(); // The base pointer. SDValue Value; // The value returned by the load op. SDLoc dl(Node); ISD::LoadExtType ExtType = LD->getExtensionType(); if (ExtType == ISD::NON_EXTLOAD) { MVT VT = Node->getSimpleValueType(0); SDValue RVal = SDValue(Node, 0); SDValue RChain = SDValue(Node, 1); switch (TLI.getOperationAction(Node->getOpcode(), VT)) { default: llvm_unreachable("This action is not supported yet!"); case TargetLowering::Legal: { EVT MemVT = LD->getMemoryVT(); unsigned AS = LD->getAddressSpace(); unsigned Align = LD->getAlignment(); const DataLayout &DL = DAG.getDataLayout(); // If this is an unaligned load and the target doesn't support it, // expand it. if (!TLI.allowsMemoryAccess(*DAG.getContext(), DL, MemVT, AS, Align)) ExpandUnalignedLoad(cast(Node), DAG, TLI, RVal, RChain); break; } case TargetLowering::Custom: { SDValue Res = TLI.LowerOperation(RVal, DAG); if (Res.getNode()) { RVal = Res; RChain = Res.getValue(1); } break; } case TargetLowering::Promote: { MVT NVT = TLI.getTypeToPromoteTo(Node->getOpcode(), VT); assert(NVT.getSizeInBits() == VT.getSizeInBits() && "Can only promote loads to same size type"); SDValue Res = DAG.getLoad(NVT, dl, Chain, Ptr, LD->getMemOperand()); RVal = DAG.getNode(ISD::BITCAST, dl, VT, Res); RChain = Res.getValue(1); break; } } if (RChain.getNode() != Node) { assert(RVal.getNode() != Node && "Load must be completely replaced"); DAG.ReplaceAllUsesOfValueWith(SDValue(Node, 0), RVal); DAG.ReplaceAllUsesOfValueWith(SDValue(Node, 1), RChain); if (UpdatedNodes) { UpdatedNodes->insert(RVal.getNode()); UpdatedNodes->insert(RChain.getNode()); } ReplacedNode(Node); } return; } EVT SrcVT = LD->getMemoryVT(); unsigned SrcWidth = SrcVT.getSizeInBits(); unsigned Alignment = LD->getAlignment(); bool isVolatile = LD->isVolatile(); bool isNonTemporal = LD->isNonTemporal(); bool isInvariant = LD->isInvariant(); AAMDNodes AAInfo = LD->getAAInfo(); if (SrcWidth != SrcVT.getStoreSizeInBits() && // Some targets pretend to have an i1 loading operation, and actually // load an i8. This trick is correct for ZEXTLOAD because the top 7 // bits are guaranteed to be zero; it helps the optimizers understand // that these bits are zero. It is also useful for EXTLOAD, since it // tells the optimizers that those bits are undefined. It would be // nice to have an effective generic way of getting these benefits... // Until such a way is found, don't insist on promoting i1 here. (SrcVT != MVT::i1 || TLI.getLoadExtAction(ExtType, Node->getValueType(0), MVT::i1) == TargetLowering::Promote)) { // Promote to a byte-sized load if not loading an integral number of // bytes. For example, promote EXTLOAD:i20 -> EXTLOAD:i24. unsigned NewWidth = SrcVT.getStoreSizeInBits(); EVT NVT = EVT::getIntegerVT(*DAG.getContext(), NewWidth); SDValue Ch; // The extra bits are guaranteed to be zero, since we stored them that // way. A zext load from NVT thus automatically gives zext from SrcVT. ISD::LoadExtType NewExtType = ExtType == ISD::ZEXTLOAD ? ISD::ZEXTLOAD : ISD::EXTLOAD; SDValue Result = DAG.getExtLoad(NewExtType, dl, Node->getValueType(0), Chain, Ptr, LD->getPointerInfo(), NVT, isVolatile, isNonTemporal, isInvariant, Alignment, AAInfo); Ch = Result.getValue(1); // The chain. if (ExtType == ISD::SEXTLOAD) // Having the top bits zero doesn't help when sign extending. Result = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, Result.getValueType(), Result, DAG.getValueType(SrcVT)); else if (ExtType == ISD::ZEXTLOAD || NVT == Result.getValueType()) // All the top bits are guaranteed to be zero - inform the optimizers. Result = DAG.getNode(ISD::AssertZext, dl, Result.getValueType(), Result, DAG.getValueType(SrcVT)); Value = Result; Chain = Ch; } else if (SrcWidth & (SrcWidth - 1)) { // If not loading a power-of-2 number of bits, expand as two loads. assert(!SrcVT.isVector() && "Unsupported extload!"); unsigned RoundWidth = 1 << Log2_32(SrcWidth); assert(RoundWidth < SrcWidth); unsigned ExtraWidth = SrcWidth - RoundWidth; assert(ExtraWidth < RoundWidth); assert(!(RoundWidth % 8) && !(ExtraWidth % 8) && "Load size not an integral number of bytes!"); EVT RoundVT = EVT::getIntegerVT(*DAG.getContext(), RoundWidth); EVT ExtraVT = EVT::getIntegerVT(*DAG.getContext(), ExtraWidth); SDValue Lo, Hi, Ch; unsigned IncrementSize; auto &DL = DAG.getDataLayout(); if (DL.isLittleEndian()) { // EXTLOAD:i24 -> ZEXTLOAD:i16 | (shl EXTLOAD@+2:i8, 16) // Load the bottom RoundWidth bits. Lo = DAG.getExtLoad(ISD::ZEXTLOAD, dl, Node->getValueType(0), Chain, Ptr, LD->getPointerInfo(), RoundVT, isVolatile, isNonTemporal, isInvariant, Alignment, AAInfo); // Load the remaining ExtraWidth bits. IncrementSize = RoundWidth / 8; Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getConstant(IncrementSize, dl, Ptr.getValueType())); Hi = DAG.getExtLoad(ExtType, dl, Node->getValueType(0), Chain, Ptr, LD->getPointerInfo().getWithOffset(IncrementSize), ExtraVT, isVolatile, isNonTemporal, isInvariant, MinAlign(Alignment, IncrementSize), AAInfo); // Build a factor node to remember that this load is independent of // the other one. Ch = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo.getValue(1), Hi.getValue(1)); // Move the top bits to the right place. Hi = DAG.getNode( ISD::SHL, dl, Hi.getValueType(), Hi, DAG.getConstant(RoundWidth, dl, TLI.getShiftAmountTy(Hi.getValueType(), DL))); // Join the hi and lo parts. Value = DAG.getNode(ISD::OR, dl, Node->getValueType(0), Lo, Hi); } else { // Big endian - avoid unaligned loads. // EXTLOAD:i24 -> (shl EXTLOAD:i16, 8) | ZEXTLOAD@+2:i8 // Load the top RoundWidth bits. Hi = DAG.getExtLoad(ExtType, dl, Node->getValueType(0), Chain, Ptr, LD->getPointerInfo(), RoundVT, isVolatile, isNonTemporal, isInvariant, Alignment, AAInfo); // Load the remaining ExtraWidth bits. IncrementSize = RoundWidth / 8; Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getConstant(IncrementSize, dl, Ptr.getValueType())); Lo = DAG.getExtLoad(ISD::ZEXTLOAD, dl, Node->getValueType(0), Chain, Ptr, LD->getPointerInfo().getWithOffset(IncrementSize), ExtraVT, isVolatile, isNonTemporal, isInvariant, MinAlign(Alignment, IncrementSize), AAInfo); // Build a factor node to remember that this load is independent of // the other one. Ch = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo.getValue(1), Hi.getValue(1)); // Move the top bits to the right place. Hi = DAG.getNode( ISD::SHL, dl, Hi.getValueType(), Hi, DAG.getConstant(ExtraWidth, dl, TLI.getShiftAmountTy(Hi.getValueType(), DL))); // Join the hi and lo parts. Value = DAG.getNode(ISD::OR, dl, Node->getValueType(0), Lo, Hi); } Chain = Ch; } else { bool isCustom = false; switch (TLI.getLoadExtAction(ExtType, Node->getValueType(0), SrcVT.getSimpleVT())) { default: llvm_unreachable("This action is not supported yet!"); case TargetLowering::Custom: isCustom = true; // FALLTHROUGH case TargetLowering::Legal: { Value = SDValue(Node, 0); Chain = SDValue(Node, 1); if (isCustom) { SDValue Res = TLI.LowerOperation(SDValue(Node, 0), DAG); if (Res.getNode()) { Value = Res; Chain = Res.getValue(1); } } else { // If this is an unaligned load and the target doesn't support it, // expand it. EVT MemVT = LD->getMemoryVT(); unsigned AS = LD->getAddressSpace(); unsigned Align = LD->getAlignment(); const DataLayout &DL = DAG.getDataLayout(); if (!TLI.allowsMemoryAccess(*DAG.getContext(), DL, MemVT, AS, Align)) ExpandUnalignedLoad(cast(Node), DAG, TLI, Value, Chain); } break; } case TargetLowering::Expand: EVT DestVT = Node->getValueType(0); if (!TLI.isLoadExtLegal(ISD::EXTLOAD, DestVT, SrcVT)) { // If the source type is not legal, see if there is a legal extload to // an intermediate type that we can then extend further. EVT LoadVT = TLI.getRegisterType(SrcVT.getSimpleVT()); if (TLI.isTypeLegal(SrcVT) || // Same as SrcVT == LoadVT? TLI.isLoadExtLegal(ExtType, LoadVT, SrcVT)) { // If we are loading a legal type, this is a non-extload followed by a // full extend. ISD::LoadExtType MidExtType = (LoadVT == SrcVT) ? ISD::NON_EXTLOAD : ExtType; SDValue Load = DAG.getExtLoad(MidExtType, dl, LoadVT, Chain, Ptr, SrcVT, LD->getMemOperand()); unsigned ExtendOp = ISD::getExtForLoadExtType(SrcVT.isFloatingPoint(), ExtType); Value = DAG.getNode(ExtendOp, dl, Node->getValueType(0), Load); Chain = Load.getValue(1); break; } // Handle the special case of fp16 extloads. EXTLOAD doesn't have the // normal undefined upper bits behavior to allow using an in-reg extend // with the illegal FP type, so load as an integer and do the // from-integer conversion. if (SrcVT.getScalarType() == MVT::f16) { EVT ISrcVT = SrcVT.changeTypeToInteger(); EVT IDestVT = DestVT.changeTypeToInteger(); EVT LoadVT = TLI.getRegisterType(IDestVT.getSimpleVT()); SDValue Result = DAG.getExtLoad(ISD::ZEXTLOAD, dl, LoadVT, Chain, Ptr, ISrcVT, LD->getMemOperand()); Value = DAG.getNode(ISD::FP16_TO_FP, dl, DestVT, Result); Chain = Result.getValue(1); break; } } assert(!SrcVT.isVector() && "Vector Loads are handled in LegalizeVectorOps"); // FIXME: This does not work for vectors on most targets. Sign- // and zero-extend operations are currently folded into extending // loads, whether they are legal or not, and then we end up here // without any support for legalizing them. assert(ExtType != ISD::EXTLOAD && "EXTLOAD should always be supported!"); // Turn the unsupported load into an EXTLOAD followed by an // explicit zero/sign extend inreg. SDValue Result = DAG.getExtLoad(ISD::EXTLOAD, dl, Node->getValueType(0), Chain, Ptr, SrcVT, LD->getMemOperand()); SDValue ValRes; if (ExtType == ISD::SEXTLOAD) ValRes = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, Result.getValueType(), Result, DAG.getValueType(SrcVT)); else ValRes = DAG.getZeroExtendInReg(Result, dl, SrcVT.getScalarType()); Value = ValRes; Chain = Result.getValue(1); break; } } // Since loads produce two values, make sure to remember that we legalized // both of them. if (Chain.getNode() != Node) { assert(Value.getNode() != Node && "Load must be completely replaced"); DAG.ReplaceAllUsesOfValueWith(SDValue(Node, 0), Value); DAG.ReplaceAllUsesOfValueWith(SDValue(Node, 1), Chain); if (UpdatedNodes) { UpdatedNodes->insert(Value.getNode()); UpdatedNodes->insert(Chain.getNode()); } ReplacedNode(Node); } } /// Return a legal replacement for the given operation, with all legal operands. void SelectionDAGLegalize::LegalizeOp(SDNode *Node) { DEBUG(dbgs() << "\nLegalizing: "; Node->dump(&DAG)); if (Node->getOpcode() == ISD::TargetConstant) // Allow illegal target nodes. return; #ifndef NDEBUG for (unsigned i = 0, e = Node->getNumValues(); i != e; ++i) assert((TLI.getTypeAction(*DAG.getContext(), Node->getValueType(i)) == TargetLowering::TypeLegal || TLI.isTypeLegal(Node->getValueType(i))) && "Unexpected illegal type!"); for (const SDValue &Op : Node->op_values()) assert((TLI.getTypeAction(*DAG.getContext(), Op.getValueType()) == TargetLowering::TypeLegal || TLI.isTypeLegal(Op.getValueType()) || Op.getOpcode() == ISD::TargetConstant) && "Unexpected illegal type!"); #endif // Figure out the correct action; the way to query this varies by opcode TargetLowering::LegalizeAction Action = TargetLowering::Legal; bool SimpleFinishLegalizing = true; switch (Node->getOpcode()) { case ISD::INTRINSIC_W_CHAIN: case ISD::INTRINSIC_WO_CHAIN: case ISD::INTRINSIC_VOID: case ISD::STACKSAVE: Action = TLI.getOperationAction(Node->getOpcode(), MVT::Other); break; case ISD::GET_DYNAMIC_AREA_OFFSET: Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); break; case ISD::VAARG: Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); if (Action != TargetLowering::Promote) Action = TLI.getOperationAction(Node->getOpcode(), MVT::Other); break; case ISD::FP_TO_FP16: case ISD::SINT_TO_FP: case ISD::UINT_TO_FP: case ISD::EXTRACT_VECTOR_ELT: Action = TLI.getOperationAction(Node->getOpcode(), Node->getOperand(0).getValueType()); break; case ISD::FP_ROUND_INREG: case ISD::SIGN_EXTEND_INREG: { EVT InnerType = cast(Node->getOperand(1))->getVT(); Action = TLI.getOperationAction(Node->getOpcode(), InnerType); break; } case ISD::ATOMIC_STORE: { Action = TLI.getOperationAction(Node->getOpcode(), Node->getOperand(2).getValueType()); break; } case ISD::SELECT_CC: case ISD::SETCC: case ISD::BR_CC: { unsigned CCOperand = Node->getOpcode() == ISD::SELECT_CC ? 4 : Node->getOpcode() == ISD::SETCC ? 2 : Node->getOpcode() == ISD::SETCCE ? 3 : 1; unsigned CompareOperand = Node->getOpcode() == ISD::BR_CC ? 2 : 0; MVT OpVT = Node->getOperand(CompareOperand).getSimpleValueType(); ISD::CondCode CCCode = cast(Node->getOperand(CCOperand))->get(); Action = TLI.getCondCodeAction(CCCode, OpVT); if (Action == TargetLowering::Legal) { if (Node->getOpcode() == ISD::SELECT_CC) Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); else Action = TLI.getOperationAction(Node->getOpcode(), OpVT); } break; } case ISD::LOAD: case ISD::STORE: // FIXME: Model these properly. LOAD and STORE are complicated, and // STORE expects the unlegalized operand in some cases. SimpleFinishLegalizing = false; break; case ISD::CALLSEQ_START: case ISD::CALLSEQ_END: // FIXME: This shouldn't be necessary. These nodes have special properties // dealing with the recursive nature of legalization. Removing this // special case should be done as part of making LegalizeDAG non-recursive. SimpleFinishLegalizing = false; break; case ISD::EXTRACT_ELEMENT: case ISD::FLT_ROUNDS_: case ISD::FPOWI: case ISD::MERGE_VALUES: case ISD::EH_RETURN: case ISD::FRAME_TO_ARGS_OFFSET: case ISD::EH_SJLJ_SETJMP: case ISD::EH_SJLJ_LONGJMP: case ISD::EH_SJLJ_SETUP_DISPATCH: // These operations lie about being legal: when they claim to be legal, // they should actually be expanded. Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); if (Action == TargetLowering::Legal) Action = TargetLowering::Expand; break; case ISD::INIT_TRAMPOLINE: case ISD::ADJUST_TRAMPOLINE: case ISD::FRAMEADDR: case ISD::RETURNADDR: // These operations lie about being legal: when they claim to be legal, // they should actually be custom-lowered. Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); if (Action == TargetLowering::Legal) Action = TargetLowering::Custom; break; case ISD::READCYCLECOUNTER: // READCYCLECOUNTER returns an i64, even if type legalization might have // expanded that to several smaller types. Action = TLI.getOperationAction(Node->getOpcode(), MVT::i64); break; case ISD::READ_REGISTER: case ISD::WRITE_REGISTER: // Named register is legal in the DAG, but blocked by register name // selection if not implemented by target (to chose the correct register) // They'll be converted to Copy(To/From)Reg. Action = TargetLowering::Legal; break; case ISD::DEBUGTRAP: Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); if (Action == TargetLowering::Expand) { // replace ISD::DEBUGTRAP with ISD::TRAP SDValue NewVal; NewVal = DAG.getNode(ISD::TRAP, SDLoc(Node), Node->getVTList(), Node->getOperand(0)); ReplaceNode(Node, NewVal.getNode()); LegalizeOp(NewVal.getNode()); return; } break; default: if (Node->getOpcode() >= ISD::BUILTIN_OP_END) { Action = TargetLowering::Legal; } else { Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); } break; } if (SimpleFinishLegalizing) { SDNode *NewNode = Node; switch (Node->getOpcode()) { default: break; case ISD::SHL: case ISD::SRL: case ISD::SRA: case ISD::ROTL: case ISD::ROTR: // Legalizing shifts/rotates requires adjusting the shift amount // to the appropriate width. if (!Node->getOperand(1).getValueType().isVector()) { SDValue SAO = DAG.getShiftAmountOperand(Node->getOperand(0).getValueType(), Node->getOperand(1)); HandleSDNode Handle(SAO); LegalizeOp(SAO.getNode()); NewNode = DAG.UpdateNodeOperands(Node, Node->getOperand(0), Handle.getValue()); } break; case ISD::SRL_PARTS: case ISD::SRA_PARTS: case ISD::SHL_PARTS: // Legalizing shifts/rotates requires adjusting the shift amount // to the appropriate width. if (!Node->getOperand(2).getValueType().isVector()) { SDValue SAO = DAG.getShiftAmountOperand(Node->getOperand(0).getValueType(), Node->getOperand(2)); HandleSDNode Handle(SAO); LegalizeOp(SAO.getNode()); NewNode = DAG.UpdateNodeOperands(Node, Node->getOperand(0), Node->getOperand(1), Handle.getValue()); } break; } if (NewNode != Node) { ReplaceNode(Node, NewNode); Node = NewNode; } switch (Action) { case TargetLowering::Legal: return; case TargetLowering::Custom: { // FIXME: The handling for custom lowering with multiple results is // a complete mess. SDValue Res = TLI.LowerOperation(SDValue(Node, 0), DAG); if (Res.getNode()) { if (!(Res.getNode() != Node || Res.getResNo() != 0)) return; if (Node->getNumValues() == 1) { // We can just directly replace this node with the lowered value. ReplaceNode(SDValue(Node, 0), Res); return; } SmallVector ResultVals; for (unsigned i = 0, e = Node->getNumValues(); i != e; ++i) ResultVals.push_back(Res.getValue(i)); ReplaceNode(Node, ResultVals.data()); return; } } // FALL THROUGH case TargetLowering::Expand: if (ExpandNode(Node)) return; // FALL THROUGH case TargetLowering::LibCall: ConvertNodeToLibcall(Node); return; case TargetLowering::Promote: PromoteNode(Node); return; } } switch (Node->getOpcode()) { default: #ifndef NDEBUG dbgs() << "NODE: "; Node->dump( &DAG); dbgs() << "\n"; #endif llvm_unreachable("Do not know how to legalize this operator!"); case ISD::CALLSEQ_START: case ISD::CALLSEQ_END: break; case ISD::LOAD: { return LegalizeLoadOps(Node); } case ISD::STORE: { return LegalizeStoreOps(Node); } } } SDValue SelectionDAGLegalize::ExpandExtractFromVectorThroughStack(SDValue Op) { SDValue Vec = Op.getOperand(0); SDValue Idx = Op.getOperand(1); SDLoc dl(Op); // Before we generate a new store to a temporary stack slot, see if there is // already one that we can use. There often is because when we scalarize // vector operations (using SelectionDAG::UnrollVectorOp for example) a whole // series of EXTRACT_VECTOR_ELT nodes are generated, one for each element in // the vector. If all are expanded here, we don't want one store per vector // element. // Caches for hasPredecessorHelper SmallPtrSet Visited; SmallVector Worklist; SDValue StackPtr, Ch; for (SDNode::use_iterator UI = Vec.getNode()->use_begin(), UE = Vec.getNode()->use_end(); UI != UE; ++UI) { SDNode *User = *UI; if (StoreSDNode *ST = dyn_cast(User)) { if (ST->isIndexed() || ST->isTruncatingStore() || ST->getValue() != Vec) continue; // Make sure that nothing else could have stored into the destination of // this store. if (!ST->getChain().reachesChainWithoutSideEffects(DAG.getEntryNode())) continue; // If the index is dependent on the store we will introduce a cycle when // creating the load (the load uses the index, and by replacing the chain // we will make the index dependent on the load). if (Idx.getNode()->hasPredecessorHelper(ST, Visited, Worklist)) continue; StackPtr = ST->getBasePtr(); Ch = SDValue(ST, 0); break; } } if (!Ch.getNode()) { // Store the value to a temporary stack slot, then LOAD the returned part. StackPtr = DAG.CreateStackTemporary(Vec.getValueType()); Ch = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, MachinePointerInfo(), false, false, 0); } // Add the offset to the index. unsigned EltSize = Vec.getValueType().getVectorElementType().getSizeInBits()/8; Idx = DAG.getNode(ISD::MUL, dl, Idx.getValueType(), Idx, DAG.getConstant(EltSize, SDLoc(Vec), Idx.getValueType())); Idx = DAG.getZExtOrTrunc(Idx, dl, TLI.getPointerTy(DAG.getDataLayout())); StackPtr = DAG.getNode(ISD::ADD, dl, Idx.getValueType(), Idx, StackPtr); SDValue NewLoad; if (Op.getValueType().isVector()) NewLoad = DAG.getLoad(Op.getValueType(), dl, Ch, StackPtr, MachinePointerInfo(), false, false, false, 0); else NewLoad = DAG.getExtLoad( ISD::EXTLOAD, dl, Op.getValueType(), Ch, StackPtr, MachinePointerInfo(), Vec.getValueType().getVectorElementType(), false, false, false, 0); // Replace the chain going out of the store, by the one out of the load. DAG.ReplaceAllUsesOfValueWith(Ch, SDValue(NewLoad.getNode(), 1)); // We introduced a cycle though, so update the loads operands, making sure // to use the original store's chain as an incoming chain. SmallVector NewLoadOperands(NewLoad->op_begin(), NewLoad->op_end()); NewLoadOperands[0] = Ch; NewLoad = SDValue(DAG.UpdateNodeOperands(NewLoad.getNode(), NewLoadOperands), 0); return NewLoad; } SDValue SelectionDAGLegalize::ExpandInsertToVectorThroughStack(SDValue Op) { assert(Op.getValueType().isVector() && "Non-vector insert subvector!"); SDValue Vec = Op.getOperand(0); SDValue Part = Op.getOperand(1); SDValue Idx = Op.getOperand(2); SDLoc dl(Op); // Store the value to a temporary stack slot, then LOAD the returned part. SDValue StackPtr = DAG.CreateStackTemporary(Vec.getValueType()); int FI = cast(StackPtr.getNode())->getIndex(); MachinePointerInfo PtrInfo = MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI); // First store the whole vector. SDValue Ch = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, PtrInfo, false, false, 0); // Then store the inserted part. // Add the offset to the index. unsigned EltSize = Vec.getValueType().getVectorElementType().getSizeInBits()/8; Idx = DAG.getNode(ISD::MUL, dl, Idx.getValueType(), Idx, DAG.getConstant(EltSize, SDLoc(Vec), Idx.getValueType())); Idx = DAG.getZExtOrTrunc(Idx, dl, TLI.getPointerTy(DAG.getDataLayout())); SDValue SubStackPtr = DAG.getNode(ISD::ADD, dl, Idx.getValueType(), Idx, StackPtr); // Store the subvector. Ch = DAG.getStore(Ch, dl, Part, SubStackPtr, MachinePointerInfo(), false, false, 0); // Finally, load the updated vector. return DAG.getLoad(Op.getValueType(), dl, Ch, StackPtr, PtrInfo, false, false, false, 0); } SDValue SelectionDAGLegalize::ExpandVectorBuildThroughStack(SDNode* Node) { // We can't handle this case efficiently. Allocate a sufficiently // aligned object on the stack, store each element into it, then load // the result as a vector. // Create the stack frame object. EVT VT = Node->getValueType(0); EVT EltVT = VT.getVectorElementType(); SDLoc dl(Node); SDValue FIPtr = DAG.CreateStackTemporary(VT); int FI = cast(FIPtr.getNode())->getIndex(); MachinePointerInfo PtrInfo = MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI); // Emit a store of each element to the stack slot. SmallVector Stores; unsigned TypeByteSize = EltVT.getSizeInBits() / 8; // Store (in the right endianness) the elements to memory. for (unsigned i = 0, e = Node->getNumOperands(); i != e; ++i) { // Ignore undef elements. if (Node->getOperand(i).getOpcode() == ISD::UNDEF) continue; unsigned Offset = TypeByteSize*i; SDValue Idx = DAG.getConstant(Offset, dl, FIPtr.getValueType()); Idx = DAG.getNode(ISD::ADD, dl, FIPtr.getValueType(), FIPtr, Idx); // If the destination vector element type is narrower than the source // element type, only store the bits necessary. if (EltVT.bitsLT(Node->getOperand(i).getValueType().getScalarType())) { Stores.push_back(DAG.getTruncStore(DAG.getEntryNode(), dl, Node->getOperand(i), Idx, PtrInfo.getWithOffset(Offset), EltVT, false, false, 0)); } else Stores.push_back(DAG.getStore(DAG.getEntryNode(), dl, Node->getOperand(i), Idx, PtrInfo.getWithOffset(Offset), false, false, 0)); } SDValue StoreChain; if (!Stores.empty()) // Not all undef elements? StoreChain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Stores); else StoreChain = DAG.getEntryNode(); // Result is a load from the stack slot. return DAG.getLoad(VT, dl, StoreChain, FIPtr, PtrInfo, false, false, false, 0); } namespace { /// Keeps track of state when getting the sign of a floating-point value as an /// integer. struct FloatSignAsInt { EVT FloatVT; SDValue Chain; SDValue FloatPtr; SDValue IntPtr; MachinePointerInfo IntPointerInfo; MachinePointerInfo FloatPointerInfo; SDValue IntValue; APInt SignMask; + uint8_t SignBit; }; } /// Bitcast a floating-point value to an integer value. Only bitcast the part /// containing the sign bit if the target has no integer value capable of /// holding all bits of the floating-point value. void SelectionDAGLegalize::getSignAsIntValue(FloatSignAsInt &State, SDLoc DL, SDValue Value) const { EVT FloatVT = Value.getValueType(); unsigned NumBits = FloatVT.getSizeInBits(); State.FloatVT = FloatVT; EVT IVT = EVT::getIntegerVT(*DAG.getContext(), NumBits); // Convert to an integer of the same size. if (TLI.isTypeLegal(IVT)) { State.IntValue = DAG.getNode(ISD::BITCAST, DL, IVT, Value); State.SignMask = APInt::getSignBit(NumBits); + State.SignBit = NumBits - 1; return; } auto &DataLayout = DAG.getDataLayout(); // Store the float to memory, then load the sign part out as an integer. MVT LoadTy = TLI.getRegisterType(*DAG.getContext(), MVT::i8); // First create a temporary that is aligned for both the load and store. SDValue StackPtr = DAG.CreateStackTemporary(FloatVT, LoadTy); int FI = cast(StackPtr.getNode())->getIndex(); // Then store the float to it. State.FloatPtr = StackPtr; MachineFunction &MF = DAG.getMachineFunction(); State.FloatPointerInfo = MachinePointerInfo::getFixedStack(MF, FI); State.Chain = DAG.getStore(DAG.getEntryNode(), DL, Value, State.FloatPtr, State.FloatPointerInfo, false, false, 0); SDValue IntPtr; if (DataLayout.isBigEndian()) { assert(FloatVT.isByteSized() && "Unsupported floating point type!"); // Load out a legal integer with the same sign bit as the float. IntPtr = StackPtr; State.IntPointerInfo = State.FloatPointerInfo; } else { // Advance the pointer so that the loaded byte will contain the sign bit. unsigned ByteOffset = (FloatVT.getSizeInBits() / 8) - 1; IntPtr = DAG.getNode(ISD::ADD, DL, StackPtr.getValueType(), StackPtr, DAG.getConstant(ByteOffset, DL, StackPtr.getValueType())); State.IntPointerInfo = MachinePointerInfo::getFixedStack(MF, FI, ByteOffset); } State.IntPtr = IntPtr; State.IntValue = DAG.getExtLoad(ISD::EXTLOAD, DL, LoadTy, State.Chain, IntPtr, State.IntPointerInfo, MVT::i8, false, false, false, 0); State.SignMask = APInt::getOneBitSet(LoadTy.getSizeInBits(), 7); + State.SignBit = 7; } /// Replace the integer value produced by getSignAsIntValue() with a new value /// and cast the result back to a floating-point type. SDValue SelectionDAGLegalize::modifySignAsInt(const FloatSignAsInt &State, SDLoc DL, SDValue NewIntValue) const { if (!State.Chain) return DAG.getNode(ISD::BITCAST, DL, State.FloatVT, NewIntValue); // Override the part containing the sign bit in the value stored on the stack. SDValue Chain = DAG.getTruncStore(State.Chain, DL, NewIntValue, State.IntPtr, State.IntPointerInfo, MVT::i8, false, false, 0); return DAG.getLoad(State.FloatVT, DL, Chain, State.FloatPtr, State.FloatPointerInfo, false, false, false, 0); } SDValue SelectionDAGLegalize::ExpandFCOPYSIGN(SDNode *Node) const { SDLoc DL(Node); SDValue Mag = Node->getOperand(0); SDValue Sign = Node->getOperand(1); // Get sign bit into an integer value. FloatSignAsInt SignAsInt; getSignAsIntValue(SignAsInt, DL, Sign); EVT IntVT = SignAsInt.IntValue.getValueType(); SDValue SignMask = DAG.getConstant(SignAsInt.SignMask, DL, IntVT); SDValue SignBit = DAG.getNode(ISD::AND, DL, IntVT, SignAsInt.IntValue, SignMask); // If FABS is legal transform FCOPYSIGN(x, y) => sign(x) ? -FABS(x) : FABS(X) EVT FloatVT = Mag.getValueType(); if (TLI.isOperationLegalOrCustom(ISD::FABS, FloatVT) && TLI.isOperationLegalOrCustom(ISD::FNEG, FloatVT)) { SDValue AbsValue = DAG.getNode(ISD::FABS, DL, FloatVT, Mag); SDValue NegValue = DAG.getNode(ISD::FNEG, DL, FloatVT, AbsValue); SDValue Cond = DAG.getSetCC(DL, getSetCCResultType(IntVT), SignBit, DAG.getConstant(0, DL, IntVT), ISD::SETNE); return DAG.getSelect(DL, FloatVT, Cond, NegValue, AbsValue); } - // Transform values to integer, copy the sign bit and transform back. + // Transform Mag value to integer, and clear the sign bit. FloatSignAsInt MagAsInt; getSignAsIntValue(MagAsInt, DL, Mag); - assert(SignAsInt.SignMask == MagAsInt.SignMask); - SDValue ClearSignMask = DAG.getConstant(~SignAsInt.SignMask, DL, IntVT); - SDValue ClearedSign = DAG.getNode(ISD::AND, DL, IntVT, MagAsInt.IntValue, + EVT MagVT = MagAsInt.IntValue.getValueType(); + SDValue ClearSignMask = DAG.getConstant(~MagAsInt.SignMask, DL, MagVT); + SDValue ClearedSign = DAG.getNode(ISD::AND, DL, MagVT, MagAsInt.IntValue, ClearSignMask); - SDValue CopiedSign = DAG.getNode(ISD::OR, DL, IntVT, ClearedSign, SignBit); + // Get the signbit at the right position for MagAsInt. + int ShiftAmount = SignAsInt.SignBit - MagAsInt.SignBit; + if (SignBit.getValueSizeInBits() > ClearedSign.getValueSizeInBits()) { + if (ShiftAmount > 0) { + SDValue ShiftCnst = DAG.getConstant(ShiftAmount, DL, IntVT); + SignBit = DAG.getNode(ISD::SRL, DL, IntVT, SignBit, ShiftCnst); + } else if (ShiftAmount < 0) { + SDValue ShiftCnst = DAG.getConstant(-ShiftAmount, DL, IntVT); + SignBit = DAG.getNode(ISD::SHL, DL, IntVT, SignBit, ShiftCnst); + } + SignBit = DAG.getNode(ISD::TRUNCATE, DL, MagVT, SignBit); + } else if (SignBit.getValueSizeInBits() < ClearedSign.getValueSizeInBits()) { + SignBit = DAG.getNode(ISD::ZERO_EXTEND, DL, MagVT, SignBit); + if (ShiftAmount > 0) { + SDValue ShiftCnst = DAG.getConstant(ShiftAmount, DL, MagVT); + SignBit = DAG.getNode(ISD::SRL, DL, MagVT, SignBit, ShiftCnst); + } else if (ShiftAmount < 0) { + SDValue ShiftCnst = DAG.getConstant(-ShiftAmount, DL, MagVT); + SignBit = DAG.getNode(ISD::SHL, DL, MagVT, SignBit, ShiftCnst); + } + } + + // Store the part with the modified sign and convert back to float. + SDValue CopiedSign = DAG.getNode(ISD::OR, DL, MagVT, ClearedSign, SignBit); return modifySignAsInt(MagAsInt, DL, CopiedSign); } SDValue SelectionDAGLegalize::ExpandFABS(SDNode *Node) const { SDLoc DL(Node); SDValue Value = Node->getOperand(0); // Transform FABS(x) => FCOPYSIGN(x, 0.0) if FCOPYSIGN is legal. EVT FloatVT = Value.getValueType(); if (TLI.isOperationLegalOrCustom(ISD::FCOPYSIGN, FloatVT)) { SDValue Zero = DAG.getConstantFP(0.0, DL, FloatVT); return DAG.getNode(ISD::FCOPYSIGN, DL, FloatVT, Value, Zero); } // Transform value to integer, clear the sign bit and transform back. FloatSignAsInt ValueAsInt; getSignAsIntValue(ValueAsInt, DL, Value); EVT IntVT = ValueAsInt.IntValue.getValueType(); SDValue ClearSignMask = DAG.getConstant(~ValueAsInt.SignMask, DL, IntVT); SDValue ClearedSign = DAG.getNode(ISD::AND, DL, IntVT, ValueAsInt.IntValue, ClearSignMask); return modifySignAsInt(ValueAsInt, DL, ClearedSign); } void SelectionDAGLegalize::ExpandDYNAMIC_STACKALLOC(SDNode* Node, SmallVectorImpl &Results) { unsigned SPReg = TLI.getStackPointerRegisterToSaveRestore(); assert(SPReg && "Target cannot require DYNAMIC_STACKALLOC expansion and" " not tell us which reg is the stack pointer!"); SDLoc dl(Node); EVT VT = Node->getValueType(0); SDValue Tmp1 = SDValue(Node, 0); SDValue Tmp2 = SDValue(Node, 1); SDValue Tmp3 = Node->getOperand(2); SDValue Chain = Tmp1.getOperand(0); // Chain the dynamic stack allocation so that it doesn't modify the stack // pointer when other instructions are using the stack. Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(0, dl, true), dl); SDValue Size = Tmp2.getOperand(1); SDValue SP = DAG.getCopyFromReg(Chain, dl, SPReg, VT); Chain = SP.getValue(1); unsigned Align = cast(Tmp3)->getZExtValue(); unsigned StackAlign = DAG.getSubtarget().getFrameLowering()->getStackAlignment(); Tmp1 = DAG.getNode(ISD::SUB, dl, VT, SP, Size); // Value if (Align > StackAlign) Tmp1 = DAG.getNode(ISD::AND, dl, VT, Tmp1, DAG.getConstant(-(uint64_t)Align, dl, VT)); Chain = DAG.getCopyToReg(Chain, dl, SPReg, Tmp1); // Output chain Tmp2 = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(0, dl, true), DAG.getIntPtrConstant(0, dl, true), SDValue(), dl); Results.push_back(Tmp1); Results.push_back(Tmp2); } /// Legalize a SETCC with given LHS and RHS and condition code CC on the current /// target. /// /// If the SETCC has been legalized using AND / OR, then the legalized node /// will be stored in LHS. RHS and CC will be set to SDValue(). NeedInvert /// will be set to false. /// /// If the SETCC has been legalized by using getSetCCSwappedOperands(), /// then the values of LHS and RHS will be swapped, CC will be set to the /// new condition, and NeedInvert will be set to false. /// /// If the SETCC has been legalized using the inverse condcode, then LHS and /// RHS will be unchanged, CC will set to the inverted condcode, and NeedInvert /// will be set to true. The caller must invert the result of the SETCC with /// SelectionDAG::getLogicalNOT() or take equivalent action to swap the effect /// of a true/false result. /// /// \returns true if the SetCC has been legalized, false if it hasn't. bool SelectionDAGLegalize::LegalizeSetCCCondCode(EVT VT, SDValue &LHS, SDValue &RHS, SDValue &CC, bool &NeedInvert, SDLoc dl) { MVT OpVT = LHS.getSimpleValueType(); ISD::CondCode CCCode = cast(CC)->get(); NeedInvert = false; switch (TLI.getCondCodeAction(CCCode, OpVT)) { default: llvm_unreachable("Unknown condition code action!"); case TargetLowering::Legal: // Nothing to do. break; case TargetLowering::Expand: { ISD::CondCode InvCC = ISD::getSetCCSwappedOperands(CCCode); if (TLI.isCondCodeLegal(InvCC, OpVT)) { std::swap(LHS, RHS); CC = DAG.getCondCode(InvCC); return true; } ISD::CondCode CC1 = ISD::SETCC_INVALID, CC2 = ISD::SETCC_INVALID; unsigned Opc = 0; switch (CCCode) { default: llvm_unreachable("Don't know how to expand this condition!"); case ISD::SETO: assert(TLI.getCondCodeAction(ISD::SETOEQ, OpVT) == TargetLowering::Legal && "If SETO is expanded, SETOEQ must be legal!"); CC1 = ISD::SETOEQ; CC2 = ISD::SETOEQ; Opc = ISD::AND; break; case ISD::SETUO: assert(TLI.getCondCodeAction(ISD::SETUNE, OpVT) == TargetLowering::Legal && "If SETUO is expanded, SETUNE must be legal!"); CC1 = ISD::SETUNE; CC2 = ISD::SETUNE; Opc = ISD::OR; break; case ISD::SETOEQ: case ISD::SETOGT: case ISD::SETOGE: case ISD::SETOLT: case ISD::SETOLE: case ISD::SETONE: case ISD::SETUEQ: case ISD::SETUNE: case ISD::SETUGT: case ISD::SETUGE: case ISD::SETULT: case ISD::SETULE: // If we are floating point, assign and break, otherwise fall through. if (!OpVT.isInteger()) { // We can use the 4th bit to tell if we are the unordered // or ordered version of the opcode. CC2 = ((unsigned)CCCode & 0x8U) ? ISD::SETUO : ISD::SETO; Opc = ((unsigned)CCCode & 0x8U) ? ISD::OR : ISD::AND; CC1 = (ISD::CondCode)(((int)CCCode & 0x7) | 0x10); break; } // Fallthrough if we are unsigned integer. case ISD::SETLE: case ISD::SETGT: case ISD::SETGE: case ISD::SETLT: // We only support using the inverted operation, which is computed above // and not a different manner of supporting expanding these cases. llvm_unreachable("Don't know how to expand this condition!"); case ISD::SETNE: case ISD::SETEQ: // Try inverting the result of the inverse condition. InvCC = CCCode == ISD::SETEQ ? ISD::SETNE : ISD::SETEQ; if (TLI.isCondCodeLegal(InvCC, OpVT)) { CC = DAG.getCondCode(InvCC); NeedInvert = true; return true; } // If inverting the condition didn't work then we have no means to expand // the condition. llvm_unreachable("Don't know how to expand this condition!"); } SDValue SetCC1, SetCC2; if (CCCode != ISD::SETO && CCCode != ISD::SETUO) { // If we aren't the ordered or unorder operation, // then the pattern is (LHS CC1 RHS) Opc (LHS CC2 RHS). SetCC1 = DAG.getSetCC(dl, VT, LHS, RHS, CC1); SetCC2 = DAG.getSetCC(dl, VT, LHS, RHS, CC2); } else { // Otherwise, the pattern is (LHS CC1 LHS) Opc (RHS CC2 RHS) SetCC1 = DAG.getSetCC(dl, VT, LHS, LHS, CC1); SetCC2 = DAG.getSetCC(dl, VT, RHS, RHS, CC2); } LHS = DAG.getNode(Opc, dl, VT, SetCC1, SetCC2); RHS = SDValue(); CC = SDValue(); return true; } } return false; } /// Emit a store/load combination to the stack. This stores /// SrcOp to a stack slot of type SlotVT, truncating it if needed. It then does /// a load from the stack slot to DestVT, extending it if needed. /// The resultant code need not be legal. SDValue SelectionDAGLegalize::EmitStackConvert(SDValue SrcOp, EVT SlotVT, EVT DestVT, SDLoc dl) { // Create the stack frame object. unsigned SrcAlign = DAG.getDataLayout().getPrefTypeAlignment( SrcOp.getValueType().getTypeForEVT(*DAG.getContext())); SDValue FIPtr = DAG.CreateStackTemporary(SlotVT, SrcAlign); FrameIndexSDNode *StackPtrFI = cast(FIPtr); int SPFI = StackPtrFI->getIndex(); MachinePointerInfo PtrInfo = MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), SPFI); unsigned SrcSize = SrcOp.getValueType().getSizeInBits(); unsigned SlotSize = SlotVT.getSizeInBits(); unsigned DestSize = DestVT.getSizeInBits(); Type *DestType = DestVT.getTypeForEVT(*DAG.getContext()); unsigned DestAlign = DAG.getDataLayout().getPrefTypeAlignment(DestType); // Emit a store to the stack slot. Use a truncstore if the input value is // later than DestVT. SDValue Store; if (SrcSize > SlotSize) Store = DAG.getTruncStore(DAG.getEntryNode(), dl, SrcOp, FIPtr, PtrInfo, SlotVT, false, false, SrcAlign); else { assert(SrcSize == SlotSize && "Invalid store"); Store = DAG.getStore(DAG.getEntryNode(), dl, SrcOp, FIPtr, PtrInfo, false, false, SrcAlign); } // Result is a load from the stack slot. if (SlotSize == DestSize) return DAG.getLoad(DestVT, dl, Store, FIPtr, PtrInfo, false, false, false, DestAlign); assert(SlotSize < DestSize && "Unknown extension!"); return DAG.getExtLoad(ISD::EXTLOAD, dl, DestVT, Store, FIPtr, PtrInfo, SlotVT, false, false, false, DestAlign); } SDValue SelectionDAGLegalize::ExpandSCALAR_TO_VECTOR(SDNode *Node) { SDLoc dl(Node); // Create a vector sized/aligned stack slot, store the value to element #0, // then load the whole vector back out. SDValue StackPtr = DAG.CreateStackTemporary(Node->getValueType(0)); FrameIndexSDNode *StackPtrFI = cast(StackPtr); int SPFI = StackPtrFI->getIndex(); SDValue Ch = DAG.getTruncStore( DAG.getEntryNode(), dl, Node->getOperand(0), StackPtr, MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), SPFI), Node->getValueType(0).getVectorElementType(), false, false, 0); return DAG.getLoad( Node->getValueType(0), dl, Ch, StackPtr, MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), SPFI), false, false, false, 0); } static bool ExpandBVWithShuffles(SDNode *Node, SelectionDAG &DAG, const TargetLowering &TLI, SDValue &Res) { unsigned NumElems = Node->getNumOperands(); SDLoc dl(Node); EVT VT = Node->getValueType(0); // Try to group the scalars into pairs, shuffle the pairs together, then // shuffle the pairs of pairs together, etc. until the vector has // been built. This will work only if all of the necessary shuffle masks // are legal. // We do this in two phases; first to check the legality of the shuffles, // and next, assuming that all shuffles are legal, to create the new nodes. for (int Phase = 0; Phase < 2; ++Phase) { SmallVector >, 16> IntermedVals, NewIntermedVals; for (unsigned i = 0; i < NumElems; ++i) { SDValue V = Node->getOperand(i); if (V.getOpcode() == ISD::UNDEF) continue; SDValue Vec; if (Phase) Vec = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, VT, V); IntermedVals.push_back(std::make_pair(Vec, SmallVector(1, i))); } while (IntermedVals.size() > 2) { NewIntermedVals.clear(); for (unsigned i = 0, e = (IntermedVals.size() & ~1u); i < e; i += 2) { // This vector and the next vector are shuffled together (simply to // append the one to the other). SmallVector ShuffleVec(NumElems, -1); SmallVector FinalIndices; FinalIndices.reserve(IntermedVals[i].second.size() + IntermedVals[i+1].second.size()); int k = 0; for (unsigned j = 0, f = IntermedVals[i].second.size(); j != f; ++j, ++k) { ShuffleVec[k] = j; FinalIndices.push_back(IntermedVals[i].second[j]); } for (unsigned j = 0, f = IntermedVals[i+1].second.size(); j != f; ++j, ++k) { ShuffleVec[k] = NumElems + j; FinalIndices.push_back(IntermedVals[i+1].second[j]); } SDValue Shuffle; if (Phase) Shuffle = DAG.getVectorShuffle(VT, dl, IntermedVals[i].first, IntermedVals[i+1].first, ShuffleVec.data()); else if (!TLI.isShuffleMaskLegal(ShuffleVec, VT)) return false; NewIntermedVals.push_back( std::make_pair(Shuffle, std::move(FinalIndices))); } // If we had an odd number of defined values, then append the last // element to the array of new vectors. if ((IntermedVals.size() & 1) != 0) NewIntermedVals.push_back(IntermedVals.back()); IntermedVals.swap(NewIntermedVals); } assert(IntermedVals.size() <= 2 && IntermedVals.size() > 0 && "Invalid number of intermediate vectors"); SDValue Vec1 = IntermedVals[0].first; SDValue Vec2; if (IntermedVals.size() > 1) Vec2 = IntermedVals[1].first; else if (Phase) Vec2 = DAG.getUNDEF(VT); SmallVector ShuffleVec(NumElems, -1); for (unsigned i = 0, e = IntermedVals[0].second.size(); i != e; ++i) ShuffleVec[IntermedVals[0].second[i]] = i; for (unsigned i = 0, e = IntermedVals[1].second.size(); i != e; ++i) ShuffleVec[IntermedVals[1].second[i]] = NumElems + i; if (Phase) Res = DAG.getVectorShuffle(VT, dl, Vec1, Vec2, ShuffleVec.data()); else if (!TLI.isShuffleMaskLegal(ShuffleVec, VT)) return false; } return true; } /// Expand a BUILD_VECTOR node on targets that don't /// support the operation, but do support the resultant vector type. SDValue SelectionDAGLegalize::ExpandBUILD_VECTOR(SDNode *Node) { unsigned NumElems = Node->getNumOperands(); SDValue Value1, Value2; SDLoc dl(Node); EVT VT = Node->getValueType(0); EVT OpVT = Node->getOperand(0).getValueType(); EVT EltVT = VT.getVectorElementType(); // If the only non-undef value is the low element, turn this into a // SCALAR_TO_VECTOR node. If this is { X, X, X, X }, determine X. bool isOnlyLowElement = true; bool MoreThanTwoValues = false; bool isConstant = true; for (unsigned i = 0; i < NumElems; ++i) { SDValue V = Node->getOperand(i); if (V.getOpcode() == ISD::UNDEF) continue; if (i > 0) isOnlyLowElement = false; if (!isa(V) && !isa(V)) isConstant = false; if (!Value1.getNode()) { Value1 = V; } else if (!Value2.getNode()) { if (V != Value1) Value2 = V; } else if (V != Value1 && V != Value2) { MoreThanTwoValues = true; } } if (!Value1.getNode()) return DAG.getUNDEF(VT); if (isOnlyLowElement) return DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, VT, Node->getOperand(0)); // If all elements are constants, create a load from the constant pool. if (isConstant) { SmallVector CV; for (unsigned i = 0, e = NumElems; i != e; ++i) { if (ConstantFPSDNode *V = dyn_cast(Node->getOperand(i))) { CV.push_back(const_cast(V->getConstantFPValue())); } else if (ConstantSDNode *V = dyn_cast(Node->getOperand(i))) { if (OpVT==EltVT) CV.push_back(const_cast(V->getConstantIntValue())); else { // If OpVT and EltVT don't match, EltVT is not legal and the // element values have been promoted/truncated earlier. Undo this; // we don't want a v16i8 to become a v16i32 for example. const ConstantInt *CI = V->getConstantIntValue(); CV.push_back(ConstantInt::get(EltVT.getTypeForEVT(*DAG.getContext()), CI->getZExtValue())); } } else { assert(Node->getOperand(i).getOpcode() == ISD::UNDEF); Type *OpNTy = EltVT.getTypeForEVT(*DAG.getContext()); CV.push_back(UndefValue::get(OpNTy)); } } Constant *CP = ConstantVector::get(CV); SDValue CPIdx = DAG.getConstantPool(CP, TLI.getPointerTy(DAG.getDataLayout())); unsigned Alignment = cast(CPIdx)->getAlignment(); return DAG.getLoad( VT, dl, DAG.getEntryNode(), CPIdx, MachinePointerInfo::getConstantPool(DAG.getMachineFunction()), false, false, false, Alignment); } SmallSet DefinedValues; for (unsigned i = 0; i < NumElems; ++i) { if (Node->getOperand(i).getOpcode() == ISD::UNDEF) continue; DefinedValues.insert(Node->getOperand(i)); } if (TLI.shouldExpandBuildVectorWithShuffles(VT, DefinedValues.size())) { if (!MoreThanTwoValues) { SmallVector ShuffleVec(NumElems, -1); for (unsigned i = 0; i < NumElems; ++i) { SDValue V = Node->getOperand(i); if (V.getOpcode() == ISD::UNDEF) continue; ShuffleVec[i] = V == Value1 ? 0 : NumElems; } if (TLI.isShuffleMaskLegal(ShuffleVec, Node->getValueType(0))) { // Get the splatted value into the low element of a vector register. SDValue Vec1 = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, VT, Value1); SDValue Vec2; if (Value2.getNode()) Vec2 = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, VT, Value2); else Vec2 = DAG.getUNDEF(VT); // Return shuffle(LowValVec, undef, <0,0,0,0>) return DAG.getVectorShuffle(VT, dl, Vec1, Vec2, ShuffleVec.data()); } } else { SDValue Res; if (ExpandBVWithShuffles(Node, DAG, TLI, Res)) return Res; } } // Otherwise, we can't handle this case efficiently. return ExpandVectorBuildThroughStack(Node); } // Expand a node into a call to a libcall. If the result value // does not fit into a register, return the lo part and set the hi part to the // by-reg argument. If it does fit into a single register, return the result // and leave the Hi part unset. SDValue SelectionDAGLegalize::ExpandLibCall(RTLIB::Libcall LC, SDNode *Node, bool isSigned) { TargetLowering::ArgListTy Args; TargetLowering::ArgListEntry Entry; for (const SDValue &Op : Node->op_values()) { EVT ArgVT = Op.getValueType(); Type *ArgTy = ArgVT.getTypeForEVT(*DAG.getContext()); Entry.Node = Op; Entry.Ty = ArgTy; Entry.isSExt = isSigned; Entry.isZExt = !isSigned; Args.push_back(Entry); } SDValue Callee = DAG.getExternalSymbol(TLI.getLibcallName(LC), TLI.getPointerTy(DAG.getDataLayout())); Type *RetTy = Node->getValueType(0).getTypeForEVT(*DAG.getContext()); // By default, the input chain to this libcall is the entry node of the // function. If the libcall is going to be emitted as a tail call then // TLI.isUsedByReturnOnly will change it to the right chain if the return // node which is being folded has a non-entry input chain. SDValue InChain = DAG.getEntryNode(); // isTailCall may be true since the callee does not reference caller stack // frame. Check if it's in the right position. SDValue TCChain = InChain; bool isTailCall = TLI.isInTailCallPosition(DAG, Node, TCChain); if (isTailCall) InChain = TCChain; TargetLowering::CallLoweringInfo CLI(DAG); CLI.setDebugLoc(SDLoc(Node)).setChain(InChain) .setCallee(TLI.getLibcallCallingConv(LC), RetTy, Callee, std::move(Args), 0) .setTailCall(isTailCall).setSExtResult(isSigned).setZExtResult(!isSigned); std::pair CallInfo = TLI.LowerCallTo(CLI); if (!CallInfo.second.getNode()) // It's a tailcall, return the chain (which is the DAG root). return DAG.getRoot(); return CallInfo.first; } /// Generate a libcall taking the given operands as arguments /// and returning a result of type RetVT. SDValue SelectionDAGLegalize::ExpandLibCall(RTLIB::Libcall LC, EVT RetVT, const SDValue *Ops, unsigned NumOps, bool isSigned, SDLoc dl) { TargetLowering::ArgListTy Args; Args.reserve(NumOps); TargetLowering::ArgListEntry Entry; for (unsigned i = 0; i != NumOps; ++i) { Entry.Node = Ops[i]; Entry.Ty = Entry.Node.getValueType().getTypeForEVT(*DAG.getContext()); Entry.isSExt = isSigned; Entry.isZExt = !isSigned; Args.push_back(Entry); } SDValue Callee = DAG.getExternalSymbol(TLI.getLibcallName(LC), TLI.getPointerTy(DAG.getDataLayout())); Type *RetTy = RetVT.getTypeForEVT(*DAG.getContext()); TargetLowering::CallLoweringInfo CLI(DAG); CLI.setDebugLoc(dl).setChain(DAG.getEntryNode()) .setCallee(TLI.getLibcallCallingConv(LC), RetTy, Callee, std::move(Args), 0) .setSExtResult(isSigned).setZExtResult(!isSigned); std::pair CallInfo = TLI.LowerCallTo(CLI); return CallInfo.first; } // Expand a node into a call to a libcall. Similar to // ExpandLibCall except that the first operand is the in-chain. std::pair SelectionDAGLegalize::ExpandChainLibCall(RTLIB::Libcall LC, SDNode *Node, bool isSigned) { SDValue InChain = Node->getOperand(0); TargetLowering::ArgListTy Args; TargetLowering::ArgListEntry Entry; for (unsigned i = 1, e = Node->getNumOperands(); i != e; ++i) { EVT ArgVT = Node->getOperand(i).getValueType(); Type *ArgTy = ArgVT.getTypeForEVT(*DAG.getContext()); Entry.Node = Node->getOperand(i); Entry.Ty = ArgTy; Entry.isSExt = isSigned; Entry.isZExt = !isSigned; Args.push_back(Entry); } SDValue Callee = DAG.getExternalSymbol(TLI.getLibcallName(LC), TLI.getPointerTy(DAG.getDataLayout())); Type *RetTy = Node->getValueType(0).getTypeForEVT(*DAG.getContext()); TargetLowering::CallLoweringInfo CLI(DAG); CLI.setDebugLoc(SDLoc(Node)).setChain(InChain) .setCallee(TLI.getLibcallCallingConv(LC), RetTy, Callee, std::move(Args), 0) .setSExtResult(isSigned).setZExtResult(!isSigned); std::pair CallInfo = TLI.LowerCallTo(CLI); return CallInfo; } SDValue SelectionDAGLegalize::ExpandFPLibCall(SDNode* Node, RTLIB::Libcall Call_F32, RTLIB::Libcall Call_F64, RTLIB::Libcall Call_F80, RTLIB::Libcall Call_F128, RTLIB::Libcall Call_PPCF128) { RTLIB::Libcall LC; switch (Node->getSimpleValueType(0).SimpleTy) { default: llvm_unreachable("Unexpected request for libcall!"); case MVT::f32: LC = Call_F32; break; case MVT::f64: LC = Call_F64; break; case MVT::f80: LC = Call_F80; break; case MVT::f128: LC = Call_F128; break; case MVT::ppcf128: LC = Call_PPCF128; break; } return ExpandLibCall(LC, Node, false); } SDValue SelectionDAGLegalize::ExpandIntLibCall(SDNode* Node, bool isSigned, RTLIB::Libcall Call_I8, RTLIB::Libcall Call_I16, RTLIB::Libcall Call_I32, RTLIB::Libcall Call_I64, RTLIB::Libcall Call_I128) { RTLIB::Libcall LC; switch (Node->getSimpleValueType(0).SimpleTy) { default: llvm_unreachable("Unexpected request for libcall!"); case MVT::i8: LC = Call_I8; break; case MVT::i16: LC = Call_I16; break; case MVT::i32: LC = Call_I32; break; case MVT::i64: LC = Call_I64; break; case MVT::i128: LC = Call_I128; break; } return ExpandLibCall(LC, Node, isSigned); } /// Issue libcalls to __{u}divmod to compute div / rem pairs. void SelectionDAGLegalize::ExpandDivRemLibCall(SDNode *Node, SmallVectorImpl &Results) { unsigned Opcode = Node->getOpcode(); bool isSigned = Opcode == ISD::SDIVREM; RTLIB::Libcall LC; switch (Node->getSimpleValueType(0).SimpleTy) { default: llvm_unreachable("Unexpected request for libcall!"); case MVT::i8: LC= isSigned ? RTLIB::SDIVREM_I8 : RTLIB::UDIVREM_I8; break; case MVT::i16: LC= isSigned ? RTLIB::SDIVREM_I16 : RTLIB::UDIVREM_I16; break; case MVT::i32: LC= isSigned ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32; break; case MVT::i64: LC= isSigned ? RTLIB::SDIVREM_I64 : RTLIB::UDIVREM_I64; break; case MVT::i128: LC= isSigned ? RTLIB::SDIVREM_I128:RTLIB::UDIVREM_I128; break; } // The input chain to this libcall is the entry node of the function. // Legalizing the call will automatically add the previous call to the // dependence. SDValue InChain = DAG.getEntryNode(); EVT RetVT = Node->getValueType(0); Type *RetTy = RetVT.getTypeForEVT(*DAG.getContext()); TargetLowering::ArgListTy Args; TargetLowering::ArgListEntry Entry; for (const SDValue &Op : Node->op_values()) { EVT ArgVT = Op.getValueType(); Type *ArgTy = ArgVT.getTypeForEVT(*DAG.getContext()); Entry.Node = Op; Entry.Ty = ArgTy; Entry.isSExt = isSigned; Entry.isZExt = !isSigned; Args.push_back(Entry); } // Also pass the return address of the remainder. SDValue FIPtr = DAG.CreateStackTemporary(RetVT); Entry.Node = FIPtr; Entry.Ty = RetTy->getPointerTo(); Entry.isSExt = isSigned; Entry.isZExt = !isSigned; Args.push_back(Entry); SDValue Callee = DAG.getExternalSymbol(TLI.getLibcallName(LC), TLI.getPointerTy(DAG.getDataLayout())); SDLoc dl(Node); TargetLowering::CallLoweringInfo CLI(DAG); CLI.setDebugLoc(dl).setChain(InChain) .setCallee(TLI.getLibcallCallingConv(LC), RetTy, Callee, std::move(Args), 0) .setSExtResult(isSigned).setZExtResult(!isSigned); std::pair CallInfo = TLI.LowerCallTo(CLI); // Remainder is loaded back from the stack frame. SDValue Rem = DAG.getLoad(RetVT, dl, CallInfo.second, FIPtr, MachinePointerInfo(), false, false, false, 0); Results.push_back(CallInfo.first); Results.push_back(Rem); } /// Return true if sincos libcall is available. static bool isSinCosLibcallAvailable(SDNode *Node, const TargetLowering &TLI) { RTLIB::Libcall LC; switch (Node->getSimpleValueType(0).SimpleTy) { default: llvm_unreachable("Unexpected request for libcall!"); case MVT::f32: LC = RTLIB::SINCOS_F32; break; case MVT::f64: LC = RTLIB::SINCOS_F64; break; case MVT::f80: LC = RTLIB::SINCOS_F80; break; case MVT::f128: LC = RTLIB::SINCOS_F128; break; case MVT::ppcf128: LC = RTLIB::SINCOS_PPCF128; break; } return TLI.getLibcallName(LC) != nullptr; } /// Return true if sincos libcall is available and can be used to combine sin /// and cos. static bool canCombineSinCosLibcall(SDNode *Node, const TargetLowering &TLI, const TargetMachine &TM) { if (!isSinCosLibcallAvailable(Node, TLI)) return false; // GNU sin/cos functions set errno while sincos does not. Therefore // combining sin and cos is only safe if unsafe-fpmath is enabled. bool isGNU = Triple(TM.getTargetTriple()).getEnvironment() == Triple::GNU; if (isGNU && !TM.Options.UnsafeFPMath) return false; return true; } /// Only issue sincos libcall if both sin and cos are needed. static bool useSinCos(SDNode *Node) { unsigned OtherOpcode = Node->getOpcode() == ISD::FSIN ? ISD::FCOS : ISD::FSIN; SDValue Op0 = Node->getOperand(0); for (SDNode::use_iterator UI = Op0.getNode()->use_begin(), UE = Op0.getNode()->use_end(); UI != UE; ++UI) { SDNode *User = *UI; if (User == Node) continue; // The other user might have been turned into sincos already. if (User->getOpcode() == OtherOpcode || User->getOpcode() == ISD::FSINCOS) return true; } return false; } /// Issue libcalls to sincos to compute sin / cos pairs. void SelectionDAGLegalize::ExpandSinCosLibCall(SDNode *Node, SmallVectorImpl &Results) { RTLIB::Libcall LC; switch (Node->getSimpleValueType(0).SimpleTy) { default: llvm_unreachable("Unexpected request for libcall!"); case MVT::f32: LC = RTLIB::SINCOS_F32; break; case MVT::f64: LC = RTLIB::SINCOS_F64; break; case MVT::f80: LC = RTLIB::SINCOS_F80; break; case MVT::f128: LC = RTLIB::SINCOS_F128; break; case MVT::ppcf128: LC = RTLIB::SINCOS_PPCF128; break; } // The input chain to this libcall is the entry node of the function. // Legalizing the call will automatically add the previous call to the // dependence. SDValue InChain = DAG.getEntryNode(); EVT RetVT = Node->getValueType(0); Type *RetTy = RetVT.getTypeForEVT(*DAG.getContext()); TargetLowering::ArgListTy Args; TargetLowering::ArgListEntry Entry; // Pass the argument. Entry.Node = Node->getOperand(0); Entry.Ty = RetTy; Entry.isSExt = false; Entry.isZExt = false; Args.push_back(Entry); // Pass the return address of sin. SDValue SinPtr = DAG.CreateStackTemporary(RetVT); Entry.Node = SinPtr; Entry.Ty = RetTy->getPointerTo(); Entry.isSExt = false; Entry.isZExt = false; Args.push_back(Entry); // Also pass the return address of the cos. SDValue CosPtr = DAG.CreateStackTemporary(RetVT); Entry.Node = CosPtr; Entry.Ty = RetTy->getPointerTo(); Entry.isSExt = false; Entry.isZExt = false; Args.push_back(Entry); SDValue Callee = DAG.getExternalSymbol(TLI.getLibcallName(LC), TLI.getPointerTy(DAG.getDataLayout())); SDLoc dl(Node); TargetLowering::CallLoweringInfo CLI(DAG); CLI.setDebugLoc(dl).setChain(InChain) .setCallee(TLI.getLibcallCallingConv(LC), Type::getVoidTy(*DAG.getContext()), Callee, std::move(Args), 0); std::pair CallInfo = TLI.LowerCallTo(CLI); Results.push_back(DAG.getLoad(RetVT, dl, CallInfo.second, SinPtr, MachinePointerInfo(), false, false, false, 0)); Results.push_back(DAG.getLoad(RetVT, dl, CallInfo.second, CosPtr, MachinePointerInfo(), false, false, false, 0)); } /// This function is responsible for legalizing a /// INT_TO_FP operation of the specified operand when the target requests that /// we expand it. At this point, we know that the result and operand types are /// legal for the target. SDValue SelectionDAGLegalize::ExpandLegalINT_TO_FP(bool isSigned, SDValue Op0, EVT DestVT, SDLoc dl) { // TODO: Should any fast-math-flags be set for the created nodes? if (Op0.getValueType() == MVT::i32 && TLI.isTypeLegal(MVT::f64)) { // simple 32-bit [signed|unsigned] integer to float/double expansion // Get the stack frame index of a 8 byte buffer. SDValue StackSlot = DAG.CreateStackTemporary(MVT::f64); // word offset constant for Hi/Lo address computation SDValue WordOff = DAG.getConstant(sizeof(int), dl, StackSlot.getValueType()); // set up Hi and Lo (into buffer) address based on endian SDValue Hi = StackSlot; SDValue Lo = DAG.getNode(ISD::ADD, dl, StackSlot.getValueType(), StackSlot, WordOff); if (DAG.getDataLayout().isLittleEndian()) std::swap(Hi, Lo); // if signed map to unsigned space SDValue Op0Mapped; if (isSigned) { // constant used to invert sign bit (signed to unsigned mapping) SDValue SignBit = DAG.getConstant(0x80000000u, dl, MVT::i32); Op0Mapped = DAG.getNode(ISD::XOR, dl, MVT::i32, Op0, SignBit); } else { Op0Mapped = Op0; } // store the lo of the constructed double - based on integer input SDValue Store1 = DAG.getStore(DAG.getEntryNode(), dl, Op0Mapped, Lo, MachinePointerInfo(), false, false, 0); // initial hi portion of constructed double SDValue InitialHi = DAG.getConstant(0x43300000u, dl, MVT::i32); // store the hi of the constructed double - biased exponent SDValue Store2 = DAG.getStore(Store1, dl, InitialHi, Hi, MachinePointerInfo(), false, false, 0); // load the constructed double SDValue Load = DAG.getLoad(MVT::f64, dl, Store2, StackSlot, MachinePointerInfo(), false, false, false, 0); // FP constant to bias correct the final result SDValue Bias = DAG.getConstantFP(isSigned ? BitsToDouble(0x4330000080000000ULL) : BitsToDouble(0x4330000000000000ULL), dl, MVT::f64); // subtract the bias SDValue Sub = DAG.getNode(ISD::FSUB, dl, MVT::f64, Load, Bias); // final result SDValue Result; // handle final rounding if (DestVT == MVT::f64) { // do nothing Result = Sub; } else if (DestVT.bitsLT(MVT::f64)) { Result = DAG.getNode(ISD::FP_ROUND, dl, DestVT, Sub, DAG.getIntPtrConstant(0, dl)); } else if (DestVT.bitsGT(MVT::f64)) { Result = DAG.getNode(ISD::FP_EXTEND, dl, DestVT, Sub); } return Result; } assert(!isSigned && "Legalize cannot Expand SINT_TO_FP for i64 yet"); // Code below here assumes !isSigned without checking again. // Implementation of unsigned i64 to f64 following the algorithm in // __floatundidf in compiler_rt. This implementation has the advantage // of performing rounding correctly, both in the default rounding mode // and in all alternate rounding modes. // TODO: Generalize this for use with other types. if (Op0.getValueType() == MVT::i64 && DestVT == MVT::f64) { SDValue TwoP52 = DAG.getConstant(UINT64_C(0x4330000000000000), dl, MVT::i64); SDValue TwoP84PlusTwoP52 = DAG.getConstantFP(BitsToDouble(UINT64_C(0x4530000000100000)), dl, MVT::f64); SDValue TwoP84 = DAG.getConstant(UINT64_C(0x4530000000000000), dl, MVT::i64); SDValue Lo = DAG.getZeroExtendInReg(Op0, dl, MVT::i32); SDValue Hi = DAG.getNode(ISD::SRL, dl, MVT::i64, Op0, DAG.getConstant(32, dl, MVT::i64)); SDValue LoOr = DAG.getNode(ISD::OR, dl, MVT::i64, Lo, TwoP52); SDValue HiOr = DAG.getNode(ISD::OR, dl, MVT::i64, Hi, TwoP84); SDValue LoFlt = DAG.getNode(ISD::BITCAST, dl, MVT::f64, LoOr); SDValue HiFlt = DAG.getNode(ISD::BITCAST, dl, MVT::f64, HiOr); SDValue HiSub = DAG.getNode(ISD::FSUB, dl, MVT::f64, HiFlt, TwoP84PlusTwoP52); return DAG.getNode(ISD::FADD, dl, MVT::f64, LoFlt, HiSub); } // Implementation of unsigned i64 to f32. // TODO: Generalize this for use with other types. if (Op0.getValueType() == MVT::i64 && DestVT == MVT::f32) { // For unsigned conversions, convert them to signed conversions using the // algorithm from the x86_64 __floatundidf in compiler_rt. if (!isSigned) { SDValue Fast = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::f32, Op0); SDValue ShiftConst = DAG.getConstant( 1, dl, TLI.getShiftAmountTy(Op0.getValueType(), DAG.getDataLayout())); SDValue Shr = DAG.getNode(ISD::SRL, dl, MVT::i64, Op0, ShiftConst); SDValue AndConst = DAG.getConstant(1, dl, MVT::i64); SDValue And = DAG.getNode(ISD::AND, dl, MVT::i64, Op0, AndConst); SDValue Or = DAG.getNode(ISD::OR, dl, MVT::i64, And, Shr); SDValue SignCvt = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::f32, Or); SDValue Slow = DAG.getNode(ISD::FADD, dl, MVT::f32, SignCvt, SignCvt); // TODO: This really should be implemented using a branch rather than a // select. We happen to get lucky and machinesink does the right // thing most of the time. This would be a good candidate for a //pseudo-op, or, even better, for whole-function isel. SDValue SignBitTest = DAG.getSetCC(dl, getSetCCResultType(MVT::i64), Op0, DAG.getConstant(0, dl, MVT::i64), ISD::SETLT); return DAG.getSelect(dl, MVT::f32, SignBitTest, Slow, Fast); } // Otherwise, implement the fully general conversion. SDValue And = DAG.getNode(ISD::AND, dl, MVT::i64, Op0, DAG.getConstant(UINT64_C(0xfffffffffffff800), dl, MVT::i64)); SDValue Or = DAG.getNode(ISD::OR, dl, MVT::i64, And, DAG.getConstant(UINT64_C(0x800), dl, MVT::i64)); SDValue And2 = DAG.getNode(ISD::AND, dl, MVT::i64, Op0, DAG.getConstant(UINT64_C(0x7ff), dl, MVT::i64)); SDValue Ne = DAG.getSetCC(dl, getSetCCResultType(MVT::i64), And2, DAG.getConstant(UINT64_C(0), dl, MVT::i64), ISD::SETNE); SDValue Sel = DAG.getSelect(dl, MVT::i64, Ne, Or, Op0); SDValue Ge = DAG.getSetCC(dl, getSetCCResultType(MVT::i64), Op0, DAG.getConstant(UINT64_C(0x0020000000000000), dl, MVT::i64), ISD::SETUGE); SDValue Sel2 = DAG.getSelect(dl, MVT::i64, Ge, Sel, Op0); EVT SHVT = TLI.getShiftAmountTy(Sel2.getValueType(), DAG.getDataLayout()); SDValue Sh = DAG.getNode(ISD::SRL, dl, MVT::i64, Sel2, DAG.getConstant(32, dl, SHVT)); SDValue Trunc = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Sh); SDValue Fcvt = DAG.getNode(ISD::UINT_TO_FP, dl, MVT::f64, Trunc); SDValue TwoP32 = DAG.getConstantFP(BitsToDouble(UINT64_C(0x41f0000000000000)), dl, MVT::f64); SDValue Fmul = DAG.getNode(ISD::FMUL, dl, MVT::f64, TwoP32, Fcvt); SDValue Lo = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Sel2); SDValue Fcvt2 = DAG.getNode(ISD::UINT_TO_FP, dl, MVT::f64, Lo); SDValue Fadd = DAG.getNode(ISD::FADD, dl, MVT::f64, Fmul, Fcvt2); return DAG.getNode(ISD::FP_ROUND, dl, MVT::f32, Fadd, DAG.getIntPtrConstant(0, dl)); } SDValue Tmp1 = DAG.getNode(ISD::SINT_TO_FP, dl, DestVT, Op0); SDValue SignSet = DAG.getSetCC(dl, getSetCCResultType(Op0.getValueType()), Op0, DAG.getConstant(0, dl, Op0.getValueType()), ISD::SETLT); SDValue Zero = DAG.getIntPtrConstant(0, dl), Four = DAG.getIntPtrConstant(4, dl); SDValue CstOffset = DAG.getSelect(dl, Zero.getValueType(), SignSet, Four, Zero); // If the sign bit of the integer is set, the large number will be treated // as a negative number. To counteract this, the dynamic code adds an // offset depending on the data type. uint64_t FF; switch (Op0.getSimpleValueType().SimpleTy) { default: llvm_unreachable("Unsupported integer type!"); case MVT::i8 : FF = 0x43800000ULL; break; // 2^8 (as a float) case MVT::i16: FF = 0x47800000ULL; break; // 2^16 (as a float) case MVT::i32: FF = 0x4F800000ULL; break; // 2^32 (as a float) case MVT::i64: FF = 0x5F800000ULL; break; // 2^64 (as a float) } if (DAG.getDataLayout().isLittleEndian()) FF <<= 32; Constant *FudgeFactor = ConstantInt::get( Type::getInt64Ty(*DAG.getContext()), FF); SDValue CPIdx = DAG.getConstantPool(FudgeFactor, TLI.getPointerTy(DAG.getDataLayout())); unsigned Alignment = cast(CPIdx)->getAlignment(); CPIdx = DAG.getNode(ISD::ADD, dl, CPIdx.getValueType(), CPIdx, CstOffset); Alignment = std::min(Alignment, 4u); SDValue FudgeInReg; if (DestVT == MVT::f32) FudgeInReg = DAG.getLoad( MVT::f32, dl, DAG.getEntryNode(), CPIdx, MachinePointerInfo::getConstantPool(DAG.getMachineFunction()), false, false, false, Alignment); else { SDValue Load = DAG.getExtLoad( ISD::EXTLOAD, dl, DestVT, DAG.getEntryNode(), CPIdx, MachinePointerInfo::getConstantPool(DAG.getMachineFunction()), MVT::f32, false, false, false, Alignment); HandleSDNode Handle(Load); LegalizeOp(Load.getNode()); FudgeInReg = Handle.getValue(); } return DAG.getNode(ISD::FADD, dl, DestVT, Tmp1, FudgeInReg); } /// This function is responsible for legalizing a /// *INT_TO_FP operation of the specified operand when the target requests that /// we promote it. At this point, we know that the result and operand types are /// legal for the target, and that there is a legal UINT_TO_FP or SINT_TO_FP /// operation that takes a larger input. SDValue SelectionDAGLegalize::PromoteLegalINT_TO_FP(SDValue LegalOp, EVT DestVT, bool isSigned, SDLoc dl) { // First step, figure out the appropriate *INT_TO_FP operation to use. EVT NewInTy = LegalOp.getValueType(); unsigned OpToUse = 0; // Scan for the appropriate larger type to use. while (1) { NewInTy = (MVT::SimpleValueType)(NewInTy.getSimpleVT().SimpleTy+1); assert(NewInTy.isInteger() && "Ran out of possibilities!"); // If the target supports SINT_TO_FP of this type, use it. if (TLI.isOperationLegalOrCustom(ISD::SINT_TO_FP, NewInTy)) { OpToUse = ISD::SINT_TO_FP; break; } if (isSigned) continue; // If the target supports UINT_TO_FP of this type, use it. if (TLI.isOperationLegalOrCustom(ISD::UINT_TO_FP, NewInTy)) { OpToUse = ISD::UINT_TO_FP; break; } // Otherwise, try a larger type. } // Okay, we found the operation and type to use. Zero extend our input to the // desired type then run the operation on it. return DAG.getNode(OpToUse, dl, DestVT, DAG.getNode(isSigned ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND, dl, NewInTy, LegalOp)); } /// This function is responsible for legalizing a /// FP_TO_*INT operation of the specified operand when the target requests that /// we promote it. At this point, we know that the result and operand types are /// legal for the target, and that there is a legal FP_TO_UINT or FP_TO_SINT /// operation that returns a larger result. SDValue SelectionDAGLegalize::PromoteLegalFP_TO_INT(SDValue LegalOp, EVT DestVT, bool isSigned, SDLoc dl) { // First step, figure out the appropriate FP_TO*INT operation to use. EVT NewOutTy = DestVT; unsigned OpToUse = 0; // Scan for the appropriate larger type to use. while (1) { NewOutTy = (MVT::SimpleValueType)(NewOutTy.getSimpleVT().SimpleTy+1); assert(NewOutTy.isInteger() && "Ran out of possibilities!"); // A larger signed type can hold all unsigned values of the requested type, // so using FP_TO_SINT is valid if (TLI.isOperationLegalOrCustom(ISD::FP_TO_SINT, NewOutTy)) { OpToUse = ISD::FP_TO_SINT; break; } // However, if the value may be < 0.0, we *must* use some FP_TO_SINT. if (!isSigned && TLI.isOperationLegalOrCustom(ISD::FP_TO_UINT, NewOutTy)) { OpToUse = ISD::FP_TO_UINT; break; } // Otherwise, try a larger type. } // Okay, we found the operation and type to use. SDValue Operation = DAG.getNode(OpToUse, dl, NewOutTy, LegalOp); // Truncate the result of the extended FP_TO_*INT operation to the desired // size. return DAG.getNode(ISD::TRUNCATE, dl, DestVT, Operation); } /// Open code the operations for BITREVERSE. SDValue SelectionDAGLegalize::ExpandBITREVERSE(SDValue Op, SDLoc dl) { EVT VT = Op.getValueType(); EVT SHVT = TLI.getShiftAmountTy(VT, DAG.getDataLayout()); unsigned Sz = VT.getScalarSizeInBits(); SDValue Tmp, Tmp2; Tmp = DAG.getConstant(0, dl, VT); for (unsigned I = 0, J = Sz-1; I < Sz; ++I, --J) { if (I < J) Tmp2 = DAG.getNode(ISD::SHL, dl, VT, Op, DAG.getConstant(J - I, dl, SHVT)); else Tmp2 = DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(I - J, dl, SHVT)); APInt Shift(Sz, 1); Shift = Shift.shl(J); Tmp2 = DAG.getNode(ISD::AND, dl, VT, Tmp2, DAG.getConstant(Shift, dl, VT)); Tmp = DAG.getNode(ISD::OR, dl, VT, Tmp, Tmp2); } return Tmp; } /// Open code the operations for BSWAP of the specified operation. SDValue SelectionDAGLegalize::ExpandBSWAP(SDValue Op, SDLoc dl) { EVT VT = Op.getValueType(); EVT SHVT = TLI.getShiftAmountTy(VT, DAG.getDataLayout()); SDValue Tmp1, Tmp2, Tmp3, Tmp4, Tmp5, Tmp6, Tmp7, Tmp8; switch (VT.getSimpleVT().SimpleTy) { default: llvm_unreachable("Unhandled Expand type in BSWAP!"); case MVT::i16: Tmp2 = DAG.getNode(ISD::SHL, dl, VT, Op, DAG.getConstant(8, dl, SHVT)); Tmp1 = DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(8, dl, SHVT)); return DAG.getNode(ISD::OR, dl, VT, Tmp1, Tmp2); case MVT::i32: Tmp4 = DAG.getNode(ISD::SHL, dl, VT, Op, DAG.getConstant(24, dl, SHVT)); Tmp3 = DAG.getNode(ISD::SHL, dl, VT, Op, DAG.getConstant(8, dl, SHVT)); Tmp2 = DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(8, dl, SHVT)); Tmp1 = DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(24, dl, SHVT)); Tmp3 = DAG.getNode(ISD::AND, dl, VT, Tmp3, DAG.getConstant(0xFF0000, dl, VT)); Tmp2 = DAG.getNode(ISD::AND, dl, VT, Tmp2, DAG.getConstant(0xFF00, dl, VT)); Tmp4 = DAG.getNode(ISD::OR, dl, VT, Tmp4, Tmp3); Tmp2 = DAG.getNode(ISD::OR, dl, VT, Tmp2, Tmp1); return DAG.getNode(ISD::OR, dl, VT, Tmp4, Tmp2); case MVT::i64: Tmp8 = DAG.getNode(ISD::SHL, dl, VT, Op, DAG.getConstant(56, dl, SHVT)); Tmp7 = DAG.getNode(ISD::SHL, dl, VT, Op, DAG.getConstant(40, dl, SHVT)); Tmp6 = DAG.getNode(ISD::SHL, dl, VT, Op, DAG.getConstant(24, dl, SHVT)); Tmp5 = DAG.getNode(ISD::SHL, dl, VT, Op, DAG.getConstant(8, dl, SHVT)); Tmp4 = DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(8, dl, SHVT)); Tmp3 = DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(24, dl, SHVT)); Tmp2 = DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(40, dl, SHVT)); Tmp1 = DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(56, dl, SHVT)); Tmp7 = DAG.getNode(ISD::AND, dl, VT, Tmp7, DAG.getConstant(255ULL<<48, dl, VT)); Tmp6 = DAG.getNode(ISD::AND, dl, VT, Tmp6, DAG.getConstant(255ULL<<40, dl, VT)); Tmp5 = DAG.getNode(ISD::AND, dl, VT, Tmp5, DAG.getConstant(255ULL<<32, dl, VT)); Tmp4 = DAG.getNode(ISD::AND, dl, VT, Tmp4, DAG.getConstant(255ULL<<24, dl, VT)); Tmp3 = DAG.getNode(ISD::AND, dl, VT, Tmp3, DAG.getConstant(255ULL<<16, dl, VT)); Tmp2 = DAG.getNode(ISD::AND, dl, VT, Tmp2, DAG.getConstant(255ULL<<8 , dl, VT)); Tmp8 = DAG.getNode(ISD::OR, dl, VT, Tmp8, Tmp7); Tmp6 = DAG.getNode(ISD::OR, dl, VT, Tmp6, Tmp5); Tmp4 = DAG.getNode(ISD::OR, dl, VT, Tmp4, Tmp3); Tmp2 = DAG.getNode(ISD::OR, dl, VT, Tmp2, Tmp1); Tmp8 = DAG.getNode(ISD::OR, dl, VT, Tmp8, Tmp6); Tmp4 = DAG.getNode(ISD::OR, dl, VT, Tmp4, Tmp2); return DAG.getNode(ISD::OR, dl, VT, Tmp8, Tmp4); } } /// Expand the specified bitcount instruction into operations. SDValue SelectionDAGLegalize::ExpandBitCount(unsigned Opc, SDValue Op, SDLoc dl) { switch (Opc) { default: llvm_unreachable("Cannot expand this yet!"); case ISD::CTPOP: { EVT VT = Op.getValueType(); EVT ShVT = TLI.getShiftAmountTy(VT, DAG.getDataLayout()); unsigned Len = VT.getSizeInBits(); assert(VT.isInteger() && Len <= 128 && Len % 8 == 0 && "CTPOP not implemented for this type."); // This is the "best" algorithm from // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel SDValue Mask55 = DAG.getConstant(APInt::getSplat(Len, APInt(8, 0x55)), dl, VT); SDValue Mask33 = DAG.getConstant(APInt::getSplat(Len, APInt(8, 0x33)), dl, VT); SDValue Mask0F = DAG.getConstant(APInt::getSplat(Len, APInt(8, 0x0F)), dl, VT); SDValue Mask01 = DAG.getConstant(APInt::getSplat(Len, APInt(8, 0x01)), dl, VT); // v = v - ((v >> 1) & 0x55555555...) Op = DAG.getNode(ISD::SUB, dl, VT, Op, DAG.getNode(ISD::AND, dl, VT, DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(1, dl, ShVT)), Mask55)); // v = (v & 0x33333333...) + ((v >> 2) & 0x33333333...) Op = DAG.getNode(ISD::ADD, dl, VT, DAG.getNode(ISD::AND, dl, VT, Op, Mask33), DAG.getNode(ISD::AND, dl, VT, DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(2, dl, ShVT)), Mask33)); // v = (v + (v >> 4)) & 0x0F0F0F0F... Op = DAG.getNode(ISD::AND, dl, VT, DAG.getNode(ISD::ADD, dl, VT, Op, DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(4, dl, ShVT))), Mask0F); // v = (v * 0x01010101...) >> (Len - 8) Op = DAG.getNode(ISD::SRL, dl, VT, DAG.getNode(ISD::MUL, dl, VT, Op, Mask01), DAG.getConstant(Len - 8, dl, ShVT)); return Op; } case ISD::CTLZ_ZERO_UNDEF: // This trivially expands to CTLZ. return DAG.getNode(ISD::CTLZ, dl, Op.getValueType(), Op); case ISD::CTLZ: { EVT VT = Op.getValueType(); unsigned len = VT.getSizeInBits(); if (TLI.isOperationLegalOrCustom(ISD::CTLZ_ZERO_UNDEF, VT)) { EVT SetCCVT = getSetCCResultType(VT); SDValue CTLZ = DAG.getNode(ISD::CTLZ_ZERO_UNDEF, dl, VT, Op); SDValue Zero = DAG.getConstant(0, dl, VT); SDValue SrcIsZero = DAG.getSetCC(dl, SetCCVT, Op, Zero, ISD::SETEQ); return DAG.getNode(ISD::SELECT, dl, VT, SrcIsZero, DAG.getConstant(len, dl, VT), CTLZ); } // for now, we do this: // x = x | (x >> 1); // x = x | (x >> 2); // ... // x = x | (x >>16); // x = x | (x >>32); // for 64-bit input // return popcount(~x); // // Ref: "Hacker's Delight" by Henry Warren EVT ShVT = TLI.getShiftAmountTy(VT, DAG.getDataLayout()); for (unsigned i = 0; (1U << i) <= (len / 2); ++i) { SDValue Tmp3 = DAG.getConstant(1ULL << i, dl, ShVT); Op = DAG.getNode(ISD::OR, dl, VT, Op, DAG.getNode(ISD::SRL, dl, VT, Op, Tmp3)); } Op = DAG.getNOT(dl, Op, VT); return DAG.getNode(ISD::CTPOP, dl, VT, Op); } case ISD::CTTZ_ZERO_UNDEF: // This trivially expands to CTTZ. return DAG.getNode(ISD::CTTZ, dl, Op.getValueType(), Op); case ISD::CTTZ: { // for now, we use: { return popcount(~x & (x - 1)); } // unless the target has ctlz but not ctpop, in which case we use: // { return 32 - nlz(~x & (x-1)); } // Ref: "Hacker's Delight" by Henry Warren EVT VT = Op.getValueType(); SDValue Tmp3 = DAG.getNode(ISD::AND, dl, VT, DAG.getNOT(dl, Op, VT), DAG.getNode(ISD::SUB, dl, VT, Op, DAG.getConstant(1, dl, VT))); // If ISD::CTLZ is legal and CTPOP isn't, then do that instead. if (!TLI.isOperationLegalOrCustom(ISD::CTPOP, VT) && TLI.isOperationLegalOrCustom(ISD::CTLZ, VT)) return DAG.getNode(ISD::SUB, dl, VT, DAG.getConstant(VT.getSizeInBits(), dl, VT), DAG.getNode(ISD::CTLZ, dl, VT, Tmp3)); return DAG.getNode(ISD::CTPOP, dl, VT, Tmp3); } } } bool SelectionDAGLegalize::ExpandNode(SDNode *Node) { SmallVector Results; SDLoc dl(Node); SDValue Tmp1, Tmp2, Tmp3, Tmp4; bool NeedInvert; switch (Node->getOpcode()) { case ISD::CTPOP: case ISD::CTLZ: case ISD::CTLZ_ZERO_UNDEF: case ISD::CTTZ: case ISD::CTTZ_ZERO_UNDEF: Tmp1 = ExpandBitCount(Node->getOpcode(), Node->getOperand(0), dl); Results.push_back(Tmp1); break; case ISD::BITREVERSE: Results.push_back(ExpandBITREVERSE(Node->getOperand(0), dl)); break; case ISD::BSWAP: Results.push_back(ExpandBSWAP(Node->getOperand(0), dl)); break; case ISD::FRAMEADDR: case ISD::RETURNADDR: case ISD::FRAME_TO_ARGS_OFFSET: Results.push_back(DAG.getConstant(0, dl, Node->getValueType(0))); break; case ISD::FLT_ROUNDS_: Results.push_back(DAG.getConstant(1, dl, Node->getValueType(0))); break; case ISD::EH_RETURN: case ISD::EH_LABEL: case ISD::PREFETCH: case ISD::VAEND: case ISD::EH_SJLJ_LONGJMP: // If the target didn't expand these, there's nothing to do, so just // preserve the chain and be done. Results.push_back(Node->getOperand(0)); break; case ISD::READCYCLECOUNTER: // If the target didn't expand this, just return 'zero' and preserve the // chain. Results.append(Node->getNumValues() - 1, DAG.getConstant(0, dl, Node->getValueType(0))); Results.push_back(Node->getOperand(0)); break; case ISD::EH_SJLJ_SETJMP: // If the target didn't expand this, just return 'zero' and preserve the // chain. Results.push_back(DAG.getConstant(0, dl, MVT::i32)); Results.push_back(Node->getOperand(0)); break; case ISD::ATOMIC_LOAD: { // There is no libcall for atomic load; fake it with ATOMIC_CMP_SWAP. SDValue Zero = DAG.getConstant(0, dl, Node->getValueType(0)); SDVTList VTs = DAG.getVTList(Node->getValueType(0), MVT::Other); SDValue Swap = DAG.getAtomicCmpSwap( ISD::ATOMIC_CMP_SWAP, dl, cast(Node)->getMemoryVT(), VTs, Node->getOperand(0), Node->getOperand(1), Zero, Zero, cast(Node)->getMemOperand(), cast(Node)->getOrdering(), cast(Node)->getOrdering(), cast(Node)->getSynchScope()); Results.push_back(Swap.getValue(0)); Results.push_back(Swap.getValue(1)); break; } case ISD::ATOMIC_STORE: { // There is no libcall for atomic store; fake it with ATOMIC_SWAP. SDValue Swap = DAG.getAtomic(ISD::ATOMIC_SWAP, dl, cast(Node)->getMemoryVT(), Node->getOperand(0), Node->getOperand(1), Node->getOperand(2), cast(Node)->getMemOperand(), cast(Node)->getOrdering(), cast(Node)->getSynchScope()); Results.push_back(Swap.getValue(1)); break; } case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS: { // Expanding an ATOMIC_CMP_SWAP_WITH_SUCCESS produces an ATOMIC_CMP_SWAP and // splits out the success value as a comparison. Expanding the resulting // ATOMIC_CMP_SWAP will produce a libcall. SDVTList VTs = DAG.getVTList(Node->getValueType(0), MVT::Other); SDValue Res = DAG.getAtomicCmpSwap( ISD::ATOMIC_CMP_SWAP, dl, cast(Node)->getMemoryVT(), VTs, Node->getOperand(0), Node->getOperand(1), Node->getOperand(2), Node->getOperand(3), cast(Node)->getMemOperand(), cast(Node)->getSuccessOrdering(), cast(Node)->getFailureOrdering(), cast(Node)->getSynchScope()); SDValue Success = DAG.getSetCC(SDLoc(Node), Node->getValueType(1), Res, Node->getOperand(2), ISD::SETEQ); Results.push_back(Res.getValue(0)); Results.push_back(Success); Results.push_back(Res.getValue(1)); break; } case ISD::DYNAMIC_STACKALLOC: ExpandDYNAMIC_STACKALLOC(Node, Results); break; case ISD::MERGE_VALUES: for (unsigned i = 0; i < Node->getNumValues(); i++) Results.push_back(Node->getOperand(i)); break; case ISD::UNDEF: { EVT VT = Node->getValueType(0); if (VT.isInteger()) Results.push_back(DAG.getConstant(0, dl, VT)); else { assert(VT.isFloatingPoint() && "Unknown value type!"); Results.push_back(DAG.getConstantFP(0, dl, VT)); } break; } case ISD::FP_ROUND: case ISD::BITCAST: Tmp1 = EmitStackConvert(Node->getOperand(0), Node->getValueType(0), Node->getValueType(0), dl); Results.push_back(Tmp1); break; case ISD::FP_EXTEND: Tmp1 = EmitStackConvert(Node->getOperand(0), Node->getOperand(0).getValueType(), Node->getValueType(0), dl); Results.push_back(Tmp1); break; case ISD::SIGN_EXTEND_INREG: { // NOTE: we could fall back on load/store here too for targets without // SAR. However, it is doubtful that any exist. EVT ExtraVT = cast(Node->getOperand(1))->getVT(); EVT VT = Node->getValueType(0); EVT ShiftAmountTy = TLI.getShiftAmountTy(VT, DAG.getDataLayout()); if (VT.isVector()) ShiftAmountTy = VT; unsigned BitsDiff = VT.getScalarType().getSizeInBits() - ExtraVT.getScalarType().getSizeInBits(); SDValue ShiftCst = DAG.getConstant(BitsDiff, dl, ShiftAmountTy); Tmp1 = DAG.getNode(ISD::SHL, dl, Node->getValueType(0), Node->getOperand(0), ShiftCst); Tmp1 = DAG.getNode(ISD::SRA, dl, Node->getValueType(0), Tmp1, ShiftCst); Results.push_back(Tmp1); break; } case ISD::FP_ROUND_INREG: { // The only way we can lower this is to turn it into a TRUNCSTORE, // EXTLOAD pair, targeting a temporary location (a stack slot). // NOTE: there is a choice here between constantly creating new stack // slots and always reusing the same one. We currently always create // new ones, as reuse may inhibit scheduling. EVT ExtraVT = cast(Node->getOperand(1))->getVT(); Tmp1 = EmitStackConvert(Node->getOperand(0), ExtraVT, Node->getValueType(0), dl); Results.push_back(Tmp1); break; } case ISD::SINT_TO_FP: case ISD::UINT_TO_FP: Tmp1 = ExpandLegalINT_TO_FP(Node->getOpcode() == ISD::SINT_TO_FP, Node->getOperand(0), Node->getValueType(0), dl); Results.push_back(Tmp1); break; case ISD::FP_TO_SINT: if (TLI.expandFP_TO_SINT(Node, Tmp1, DAG)) Results.push_back(Tmp1); break; case ISD::FP_TO_UINT: { SDValue True, False; EVT VT = Node->getOperand(0).getValueType(); EVT NVT = Node->getValueType(0); APFloat apf(DAG.EVTToAPFloatSemantics(VT), APInt::getNullValue(VT.getSizeInBits())); APInt x = APInt::getSignBit(NVT.getSizeInBits()); (void)apf.convertFromAPInt(x, false, APFloat::rmNearestTiesToEven); Tmp1 = DAG.getConstantFP(apf, dl, VT); Tmp2 = DAG.getSetCC(dl, getSetCCResultType(VT), Node->getOperand(0), Tmp1, ISD::SETLT); True = DAG.getNode(ISD::FP_TO_SINT, dl, NVT, Node->getOperand(0)); // TODO: Should any fast-math-flags be set for the FSUB? False = DAG.getNode(ISD::FP_TO_SINT, dl, NVT, DAG.getNode(ISD::FSUB, dl, VT, Node->getOperand(0), Tmp1)); False = DAG.getNode(ISD::XOR, dl, NVT, False, DAG.getConstant(x, dl, NVT)); Tmp1 = DAG.getSelect(dl, NVT, Tmp2, True, False); Results.push_back(Tmp1); break; } case ISD::VAARG: Results.push_back(DAG.expandVAArg(Node)); Results.push_back(Results[0].getValue(1)); break; case ISD::VACOPY: Results.push_back(DAG.expandVACopy(Node)); break; case ISD::EXTRACT_VECTOR_ELT: if (Node->getOperand(0).getValueType().getVectorNumElements() == 1) // This must be an access of the only element. Return it. Tmp1 = DAG.getNode(ISD::BITCAST, dl, Node->getValueType(0), Node->getOperand(0)); else Tmp1 = ExpandExtractFromVectorThroughStack(SDValue(Node, 0)); Results.push_back(Tmp1); break; case ISD::EXTRACT_SUBVECTOR: Results.push_back(ExpandExtractFromVectorThroughStack(SDValue(Node, 0))); break; case ISD::INSERT_SUBVECTOR: Results.push_back(ExpandInsertToVectorThroughStack(SDValue(Node, 0))); break; case ISD::CONCAT_VECTORS: { Results.push_back(ExpandVectorBuildThroughStack(Node)); break; } case ISD::SCALAR_TO_VECTOR: Results.push_back(ExpandSCALAR_TO_VECTOR(Node)); break; case ISD::INSERT_VECTOR_ELT: Results.push_back(ExpandINSERT_VECTOR_ELT(Node->getOperand(0), Node->getOperand(1), Node->getOperand(2), dl)); break; case ISD::VECTOR_SHUFFLE: { SmallVector NewMask; ArrayRef Mask = cast(Node)->getMask(); EVT VT = Node->getValueType(0); EVT EltVT = VT.getVectorElementType(); SDValue Op0 = Node->getOperand(0); SDValue Op1 = Node->getOperand(1); if (!TLI.isTypeLegal(EltVT)) { EVT NewEltVT = TLI.getTypeToTransformTo(*DAG.getContext(), EltVT); // BUILD_VECTOR operands are allowed to be wider than the element type. // But if NewEltVT is smaller that EltVT the BUILD_VECTOR does not accept // it. if (NewEltVT.bitsLT(EltVT)) { // Convert shuffle node. // If original node was v4i64 and the new EltVT is i32, // cast operands to v8i32 and re-build the mask. // Calculate new VT, the size of the new VT should be equal to original. EVT NewVT = EVT::getVectorVT(*DAG.getContext(), NewEltVT, VT.getSizeInBits() / NewEltVT.getSizeInBits()); assert(NewVT.bitsEq(VT)); // cast operands to new VT Op0 = DAG.getNode(ISD::BITCAST, dl, NewVT, Op0); Op1 = DAG.getNode(ISD::BITCAST, dl, NewVT, Op1); // Convert the shuffle mask unsigned int factor = NewVT.getVectorNumElements()/VT.getVectorNumElements(); // EltVT gets smaller assert(factor > 0); for (unsigned i = 0; i < VT.getVectorNumElements(); ++i) { if (Mask[i] < 0) { for (unsigned fi = 0; fi < factor; ++fi) NewMask.push_back(Mask[i]); } else { for (unsigned fi = 0; fi < factor; ++fi) NewMask.push_back(Mask[i]*factor+fi); } } Mask = NewMask; VT = NewVT; } EltVT = NewEltVT; } unsigned NumElems = VT.getVectorNumElements(); SmallVector Ops; for (unsigned i = 0; i != NumElems; ++i) { if (Mask[i] < 0) { Ops.push_back(DAG.getUNDEF(EltVT)); continue; } unsigned Idx = Mask[i]; if (Idx < NumElems) Ops.push_back(DAG.getNode( ISD::EXTRACT_VECTOR_ELT, dl, EltVT, Op0, DAG.getConstant(Idx, dl, TLI.getVectorIdxTy(DAG.getDataLayout())))); else Ops.push_back(DAG.getNode( ISD::EXTRACT_VECTOR_ELT, dl, EltVT, Op1, DAG.getConstant(Idx - NumElems, dl, TLI.getVectorIdxTy(DAG.getDataLayout())))); } Tmp1 = DAG.getNode(ISD::BUILD_VECTOR, dl, VT, Ops); // We may have changed the BUILD_VECTOR type. Cast it back to the Node type. Tmp1 = DAG.getNode(ISD::BITCAST, dl, Node->getValueType(0), Tmp1); Results.push_back(Tmp1); break; } case ISD::EXTRACT_ELEMENT: { EVT OpTy = Node->getOperand(0).getValueType(); if (cast(Node->getOperand(1))->getZExtValue()) { // 1 -> Hi Tmp1 = DAG.getNode(ISD::SRL, dl, OpTy, Node->getOperand(0), DAG.getConstant(OpTy.getSizeInBits() / 2, dl, TLI.getShiftAmountTy( Node->getOperand(0).getValueType(), DAG.getDataLayout()))); Tmp1 = DAG.getNode(ISD::TRUNCATE, dl, Node->getValueType(0), Tmp1); } else { // 0 -> Lo Tmp1 = DAG.getNode(ISD::TRUNCATE, dl, Node->getValueType(0), Node->getOperand(0)); } Results.push_back(Tmp1); break; } case ISD::STACKSAVE: // Expand to CopyFromReg if the target set // StackPointerRegisterToSaveRestore. if (unsigned SP = TLI.getStackPointerRegisterToSaveRestore()) { Results.push_back(DAG.getCopyFromReg(Node->getOperand(0), dl, SP, Node->getValueType(0))); Results.push_back(Results[0].getValue(1)); } else { Results.push_back(DAG.getUNDEF(Node->getValueType(0))); Results.push_back(Node->getOperand(0)); } break; case ISD::STACKRESTORE: // Expand to CopyToReg if the target set // StackPointerRegisterToSaveRestore. if (unsigned SP = TLI.getStackPointerRegisterToSaveRestore()) { Results.push_back(DAG.getCopyToReg(Node->getOperand(0), dl, SP, Node->getOperand(1))); } else { Results.push_back(Node->getOperand(0)); } break; case ISD::GET_DYNAMIC_AREA_OFFSET: Results.push_back(DAG.getConstant(0, dl, Node->getValueType(0))); Results.push_back(Results[0].getValue(0)); break; case ISD::FCOPYSIGN: Results.push_back(ExpandFCOPYSIGN(Node)); break; case ISD::FNEG: // Expand Y = FNEG(X) -> Y = SUB -0.0, X Tmp1 = DAG.getConstantFP(-0.0, dl, Node->getValueType(0)); // TODO: If FNEG has fast-math-flags, propagate them to the FSUB. Tmp1 = DAG.getNode(ISD::FSUB, dl, Node->getValueType(0), Tmp1, Node->getOperand(0)); Results.push_back(Tmp1); break; case ISD::FABS: Results.push_back(ExpandFABS(Node)); break; case ISD::SMIN: case ISD::SMAX: case ISD::UMIN: case ISD::UMAX: { // Expand Y = MAX(A, B) -> Y = (A > B) ? A : B ISD::CondCode Pred; switch (Node->getOpcode()) { default: llvm_unreachable("How did we get here?"); case ISD::SMAX: Pred = ISD::SETGT; break; case ISD::SMIN: Pred = ISD::SETLT; break; case ISD::UMAX: Pred = ISD::SETUGT; break; case ISD::UMIN: Pred = ISD::SETULT; break; } Tmp1 = Node->getOperand(0); Tmp2 = Node->getOperand(1); Tmp1 = DAG.getSelectCC(dl, Tmp1, Tmp2, Tmp1, Tmp2, Pred); Results.push_back(Tmp1); break; } case ISD::FSIN: case ISD::FCOS: { EVT VT = Node->getValueType(0); // Turn fsin / fcos into ISD::FSINCOS node if there are a pair of fsin / // fcos which share the same operand and both are used. if ((TLI.isOperationLegalOrCustom(ISD::FSINCOS, VT) || canCombineSinCosLibcall(Node, TLI, TM)) && useSinCos(Node)) { SDVTList VTs = DAG.getVTList(VT, VT); Tmp1 = DAG.getNode(ISD::FSINCOS, dl, VTs, Node->getOperand(0)); if (Node->getOpcode() == ISD::FCOS) Tmp1 = Tmp1.getValue(1); Results.push_back(Tmp1); } break; } case ISD::FMAD: llvm_unreachable("Illegal fmad should never be formed"); case ISD::FP16_TO_FP: if (Node->getValueType(0) != MVT::f32) { // We can extend to types bigger than f32 in two steps without changing // the result. Since "f16 -> f32" is much more commonly available, give // CodeGen the option of emitting that before resorting to a libcall. SDValue Res = DAG.getNode(ISD::FP16_TO_FP, dl, MVT::f32, Node->getOperand(0)); Results.push_back( DAG.getNode(ISD::FP_EXTEND, dl, Node->getValueType(0), Res)); } break; case ISD::FP_TO_FP16: if (!TLI.useSoftFloat() && TM.Options.UnsafeFPMath) { SDValue Op = Node->getOperand(0); MVT SVT = Op.getSimpleValueType(); if ((SVT == MVT::f64 || SVT == MVT::f80) && TLI.isOperationLegalOrCustom(ISD::FP_TO_FP16, MVT::f32)) { // Under fastmath, we can expand this node into a fround followed by // a float-half conversion. SDValue FloatVal = DAG.getNode(ISD::FP_ROUND, dl, MVT::f32, Op, DAG.getIntPtrConstant(0, dl)); Results.push_back( DAG.getNode(ISD::FP_TO_FP16, dl, MVT::i16, FloatVal)); } } break; case ISD::ConstantFP: { ConstantFPSDNode *CFP = cast(Node); // Check to see if this FP immediate is already legal. // If this is a legal constant, turn it into a TargetConstantFP node. if (!TLI.isFPImmLegal(CFP->getValueAPF(), Node->getValueType(0))) Results.push_back(ExpandConstantFP(CFP, true)); break; } case ISD::Constant: { ConstantSDNode *CP = cast(Node); Results.push_back(ExpandConstant(CP)); break; } case ISD::FSUB: { EVT VT = Node->getValueType(0); if (TLI.isOperationLegalOrCustom(ISD::FADD, VT) && TLI.isOperationLegalOrCustom(ISD::FNEG, VT)) { const SDNodeFlags *Flags = &cast(Node)->Flags; Tmp1 = DAG.getNode(ISD::FNEG, dl, VT, Node->getOperand(1)); Tmp1 = DAG.getNode(ISD::FADD, dl, VT, Node->getOperand(0), Tmp1, Flags); Results.push_back(Tmp1); } break; } case ISD::SUB: { EVT VT = Node->getValueType(0); assert(TLI.isOperationLegalOrCustom(ISD::ADD, VT) && TLI.isOperationLegalOrCustom(ISD::XOR, VT) && "Don't know how to expand this subtraction!"); Tmp1 = DAG.getNode(ISD::XOR, dl, VT, Node->getOperand(1), DAG.getConstant(APInt::getAllOnesValue(VT.getSizeInBits()), dl, VT)); Tmp1 = DAG.getNode(ISD::ADD, dl, VT, Tmp1, DAG.getConstant(1, dl, VT)); Results.push_back(DAG.getNode(ISD::ADD, dl, VT, Node->getOperand(0), Tmp1)); break; } case ISD::UREM: case ISD::SREM: { EVT VT = Node->getValueType(0); bool isSigned = Node->getOpcode() == ISD::SREM; unsigned DivOpc = isSigned ? ISD::SDIV : ISD::UDIV; unsigned DivRemOpc = isSigned ? ISD::SDIVREM : ISD::UDIVREM; Tmp2 = Node->getOperand(0); Tmp3 = Node->getOperand(1); if (TLI.isOperationLegalOrCustom(DivRemOpc, VT)) { SDVTList VTs = DAG.getVTList(VT, VT); Tmp1 = DAG.getNode(DivRemOpc, dl, VTs, Tmp2, Tmp3).getValue(1); Results.push_back(Tmp1); } else if (TLI.isOperationLegalOrCustom(DivOpc, VT)) { // X % Y -> X-X/Y*Y Tmp1 = DAG.getNode(DivOpc, dl, VT, Tmp2, Tmp3); Tmp1 = DAG.getNode(ISD::MUL, dl, VT, Tmp1, Tmp3); Tmp1 = DAG.getNode(ISD::SUB, dl, VT, Tmp2, Tmp1); Results.push_back(Tmp1); } break; } case ISD::UDIV: case ISD::SDIV: { bool isSigned = Node->getOpcode() == ISD::SDIV; unsigned DivRemOpc = isSigned ? ISD::SDIVREM : ISD::UDIVREM; EVT VT = Node->getValueType(0); if (TLI.isOperationLegalOrCustom(DivRemOpc, VT)) { SDVTList VTs = DAG.getVTList(VT, VT); Tmp1 = DAG.getNode(DivRemOpc, dl, VTs, Node->getOperand(0), Node->getOperand(1)); Results.push_back(Tmp1); } break; } case ISD::MULHU: case ISD::MULHS: { unsigned ExpandOpcode = Node->getOpcode() == ISD::MULHU ? ISD::UMUL_LOHI : ISD::SMUL_LOHI; EVT VT = Node->getValueType(0); SDVTList VTs = DAG.getVTList(VT, VT); assert(TLI.isOperationLegalOrCustom(ExpandOpcode, VT) && "If this wasn't legal, it shouldn't have been created!"); Tmp1 = DAG.getNode(ExpandOpcode, dl, VTs, Node->getOperand(0), Node->getOperand(1)); Results.push_back(Tmp1.getValue(1)); break; } case ISD::MUL: { EVT VT = Node->getValueType(0); SDVTList VTs = DAG.getVTList(VT, VT); // See if multiply or divide can be lowered using two-result operations. // We just need the low half of the multiply; try both the signed // and unsigned forms. If the target supports both SMUL_LOHI and // UMUL_LOHI, form a preference by checking which forms of plain // MULH it supports. bool HasSMUL_LOHI = TLI.isOperationLegalOrCustom(ISD::SMUL_LOHI, VT); bool HasUMUL_LOHI = TLI.isOperationLegalOrCustom(ISD::UMUL_LOHI, VT); bool HasMULHS = TLI.isOperationLegalOrCustom(ISD::MULHS, VT); bool HasMULHU = TLI.isOperationLegalOrCustom(ISD::MULHU, VT); unsigned OpToUse = 0; if (HasSMUL_LOHI && !HasMULHS) { OpToUse = ISD::SMUL_LOHI; } else if (HasUMUL_LOHI && !HasMULHU) { OpToUse = ISD::UMUL_LOHI; } else if (HasSMUL_LOHI) { OpToUse = ISD::SMUL_LOHI; } else if (HasUMUL_LOHI) { OpToUse = ISD::UMUL_LOHI; } if (OpToUse) { Results.push_back(DAG.getNode(OpToUse, dl, VTs, Node->getOperand(0), Node->getOperand(1))); break; } SDValue Lo, Hi; EVT HalfType = VT.getHalfSizedIntegerVT(*DAG.getContext()); if (TLI.isOperationLegalOrCustom(ISD::ZERO_EXTEND, VT) && TLI.isOperationLegalOrCustom(ISD::ANY_EXTEND, VT) && TLI.isOperationLegalOrCustom(ISD::SHL, VT) && TLI.isOperationLegalOrCustom(ISD::OR, VT) && TLI.expandMUL(Node, Lo, Hi, HalfType, DAG)) { Lo = DAG.getNode(ISD::ZERO_EXTEND, dl, VT, Lo); Hi = DAG.getNode(ISD::ANY_EXTEND, dl, VT, Hi); SDValue Shift = DAG.getConstant(HalfType.getSizeInBits(), dl, TLI.getShiftAmountTy(HalfType, DAG.getDataLayout())); Hi = DAG.getNode(ISD::SHL, dl, VT, Hi, Shift); Results.push_back(DAG.getNode(ISD::OR, dl, VT, Lo, Hi)); } break; } case ISD::SADDO: case ISD::SSUBO: { SDValue LHS = Node->getOperand(0); SDValue RHS = Node->getOperand(1); SDValue Sum = DAG.getNode(Node->getOpcode() == ISD::SADDO ? ISD::ADD : ISD::SUB, dl, LHS.getValueType(), LHS, RHS); Results.push_back(Sum); EVT ResultType = Node->getValueType(1); EVT OType = getSetCCResultType(Node->getValueType(0)); SDValue Zero = DAG.getConstant(0, dl, LHS.getValueType()); // LHSSign -> LHS >= 0 // RHSSign -> RHS >= 0 // SumSign -> Sum >= 0 // // Add: // Overflow -> (LHSSign == RHSSign) && (LHSSign != SumSign) // Sub: // Overflow -> (LHSSign != RHSSign) && (LHSSign != SumSign) // SDValue LHSSign = DAG.getSetCC(dl, OType, LHS, Zero, ISD::SETGE); SDValue RHSSign = DAG.getSetCC(dl, OType, RHS, Zero, ISD::SETGE); SDValue SignsMatch = DAG.getSetCC(dl, OType, LHSSign, RHSSign, Node->getOpcode() == ISD::SADDO ? ISD::SETEQ : ISD::SETNE); SDValue SumSign = DAG.getSetCC(dl, OType, Sum, Zero, ISD::SETGE); SDValue SumSignNE = DAG.getSetCC(dl, OType, LHSSign, SumSign, ISD::SETNE); SDValue Cmp = DAG.getNode(ISD::AND, dl, OType, SignsMatch, SumSignNE); Results.push_back(DAG.getBoolExtOrTrunc(Cmp, dl, ResultType, ResultType)); break; } case ISD::UADDO: case ISD::USUBO: { SDValue LHS = Node->getOperand(0); SDValue RHS = Node->getOperand(1); SDValue Sum = DAG.getNode(Node->getOpcode() == ISD::UADDO ? ISD::ADD : ISD::SUB, dl, LHS.getValueType(), LHS, RHS); Results.push_back(Sum); EVT ResultType = Node->getValueType(1); EVT SetCCType = getSetCCResultType(Node->getValueType(0)); ISD::CondCode CC = Node->getOpcode() == ISD::UADDO ? ISD::SETULT : ISD::SETUGT; SDValue SetCC = DAG.getSetCC(dl, SetCCType, Sum, LHS, CC); Results.push_back(DAG.getBoolExtOrTrunc(SetCC, dl, ResultType, ResultType)); break; } case ISD::UMULO: case ISD::SMULO: { EVT VT = Node->getValueType(0); EVT WideVT = EVT::getIntegerVT(*DAG.getContext(), VT.getSizeInBits() * 2); SDValue LHS = Node->getOperand(0); SDValue RHS = Node->getOperand(1); SDValue BottomHalf; SDValue TopHalf; static const unsigned Ops[2][3] = { { ISD::MULHU, ISD::UMUL_LOHI, ISD::ZERO_EXTEND }, { ISD::MULHS, ISD::SMUL_LOHI, ISD::SIGN_EXTEND }}; bool isSigned = Node->getOpcode() == ISD::SMULO; if (TLI.isOperationLegalOrCustom(Ops[isSigned][0], VT)) { BottomHalf = DAG.getNode(ISD::MUL, dl, VT, LHS, RHS); TopHalf = DAG.getNode(Ops[isSigned][0], dl, VT, LHS, RHS); } else if (TLI.isOperationLegalOrCustom(Ops[isSigned][1], VT)) { BottomHalf = DAG.getNode(Ops[isSigned][1], dl, DAG.getVTList(VT, VT), LHS, RHS); TopHalf = BottomHalf.getValue(1); } else if (TLI.isTypeLegal(WideVT)) { LHS = DAG.getNode(Ops[isSigned][2], dl, WideVT, LHS); RHS = DAG.getNode(Ops[isSigned][2], dl, WideVT, RHS); Tmp1 = DAG.getNode(ISD::MUL, dl, WideVT, LHS, RHS); BottomHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT, Tmp1, DAG.getIntPtrConstant(0, dl)); TopHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT, Tmp1, DAG.getIntPtrConstant(1, dl)); } else { // We can fall back to a libcall with an illegal type for the MUL if we // have a libcall big enough. // Also, we can fall back to a division in some cases, but that's a big // performance hit in the general case. RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; if (WideVT == MVT::i16) LC = RTLIB::MUL_I16; else if (WideVT == MVT::i32) LC = RTLIB::MUL_I32; else if (WideVT == MVT::i64) LC = RTLIB::MUL_I64; else if (WideVT == MVT::i128) LC = RTLIB::MUL_I128; assert(LC != RTLIB::UNKNOWN_LIBCALL && "Cannot expand this operation!"); // The high part is obtained by SRA'ing all but one of the bits of low // part. unsigned LoSize = VT.getSizeInBits(); SDValue HiLHS = DAG.getNode(ISD::SRA, dl, VT, RHS, DAG.getConstant(LoSize - 1, dl, TLI.getPointerTy(DAG.getDataLayout()))); SDValue HiRHS = DAG.getNode(ISD::SRA, dl, VT, LHS, DAG.getConstant(LoSize - 1, dl, TLI.getPointerTy(DAG.getDataLayout()))); // Here we're passing the 2 arguments explicitly as 4 arguments that are // pre-lowered to the correct types. This all depends upon WideVT not // being a legal type for the architecture and thus has to be split to // two arguments. SDValue Args[] = { LHS, HiLHS, RHS, HiRHS }; SDValue Ret = ExpandLibCall(LC, WideVT, Args, 4, isSigned, dl); BottomHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT, Ret, DAG.getIntPtrConstant(0, dl)); TopHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT, Ret, DAG.getIntPtrConstant(1, dl)); // Ret is a node with an illegal type. Because such things are not // generally permitted during this phase of legalization, make sure the // node has no more uses. The above EXTRACT_ELEMENT nodes should have been // folded. assert(Ret->use_empty() && "Unexpected uses of illegally type from expanded lib call."); } if (isSigned) { Tmp1 = DAG.getConstant( VT.getSizeInBits() - 1, dl, TLI.getShiftAmountTy(BottomHalf.getValueType(), DAG.getDataLayout())); Tmp1 = DAG.getNode(ISD::SRA, dl, VT, BottomHalf, Tmp1); TopHalf = DAG.getSetCC(dl, getSetCCResultType(VT), TopHalf, Tmp1, ISD::SETNE); } else { TopHalf = DAG.getSetCC(dl, getSetCCResultType(VT), TopHalf, DAG.getConstant(0, dl, VT), ISD::SETNE); } Results.push_back(BottomHalf); Results.push_back(TopHalf); break; } case ISD::BUILD_PAIR: { EVT PairTy = Node->getValueType(0); Tmp1 = DAG.getNode(ISD::ZERO_EXTEND, dl, PairTy, Node->getOperand(0)); Tmp2 = DAG.getNode(ISD::ANY_EXTEND, dl, PairTy, Node->getOperand(1)); Tmp2 = DAG.getNode( ISD::SHL, dl, PairTy, Tmp2, DAG.getConstant(PairTy.getSizeInBits() / 2, dl, TLI.getShiftAmountTy(PairTy, DAG.getDataLayout()))); Results.push_back(DAG.getNode(ISD::OR, dl, PairTy, Tmp1, Tmp2)); break; } case ISD::SELECT: Tmp1 = Node->getOperand(0); Tmp2 = Node->getOperand(1); Tmp3 = Node->getOperand(2); if (Tmp1.getOpcode() == ISD::SETCC) { Tmp1 = DAG.getSelectCC(dl, Tmp1.getOperand(0), Tmp1.getOperand(1), Tmp2, Tmp3, cast(Tmp1.getOperand(2))->get()); } else { Tmp1 = DAG.getSelectCC(dl, Tmp1, DAG.getConstant(0, dl, Tmp1.getValueType()), Tmp2, Tmp3, ISD::SETNE); } Results.push_back(Tmp1); break; case ISD::BR_JT: { SDValue Chain = Node->getOperand(0); SDValue Table = Node->getOperand(1); SDValue Index = Node->getOperand(2); EVT PTy = TLI.getPointerTy(DAG.getDataLayout()); const DataLayout &TD = DAG.getDataLayout(); unsigned EntrySize = DAG.getMachineFunction().getJumpTableInfo()->getEntrySize(TD); Index = DAG.getNode(ISD::MUL, dl, Index.getValueType(), Index, DAG.getConstant(EntrySize, dl, Index.getValueType())); SDValue Addr = DAG.getNode(ISD::ADD, dl, Index.getValueType(), Index, Table); EVT MemVT = EVT::getIntegerVT(*DAG.getContext(), EntrySize * 8); SDValue LD = DAG.getExtLoad( ISD::SEXTLOAD, dl, PTy, Chain, Addr, MachinePointerInfo::getJumpTable(DAG.getMachineFunction()), MemVT, false, false, false, 0); Addr = LD; if (TM.getRelocationModel() == Reloc::PIC_) { // For PIC, the sequence is: // BRIND(load(Jumptable + index) + RelocBase) // RelocBase can be JumpTable, GOT or some sort of global base. Addr = DAG.getNode(ISD::ADD, dl, PTy, Addr, TLI.getPICJumpTableRelocBase(Table, DAG)); } Tmp1 = DAG.getNode(ISD::BRIND, dl, MVT::Other, LD.getValue(1), Addr); Results.push_back(Tmp1); break; } case ISD::BRCOND: // Expand brcond's setcc into its constituent parts and create a BR_CC // Node. Tmp1 = Node->getOperand(0); Tmp2 = Node->getOperand(1); if (Tmp2.getOpcode() == ISD::SETCC) { Tmp1 = DAG.getNode(ISD::BR_CC, dl, MVT::Other, Tmp1, Tmp2.getOperand(2), Tmp2.getOperand(0), Tmp2.getOperand(1), Node->getOperand(2)); } else { // We test only the i1 bit. Skip the AND if UNDEF. Tmp3 = (Tmp2.getOpcode() == ISD::UNDEF) ? Tmp2 : DAG.getNode(ISD::AND, dl, Tmp2.getValueType(), Tmp2, DAG.getConstant(1, dl, Tmp2.getValueType())); Tmp1 = DAG.getNode(ISD::BR_CC, dl, MVT::Other, Tmp1, DAG.getCondCode(ISD::SETNE), Tmp3, DAG.getConstant(0, dl, Tmp3.getValueType()), Node->getOperand(2)); } Results.push_back(Tmp1); break; case ISD::SETCC: { Tmp1 = Node->getOperand(0); Tmp2 = Node->getOperand(1); Tmp3 = Node->getOperand(2); bool Legalized = LegalizeSetCCCondCode(Node->getValueType(0), Tmp1, Tmp2, Tmp3, NeedInvert, dl); if (Legalized) { // If we expanded the SETCC by swapping LHS and RHS, or by inverting the // condition code, create a new SETCC node. if (Tmp3.getNode()) Tmp1 = DAG.getNode(ISD::SETCC, dl, Node->getValueType(0), Tmp1, Tmp2, Tmp3); // If we expanded the SETCC by inverting the condition code, then wrap // the existing SETCC in a NOT to restore the intended condition. if (NeedInvert) Tmp1 = DAG.getLogicalNOT(dl, Tmp1, Tmp1->getValueType(0)); Results.push_back(Tmp1); break; } // Otherwise, SETCC for the given comparison type must be completely // illegal; expand it into a SELECT_CC. EVT VT = Node->getValueType(0); int TrueValue; switch (TLI.getBooleanContents(Tmp1->getValueType(0))) { case TargetLowering::ZeroOrOneBooleanContent: case TargetLowering::UndefinedBooleanContent: TrueValue = 1; break; case TargetLowering::ZeroOrNegativeOneBooleanContent: TrueValue = -1; break; } Tmp1 = DAG.getNode(ISD::SELECT_CC, dl, VT, Tmp1, Tmp2, DAG.getConstant(TrueValue, dl, VT), DAG.getConstant(0, dl, VT), Tmp3); Results.push_back(Tmp1); break; } case ISD::SELECT_CC: { Tmp1 = Node->getOperand(0); // LHS Tmp2 = Node->getOperand(1); // RHS Tmp3 = Node->getOperand(2); // True Tmp4 = Node->getOperand(3); // False EVT VT = Node->getValueType(0); SDValue CC = Node->getOperand(4); ISD::CondCode CCOp = cast(CC)->get(); if (TLI.isCondCodeLegal(CCOp, Tmp1.getSimpleValueType())) { // If the condition code is legal, then we need to expand this // node using SETCC and SELECT. EVT CmpVT = Tmp1.getValueType(); assert(!TLI.isOperationExpand(ISD::SELECT, VT) && "Cannot expand ISD::SELECT_CC when ISD::SELECT also needs to be " "expanded."); EVT CCVT = TLI.getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), CmpVT); SDValue Cond = DAG.getNode(ISD::SETCC, dl, CCVT, Tmp1, Tmp2, CC); Results.push_back(DAG.getSelect(dl, VT, Cond, Tmp3, Tmp4)); break; } // SELECT_CC is legal, so the condition code must not be. bool Legalized = false; // Try to legalize by inverting the condition. This is for targets that // might support an ordered version of a condition, but not the unordered // version (or vice versa). ISD::CondCode InvCC = ISD::getSetCCInverse(CCOp, Tmp1.getValueType().isInteger()); if (TLI.isCondCodeLegal(InvCC, Tmp1.getSimpleValueType())) { // Use the new condition code and swap true and false Legalized = true; Tmp1 = DAG.getSelectCC(dl, Tmp1, Tmp2, Tmp4, Tmp3, InvCC); } else { // If The inverse is not legal, then try to swap the arguments using // the inverse condition code. ISD::CondCode SwapInvCC = ISD::getSetCCSwappedOperands(InvCC); if (TLI.isCondCodeLegal(SwapInvCC, Tmp1.getSimpleValueType())) { // The swapped inverse condition is legal, so swap true and false, // lhs and rhs. Legalized = true; Tmp1 = DAG.getSelectCC(dl, Tmp2, Tmp1, Tmp4, Tmp3, SwapInvCC); } } if (!Legalized) { Legalized = LegalizeSetCCCondCode( getSetCCResultType(Tmp1.getValueType()), Tmp1, Tmp2, CC, NeedInvert, dl); assert(Legalized && "Can't legalize SELECT_CC with legal condition!"); // If we expanded the SETCC by inverting the condition code, then swap // the True/False operands to match. if (NeedInvert) std::swap(Tmp3, Tmp4); // If we expanded the SETCC by swapping LHS and RHS, or by inverting the // condition code, create a new SELECT_CC node. if (CC.getNode()) { Tmp1 = DAG.getNode(ISD::SELECT_CC, dl, Node->getValueType(0), Tmp1, Tmp2, Tmp3, Tmp4, CC); } else { Tmp2 = DAG.getConstant(0, dl, Tmp1.getValueType()); CC = DAG.getCondCode(ISD::SETNE); Tmp1 = DAG.getNode(ISD::SELECT_CC, dl, Node->getValueType(0), Tmp1, Tmp2, Tmp3, Tmp4, CC); } } Results.push_back(Tmp1); break; } case ISD::BR_CC: { Tmp1 = Node->getOperand(0); // Chain Tmp2 = Node->getOperand(2); // LHS Tmp3 = Node->getOperand(3); // RHS Tmp4 = Node->getOperand(1); // CC bool Legalized = LegalizeSetCCCondCode(getSetCCResultType( Tmp2.getValueType()), Tmp2, Tmp3, Tmp4, NeedInvert, dl); (void)Legalized; assert(Legalized && "Can't legalize BR_CC with legal condition!"); // If we expanded the SETCC by inverting the condition code, then wrap // the existing SETCC in a NOT to restore the intended condition. if (NeedInvert) Tmp4 = DAG.getNOT(dl, Tmp4, Tmp4->getValueType(0)); // If we expanded the SETCC by swapping LHS and RHS, create a new BR_CC // node. if (Tmp4.getNode()) { Tmp1 = DAG.getNode(ISD::BR_CC, dl, Node->getValueType(0), Tmp1, Tmp4, Tmp2, Tmp3, Node->getOperand(4)); } else { Tmp3 = DAG.getConstant(0, dl, Tmp2.getValueType()); Tmp4 = DAG.getCondCode(ISD::SETNE); Tmp1 = DAG.getNode(ISD::BR_CC, dl, Node->getValueType(0), Tmp1, Tmp4, Tmp2, Tmp3, Node->getOperand(4)); } Results.push_back(Tmp1); break; } case ISD::BUILD_VECTOR: Results.push_back(ExpandBUILD_VECTOR(Node)); break; case ISD::SRA: case ISD::SRL: case ISD::SHL: { // Scalarize vector SRA/SRL/SHL. EVT VT = Node->getValueType(0); assert(VT.isVector() && "Unable to legalize non-vector shift"); assert(TLI.isTypeLegal(VT.getScalarType())&& "Element type must be legal"); unsigned NumElem = VT.getVectorNumElements(); SmallVector Scalars; for (unsigned Idx = 0; Idx < NumElem; Idx++) { SDValue Ex = DAG.getNode( ISD::EXTRACT_VECTOR_ELT, dl, VT.getScalarType(), Node->getOperand(0), DAG.getConstant(Idx, dl, TLI.getVectorIdxTy(DAG.getDataLayout()))); SDValue Sh = DAG.getNode( ISD::EXTRACT_VECTOR_ELT, dl, VT.getScalarType(), Node->getOperand(1), DAG.getConstant(Idx, dl, TLI.getVectorIdxTy(DAG.getDataLayout()))); Scalars.push_back(DAG.getNode(Node->getOpcode(), dl, VT.getScalarType(), Ex, Sh)); } SDValue Result = DAG.getNode(ISD::BUILD_VECTOR, dl, Node->getValueType(0), Scalars); ReplaceNode(SDValue(Node, 0), Result); break; } case ISD::GLOBAL_OFFSET_TABLE: case ISD::GlobalAddress: case ISD::GlobalTLSAddress: case ISD::ExternalSymbol: case ISD::ConstantPool: case ISD::JumpTable: case ISD::INTRINSIC_W_CHAIN: case ISD::INTRINSIC_WO_CHAIN: case ISD::INTRINSIC_VOID: // FIXME: Custom lowering for these operations shouldn't return null! break; } // Replace the original node with the legalized result. if (Results.empty()) return false; ReplaceNode(Node, Results.data()); return true; } void SelectionDAGLegalize::ConvertNodeToLibcall(SDNode *Node) { SmallVector Results; SDLoc dl(Node); SDValue Tmp1, Tmp2, Tmp3, Tmp4; unsigned Opc = Node->getOpcode(); switch (Opc) { case ISD::ATOMIC_FENCE: { // If the target didn't lower this, lower it to '__sync_synchronize()' call // FIXME: handle "fence singlethread" more efficiently. TargetLowering::ArgListTy Args; TargetLowering::CallLoweringInfo CLI(DAG); CLI.setDebugLoc(dl) .setChain(Node->getOperand(0)) .setCallee(CallingConv::C, Type::getVoidTy(*DAG.getContext()), DAG.getExternalSymbol("__sync_synchronize", TLI.getPointerTy(DAG.getDataLayout())), std::move(Args), 0); std::pair CallResult = TLI.LowerCallTo(CLI); Results.push_back(CallResult.second); break; } // By default, atomic intrinsics are marked Legal and lowered. Targets // which don't support them directly, however, may want libcalls, in which // case they mark them Expand, and we get here. case ISD::ATOMIC_SWAP: case ISD::ATOMIC_LOAD_ADD: case ISD::ATOMIC_LOAD_SUB: case ISD::ATOMIC_LOAD_AND: case ISD::ATOMIC_LOAD_OR: case ISD::ATOMIC_LOAD_XOR: case ISD::ATOMIC_LOAD_NAND: case ISD::ATOMIC_LOAD_MIN: case ISD::ATOMIC_LOAD_MAX: case ISD::ATOMIC_LOAD_UMIN: case ISD::ATOMIC_LOAD_UMAX: case ISD::ATOMIC_CMP_SWAP: { MVT VT = cast(Node)->getMemoryVT().getSimpleVT(); RTLIB::Libcall LC = RTLIB::getATOMIC(Opc, VT); assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unexpected atomic op or value type!"); std::pair Tmp = ExpandChainLibCall(LC, Node, false); Results.push_back(Tmp.first); Results.push_back(Tmp.second); break; } case ISD::TRAP: { // If this operation is not supported, lower it to 'abort()' call TargetLowering::ArgListTy Args; TargetLowering::CallLoweringInfo CLI(DAG); CLI.setDebugLoc(dl) .setChain(Node->getOperand(0)) .setCallee(CallingConv::C, Type::getVoidTy(*DAG.getContext()), DAG.getExternalSymbol("abort", TLI.getPointerTy(DAG.getDataLayout())), std::move(Args), 0); std::pair CallResult = TLI.LowerCallTo(CLI); Results.push_back(CallResult.second); break; } case ISD::FMINNUM: Results.push_back(ExpandFPLibCall(Node, RTLIB::FMIN_F32, RTLIB::FMIN_F64, RTLIB::FMIN_F80, RTLIB::FMIN_F128, RTLIB::FMIN_PPCF128)); break; case ISD::FMAXNUM: Results.push_back(ExpandFPLibCall(Node, RTLIB::FMAX_F32, RTLIB::FMAX_F64, RTLIB::FMAX_F80, RTLIB::FMAX_F128, RTLIB::FMAX_PPCF128)); break; case ISD::FSQRT: Results.push_back(ExpandFPLibCall(Node, RTLIB::SQRT_F32, RTLIB::SQRT_F64, RTLIB::SQRT_F80, RTLIB::SQRT_F128, RTLIB::SQRT_PPCF128)); break; case ISD::FSIN: Results.push_back(ExpandFPLibCall(Node, RTLIB::SIN_F32, RTLIB::SIN_F64, RTLIB::SIN_F80, RTLIB::SIN_F128, RTLIB::SIN_PPCF128)); break; case ISD::FCOS: Results.push_back(ExpandFPLibCall(Node, RTLIB::COS_F32, RTLIB::COS_F64, RTLIB::COS_F80, RTLIB::COS_F128, RTLIB::COS_PPCF128)); break; case ISD::FSINCOS: // Expand into sincos libcall. ExpandSinCosLibCall(Node, Results); break; case ISD::FLOG: Results.push_back(ExpandFPLibCall(Node, RTLIB::LOG_F32, RTLIB::LOG_F64, RTLIB::LOG_F80, RTLIB::LOG_F128, RTLIB::LOG_PPCF128)); break; case ISD::FLOG2: Results.push_back(ExpandFPLibCall(Node, RTLIB::LOG2_F32, RTLIB::LOG2_F64, RTLIB::LOG2_F80, RTLIB::LOG2_F128, RTLIB::LOG2_PPCF128)); break; case ISD::FLOG10: Results.push_back(ExpandFPLibCall(Node, RTLIB::LOG10_F32, RTLIB::LOG10_F64, RTLIB::LOG10_F80, RTLIB::LOG10_F128, RTLIB::LOG10_PPCF128)); break; case ISD::FEXP: Results.push_back(ExpandFPLibCall(Node, RTLIB::EXP_F32, RTLIB::EXP_F64, RTLIB::EXP_F80, RTLIB::EXP_F128, RTLIB::EXP_PPCF128)); break; case ISD::FEXP2: Results.push_back(ExpandFPLibCall(Node, RTLIB::EXP2_F32, RTLIB::EXP2_F64, RTLIB::EXP2_F80, RTLIB::EXP2_F128, RTLIB::EXP2_PPCF128)); break; case ISD::FTRUNC: Results.push_back(ExpandFPLibCall(Node, RTLIB::TRUNC_F32, RTLIB::TRUNC_F64, RTLIB::TRUNC_F80, RTLIB::TRUNC_F128, RTLIB::TRUNC_PPCF128)); break; case ISD::FFLOOR: Results.push_back(ExpandFPLibCall(Node, RTLIB::FLOOR_F32, RTLIB::FLOOR_F64, RTLIB::FLOOR_F80, RTLIB::FLOOR_F128, RTLIB::FLOOR_PPCF128)); break; case ISD::FCEIL: Results.push_back(ExpandFPLibCall(Node, RTLIB::CEIL_F32, RTLIB::CEIL_F64, RTLIB::CEIL_F80, RTLIB::CEIL_F128, RTLIB::CEIL_PPCF128)); break; case ISD::FRINT: Results.push_back(ExpandFPLibCall(Node, RTLIB::RINT_F32, RTLIB::RINT_F64, RTLIB::RINT_F80, RTLIB::RINT_F128, RTLIB::RINT_PPCF128)); break; case ISD::FNEARBYINT: Results.push_back(ExpandFPLibCall(Node, RTLIB::NEARBYINT_F32, RTLIB::NEARBYINT_F64, RTLIB::NEARBYINT_F80, RTLIB::NEARBYINT_F128, RTLIB::NEARBYINT_PPCF128)); break; case ISD::FROUND: Results.push_back(ExpandFPLibCall(Node, RTLIB::ROUND_F32, RTLIB::ROUND_F64, RTLIB::ROUND_F80, RTLIB::ROUND_F128, RTLIB::ROUND_PPCF128)); break; case ISD::FPOWI: Results.push_back(ExpandFPLibCall(Node, RTLIB::POWI_F32, RTLIB::POWI_F64, RTLIB::POWI_F80, RTLIB::POWI_F128, RTLIB::POWI_PPCF128)); break; case ISD::FPOW: Results.push_back(ExpandFPLibCall(Node, RTLIB::POW_F32, RTLIB::POW_F64, RTLIB::POW_F80, RTLIB::POW_F128, RTLIB::POW_PPCF128)); break; case ISD::FDIV: Results.push_back(ExpandFPLibCall(Node, RTLIB::DIV_F32, RTLIB::DIV_F64, RTLIB::DIV_F80, RTLIB::DIV_F128, RTLIB::DIV_PPCF128)); break; case ISD::FREM: Results.push_back(ExpandFPLibCall(Node, RTLIB::REM_F32, RTLIB::REM_F64, RTLIB::REM_F80, RTLIB::REM_F128, RTLIB::REM_PPCF128)); break; case ISD::FMA: Results.push_back(ExpandFPLibCall(Node, RTLIB::FMA_F32, RTLIB::FMA_F64, RTLIB::FMA_F80, RTLIB::FMA_F128, RTLIB::FMA_PPCF128)); break; case ISD::FADD: Results.push_back(ExpandFPLibCall(Node, RTLIB::ADD_F32, RTLIB::ADD_F64, RTLIB::ADD_F80, RTLIB::ADD_F128, RTLIB::ADD_PPCF128)); break; case ISD::FMUL: Results.push_back(ExpandFPLibCall(Node, RTLIB::MUL_F32, RTLIB::MUL_F64, RTLIB::MUL_F80, RTLIB::MUL_F128, RTLIB::MUL_PPCF128)); break; case ISD::FP16_TO_FP: if (Node->getValueType(0) == MVT::f32) { Results.push_back(ExpandLibCall(RTLIB::FPEXT_F16_F32, Node, false)); } break; case ISD::FP_TO_FP16: { RTLIB::Libcall LC = RTLIB::getFPROUND(Node->getOperand(0).getValueType(), MVT::f16); assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unable to expand fp_to_fp16"); Results.push_back(ExpandLibCall(LC, Node, false)); break; } case ISD::FSUB: Results.push_back(ExpandFPLibCall(Node, RTLIB::SUB_F32, RTLIB::SUB_F64, RTLIB::SUB_F80, RTLIB::SUB_F128, RTLIB::SUB_PPCF128)); break; case ISD::SREM: Results.push_back(ExpandIntLibCall(Node, true, RTLIB::SREM_I8, RTLIB::SREM_I16, RTLIB::SREM_I32, RTLIB::SREM_I64, RTLIB::SREM_I128)); break; case ISD::UREM: Results.push_back(ExpandIntLibCall(Node, false, RTLIB::UREM_I8, RTLIB::UREM_I16, RTLIB::UREM_I32, RTLIB::UREM_I64, RTLIB::UREM_I128)); break; case ISD::SDIV: Results.push_back(ExpandIntLibCall(Node, true, RTLIB::SDIV_I8, RTLIB::SDIV_I16, RTLIB::SDIV_I32, RTLIB::SDIV_I64, RTLIB::SDIV_I128)); break; case ISD::UDIV: Results.push_back(ExpandIntLibCall(Node, false, RTLIB::UDIV_I8, RTLIB::UDIV_I16, RTLIB::UDIV_I32, RTLIB::UDIV_I64, RTLIB::UDIV_I128)); break; case ISD::SDIVREM: case ISD::UDIVREM: // Expand into divrem libcall ExpandDivRemLibCall(Node, Results); break; case ISD::MUL: Results.push_back(ExpandIntLibCall(Node, false, RTLIB::MUL_I8, RTLIB::MUL_I16, RTLIB::MUL_I32, RTLIB::MUL_I64, RTLIB::MUL_I128)); break; } // Replace the original node with the legalized result. if (!Results.empty()) ReplaceNode(Node, Results.data()); } // Determine the vector type to use in place of an original scalar element when // promoting equally sized vectors. static MVT getPromotedVectorElementType(const TargetLowering &TLI, MVT EltVT, MVT NewEltVT) { unsigned OldEltsPerNewElt = EltVT.getSizeInBits() / NewEltVT.getSizeInBits(); MVT MidVT = MVT::getVectorVT(NewEltVT, OldEltsPerNewElt); assert(TLI.isTypeLegal(MidVT) && "unexpected"); return MidVT; } void SelectionDAGLegalize::PromoteNode(SDNode *Node) { SmallVector Results; MVT OVT = Node->getSimpleValueType(0); if (Node->getOpcode() == ISD::UINT_TO_FP || Node->getOpcode() == ISD::SINT_TO_FP || Node->getOpcode() == ISD::SETCC || Node->getOpcode() == ISD::EXTRACT_VECTOR_ELT || Node->getOpcode() == ISD::INSERT_VECTOR_ELT) { OVT = Node->getOperand(0).getSimpleValueType(); } if (Node->getOpcode() == ISD::BR_CC) OVT = Node->getOperand(2).getSimpleValueType(); MVT NVT = TLI.getTypeToPromoteTo(Node->getOpcode(), OVT); SDLoc dl(Node); SDValue Tmp1, Tmp2, Tmp3; switch (Node->getOpcode()) { case ISD::CTTZ: case ISD::CTTZ_ZERO_UNDEF: case ISD::CTLZ: case ISD::CTLZ_ZERO_UNDEF: case ISD::CTPOP: // Zero extend the argument. Tmp1 = DAG.getNode(ISD::ZERO_EXTEND, dl, NVT, Node->getOperand(0)); // Perform the larger operation. For CTPOP and CTTZ_ZERO_UNDEF, this is // already the correct result. Tmp1 = DAG.getNode(Node->getOpcode(), dl, NVT, Tmp1); if (Node->getOpcode() == ISD::CTTZ) { // FIXME: This should set a bit in the zero extended value instead. Tmp2 = DAG.getSetCC(dl, getSetCCResultType(NVT), Tmp1, DAG.getConstant(NVT.getSizeInBits(), dl, NVT), ISD::SETEQ); Tmp1 = DAG.getSelect(dl, NVT, Tmp2, DAG.getConstant(OVT.getSizeInBits(), dl, NVT), Tmp1); } else if (Node->getOpcode() == ISD::CTLZ || Node->getOpcode() == ISD::CTLZ_ZERO_UNDEF) { // Tmp1 = Tmp1 - (sizeinbits(NVT) - sizeinbits(Old VT)) Tmp1 = DAG.getNode(ISD::SUB, dl, NVT, Tmp1, DAG.getConstant(NVT.getSizeInBits() - OVT.getSizeInBits(), dl, NVT)); } Results.push_back(DAG.getNode(ISD::TRUNCATE, dl, OVT, Tmp1)); break; case ISD::BSWAP: { unsigned DiffBits = NVT.getSizeInBits() - OVT.getSizeInBits(); Tmp1 = DAG.getNode(ISD::ZERO_EXTEND, dl, NVT, Node->getOperand(0)); Tmp1 = DAG.getNode(ISD::BSWAP, dl, NVT, Tmp1); Tmp1 = DAG.getNode( ISD::SRL, dl, NVT, Tmp1, DAG.getConstant(DiffBits, dl, TLI.getShiftAmountTy(NVT, DAG.getDataLayout()))); Results.push_back(Tmp1); break; } case ISD::FP_TO_UINT: case ISD::FP_TO_SINT: Tmp1 = PromoteLegalFP_TO_INT(Node->getOperand(0), Node->getValueType(0), Node->getOpcode() == ISD::FP_TO_SINT, dl); Results.push_back(Tmp1); break; case ISD::UINT_TO_FP: case ISD::SINT_TO_FP: Tmp1 = PromoteLegalINT_TO_FP(Node->getOperand(0), Node->getValueType(0), Node->getOpcode() == ISD::SINT_TO_FP, dl); Results.push_back(Tmp1); break; case ISD::VAARG: { SDValue Chain = Node->getOperand(0); // Get the chain. SDValue Ptr = Node->getOperand(1); // Get the pointer. unsigned TruncOp; if (OVT.isVector()) { TruncOp = ISD::BITCAST; } else { assert(OVT.isInteger() && "VAARG promotion is supported only for vectors or integer types"); TruncOp = ISD::TRUNCATE; } // Perform the larger operation, then convert back Tmp1 = DAG.getVAArg(NVT, dl, Chain, Ptr, Node->getOperand(2), Node->getConstantOperandVal(3)); Chain = Tmp1.getValue(1); Tmp2 = DAG.getNode(TruncOp, dl, OVT, Tmp1); // Modified the chain result - switch anything that used the old chain to // use the new one. DAG.ReplaceAllUsesOfValueWith(SDValue(Node, 0), Tmp2); DAG.ReplaceAllUsesOfValueWith(SDValue(Node, 1), Chain); if (UpdatedNodes) { UpdatedNodes->insert(Tmp2.getNode()); UpdatedNodes->insert(Chain.getNode()); } ReplacedNode(Node); break; } case ISD::AND: case ISD::OR: case ISD::XOR: { unsigned ExtOp, TruncOp; if (OVT.isVector()) { ExtOp = ISD::BITCAST; TruncOp = ISD::BITCAST; } else { assert(OVT.isInteger() && "Cannot promote logic operation"); ExtOp = ISD::ANY_EXTEND; TruncOp = ISD::TRUNCATE; } // Promote each of the values to the new type. Tmp1 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(0)); Tmp2 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(1)); // Perform the larger operation, then convert back Tmp1 = DAG.getNode(Node->getOpcode(), dl, NVT, Tmp1, Tmp2); Results.push_back(DAG.getNode(TruncOp, dl, OVT, Tmp1)); break; } case ISD::SELECT: { unsigned ExtOp, TruncOp; if (Node->getValueType(0).isVector() || Node->getValueType(0).getSizeInBits() == NVT.getSizeInBits()) { ExtOp = ISD::BITCAST; TruncOp = ISD::BITCAST; } else if (Node->getValueType(0).isInteger()) { ExtOp = ISD::ANY_EXTEND; TruncOp = ISD::TRUNCATE; } else { ExtOp = ISD::FP_EXTEND; TruncOp = ISD::FP_ROUND; } Tmp1 = Node->getOperand(0); // Promote each of the values to the new type. Tmp2 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(1)); Tmp3 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(2)); // Perform the larger operation, then round down. Tmp1 = DAG.getSelect(dl, NVT, Tmp1, Tmp2, Tmp3); if (TruncOp != ISD::FP_ROUND) Tmp1 = DAG.getNode(TruncOp, dl, Node->getValueType(0), Tmp1); else Tmp1 = DAG.getNode(TruncOp, dl, Node->getValueType(0), Tmp1, DAG.getIntPtrConstant(0, dl)); Results.push_back(Tmp1); break; } case ISD::VECTOR_SHUFFLE: { ArrayRef Mask = cast(Node)->getMask(); // Cast the two input vectors. Tmp1 = DAG.getNode(ISD::BITCAST, dl, NVT, Node->getOperand(0)); Tmp2 = DAG.getNode(ISD::BITCAST, dl, NVT, Node->getOperand(1)); // Convert the shuffle mask to the right # elements. Tmp1 = ShuffleWithNarrowerEltType(NVT, OVT, dl, Tmp1, Tmp2, Mask); Tmp1 = DAG.getNode(ISD::BITCAST, dl, OVT, Tmp1); Results.push_back(Tmp1); break; } case ISD::SETCC: { unsigned ExtOp = ISD::FP_EXTEND; if (NVT.isInteger()) { ISD::CondCode CCCode = cast(Node->getOperand(2))->get(); ExtOp = isSignedIntSetCC(CCCode) ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND; } Tmp1 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(0)); Tmp2 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(1)); Results.push_back(DAG.getNode(ISD::SETCC, dl, Node->getValueType(0), Tmp1, Tmp2, Node->getOperand(2))); break; } case ISD::BR_CC: { unsigned ExtOp = ISD::FP_EXTEND; if (NVT.isInteger()) { ISD::CondCode CCCode = cast(Node->getOperand(1))->get(); ExtOp = isSignedIntSetCC(CCCode) ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND; } Tmp1 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(2)); Tmp2 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(3)); Results.push_back(DAG.getNode(ISD::BR_CC, dl, Node->getValueType(0), Node->getOperand(0), Node->getOperand(1), Tmp1, Tmp2, Node->getOperand(4))); break; } case ISD::FADD: case ISD::FSUB: case ISD::FMUL: case ISD::FDIV: case ISD::FREM: case ISD::FMINNUM: case ISD::FMAXNUM: case ISD::FPOW: { Tmp1 = DAG.getNode(ISD::FP_EXTEND, dl, NVT, Node->getOperand(0)); Tmp2 = DAG.getNode(ISD::FP_EXTEND, dl, NVT, Node->getOperand(1)); Tmp3 = DAG.getNode(Node->getOpcode(), dl, NVT, Tmp1, Tmp2, Node->getFlags()); Results.push_back(DAG.getNode(ISD::FP_ROUND, dl, OVT, Tmp3, DAG.getIntPtrConstant(0, dl))); break; } case ISD::FMA: { Tmp1 = DAG.getNode(ISD::FP_EXTEND, dl, NVT, Node->getOperand(0)); Tmp2 = DAG.getNode(ISD::FP_EXTEND, dl, NVT, Node->getOperand(1)); Tmp3 = DAG.getNode(ISD::FP_EXTEND, dl, NVT, Node->getOperand(2)); Results.push_back( DAG.getNode(ISD::FP_ROUND, dl, OVT, DAG.getNode(Node->getOpcode(), dl, NVT, Tmp1, Tmp2, Tmp3), DAG.getIntPtrConstant(0, dl))); break; } case ISD::FCOPYSIGN: case ISD::FPOWI: { Tmp1 = DAG.getNode(ISD::FP_EXTEND, dl, NVT, Node->getOperand(0)); Tmp2 = Node->getOperand(1); Tmp3 = DAG.getNode(Node->getOpcode(), dl, NVT, Tmp1, Tmp2); // fcopysign doesn't change anything but the sign bit, so // (fp_round (fcopysign (fpext a), b)) // is as precise as // (fp_round (fpext a)) // which is a no-op. Mark it as a TRUNCating FP_ROUND. const bool isTrunc = (Node->getOpcode() == ISD::FCOPYSIGN); Results.push_back(DAG.getNode(ISD::FP_ROUND, dl, OVT, Tmp3, DAG.getIntPtrConstant(isTrunc, dl))); break; } case ISD::FFLOOR: case ISD::FCEIL: case ISD::FRINT: case ISD::FNEARBYINT: case ISD::FROUND: case ISD::FTRUNC: case ISD::FNEG: case ISD::FSQRT: case ISD::FSIN: case ISD::FCOS: case ISD::FLOG: case ISD::FLOG2: case ISD::FLOG10: case ISD::FABS: case ISD::FEXP: case ISD::FEXP2: { Tmp1 = DAG.getNode(ISD::FP_EXTEND, dl, NVT, Node->getOperand(0)); Tmp2 = DAG.getNode(Node->getOpcode(), dl, NVT, Tmp1); Results.push_back(DAG.getNode(ISD::FP_ROUND, dl, OVT, Tmp2, DAG.getIntPtrConstant(0, dl))); break; } case ISD::BUILD_VECTOR: { MVT EltVT = OVT.getVectorElementType(); MVT NewEltVT = NVT.getVectorElementType(); // Handle bitcasts to a different vector type with the same total bit size // // e.g. v2i64 = build_vector i64:x, i64:y => v4i32 // => // v4i32 = concat_vectors (v2i32 (bitcast i64:x)), (v2i32 (bitcast i64:y)) assert(NVT.isVector() && OVT.getSizeInBits() == NVT.getSizeInBits() && "Invalid promote type for build_vector"); assert(NewEltVT.bitsLT(EltVT) && "not handled"); MVT MidVT = getPromotedVectorElementType(TLI, EltVT, NewEltVT); SmallVector NewOps; for (unsigned I = 0, E = Node->getNumOperands(); I != E; ++I) { SDValue Op = Node->getOperand(I); NewOps.push_back(DAG.getNode(ISD::BITCAST, SDLoc(Op), MidVT, Op)); } SDLoc SL(Node); SDValue Concat = DAG.getNode(ISD::CONCAT_VECTORS, SL, NVT, NewOps); SDValue CvtVec = DAG.getNode(ISD::BITCAST, SL, OVT, Concat); Results.push_back(CvtVec); break; } case ISD::EXTRACT_VECTOR_ELT: { MVT EltVT = OVT.getVectorElementType(); MVT NewEltVT = NVT.getVectorElementType(); // Handle bitcasts to a different vector type with the same total bit size. // // e.g. v2i64 = extract_vector_elt x:v2i64, y:i32 // => // v4i32:castx = bitcast x:v2i64 // // i64 = bitcast // (v2i32 build_vector (i32 (extract_vector_elt castx, (2 * y))), // (i32 (extract_vector_elt castx, (2 * y + 1))) // assert(NVT.isVector() && OVT.getSizeInBits() == NVT.getSizeInBits() && "Invalid promote type for extract_vector_elt"); assert(NewEltVT.bitsLT(EltVT) && "not handled"); MVT MidVT = getPromotedVectorElementType(TLI, EltVT, NewEltVT); unsigned NewEltsPerOldElt = MidVT.getVectorNumElements(); SDValue Idx = Node->getOperand(1); EVT IdxVT = Idx.getValueType(); SDLoc SL(Node); SDValue Factor = DAG.getConstant(NewEltsPerOldElt, SL, IdxVT); SDValue NewBaseIdx = DAG.getNode(ISD::MUL, SL, IdxVT, Idx, Factor); SDValue CastVec = DAG.getNode(ISD::BITCAST, SL, NVT, Node->getOperand(0)); SmallVector NewOps; for (unsigned I = 0; I < NewEltsPerOldElt; ++I) { SDValue IdxOffset = DAG.getConstant(I, SL, IdxVT); SDValue TmpIdx = DAG.getNode(ISD::ADD, SL, IdxVT, NewBaseIdx, IdxOffset); SDValue Elt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, NewEltVT, CastVec, TmpIdx); NewOps.push_back(Elt); } SDValue NewVec = DAG.getNode(ISD::BUILD_VECTOR, SL, MidVT, NewOps); Results.push_back(DAG.getNode(ISD::BITCAST, SL, EltVT, NewVec)); break; } case ISD::INSERT_VECTOR_ELT: { MVT EltVT = OVT.getVectorElementType(); MVT NewEltVT = NVT.getVectorElementType(); // Handle bitcasts to a different vector type with the same total bit size // // e.g. v2i64 = insert_vector_elt x:v2i64, y:i64, z:i32 // => // v4i32:castx = bitcast x:v2i64 // v2i32:casty = bitcast y:i64 // // v2i64 = bitcast // (v4i32 insert_vector_elt // (v4i32 insert_vector_elt v4i32:castx, // (extract_vector_elt casty, 0), 2 * z), // (extract_vector_elt casty, 1), (2 * z + 1)) assert(NVT.isVector() && OVT.getSizeInBits() == NVT.getSizeInBits() && "Invalid promote type for insert_vector_elt"); assert(NewEltVT.bitsLT(EltVT) && "not handled"); MVT MidVT = getPromotedVectorElementType(TLI, EltVT, NewEltVT); unsigned NewEltsPerOldElt = MidVT.getVectorNumElements(); SDValue Val = Node->getOperand(1); SDValue Idx = Node->getOperand(2); EVT IdxVT = Idx.getValueType(); SDLoc SL(Node); SDValue Factor = DAG.getConstant(NewEltsPerOldElt, SDLoc(), IdxVT); SDValue NewBaseIdx = DAG.getNode(ISD::MUL, SL, IdxVT, Idx, Factor); SDValue CastVec = DAG.getNode(ISD::BITCAST, SL, NVT, Node->getOperand(0)); SDValue CastVal = DAG.getNode(ISD::BITCAST, SL, MidVT, Val); SDValue NewVec = CastVec; for (unsigned I = 0; I < NewEltsPerOldElt; ++I) { SDValue IdxOffset = DAG.getConstant(I, SL, IdxVT); SDValue InEltIdx = DAG.getNode(ISD::ADD, SL, IdxVT, NewBaseIdx, IdxOffset); SDValue Elt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, NewEltVT, CastVal, IdxOffset); NewVec = DAG.getNode(ISD::INSERT_VECTOR_ELT, SL, NVT, NewVec, Elt, InEltIdx); } Results.push_back(DAG.getNode(ISD::BITCAST, SL, OVT, NewVec)); break; } case ISD::SCALAR_TO_VECTOR: { MVT EltVT = OVT.getVectorElementType(); MVT NewEltVT = NVT.getVectorElementType(); // Handle bitcasts to different vector type with the smae total bit size. // // e.g. v2i64 = scalar_to_vector x:i64 // => // concat_vectors (v2i32 bitcast x:i64), (v2i32 undef) // MVT MidVT = getPromotedVectorElementType(TLI, EltVT, NewEltVT); SDValue Val = Node->getOperand(0); SDLoc SL(Node); SDValue CastVal = DAG.getNode(ISD::BITCAST, SL, MidVT, Val); SDValue Undef = DAG.getUNDEF(MidVT); SmallVector NewElts; NewElts.push_back(CastVal); for (unsigned I = 1, NElts = OVT.getVectorNumElements(); I != NElts; ++I) NewElts.push_back(Undef); SDValue Concat = DAG.getNode(ISD::CONCAT_VECTORS, SL, NVT, NewElts); SDValue CvtVec = DAG.getNode(ISD::BITCAST, SL, OVT, Concat); Results.push_back(CvtVec); break; } } // Replace the original node with the legalized result. if (!Results.empty()) ReplaceNode(Node, Results.data()); } /// This is the entry point for the file. void SelectionDAG::Legalize() { AssignTopologicalOrder(); SmallPtrSet LegalizedNodes; SelectionDAGLegalize Legalizer(*this, LegalizedNodes); // Visit all the nodes. We start in topological order, so that we see // nodes with their original operands intact. Legalization can produce // new nodes which may themselves need to be legalized. Iterate until all // nodes have been legalized. for (;;) { bool AnyLegalized = false; for (auto NI = allnodes_end(); NI != allnodes_begin();) { --NI; SDNode *N = &*NI; if (N->use_empty() && N != getRoot().getNode()) { ++NI; DeleteNode(N); continue; } if (LegalizedNodes.insert(N).second) { AnyLegalized = true; Legalizer.LegalizeOp(N); if (N->use_empty() && N != getRoot().getNode()) { ++NI; DeleteNode(N); } } } if (!AnyLegalized) break; } // Remove dead nodes now. RemoveDeadNodes(); } bool SelectionDAG::LegalizeOp(SDNode *N, SmallSetVector &UpdatedNodes) { SmallPtrSet LegalizedNodes; SelectionDAGLegalize Legalizer(*this, LegalizedNodes, &UpdatedNodes); // Directly insert the node in question, and legalize it. This will recurse // as needed through operands. LegalizedNodes.insert(N); Legalizer.LegalizeOp(N); return LegalizedNodes.count(N); } Index: projects/clang380-import/contrib/llvm/lib/CodeGen/WinEHPrepare.cpp =================================================================== --- projects/clang380-import/contrib/llvm/lib/CodeGen/WinEHPrepare.cpp (revision 295858) +++ projects/clang380-import/contrib/llvm/lib/CodeGen/WinEHPrepare.cpp (revision 295859) @@ -1,1222 +1,1230 @@ //===-- WinEHPrepare - Prepare exception handling for code generation ---===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This pass lowers LLVM IR exception handling into something closer to what the // backend wants for functions using a personality function from a runtime // provided by MSVC. Functions with other personality functions are left alone // and may be prepared by other passes. In particular, all supported MSVC // personality functions require cleanup code to be outlined, and the C++ // personality requires catch handler code to be outlined. // //===----------------------------------------------------------------------===// #include "llvm/CodeGen/Passes.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Analysis/CFG.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/IR/Verifier.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Pass.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/SSAUpdater.h" using namespace llvm; #define DEBUG_TYPE "winehprepare" static cl::opt DisableDemotion( "disable-demotion", cl::Hidden, cl::desc( "Clone multicolor basic blocks but do not demote cross funclet values"), cl::init(false)); static cl::opt DisableCleanups( "disable-cleanups", cl::Hidden, cl::desc("Do not remove implausible terminators or other similar cleanups"), cl::init(false)); namespace { class WinEHPrepare : public FunctionPass { public: static char ID; // Pass identification, replacement for typeid. WinEHPrepare(const TargetMachine *TM = nullptr) : FunctionPass(ID) {} bool runOnFunction(Function &Fn) override; bool doFinalization(Module &M) override; void getAnalysisUsage(AnalysisUsage &AU) const override; const char *getPassName() const override { return "Windows exception handling preparation"; } private: void insertPHIStores(PHINode *OriginalPHI, AllocaInst *SpillSlot); void insertPHIStore(BasicBlock *PredBlock, Value *PredVal, AllocaInst *SpillSlot, SmallVectorImpl> &Worklist); AllocaInst *insertPHILoads(PHINode *PN, Function &F); void replaceUseWithLoad(Value *V, Use &U, AllocaInst *&SpillSlot, DenseMap &Loads, Function &F); bool prepareExplicitEH(Function &F); void colorFunclets(Function &F); void demotePHIsOnFunclets(Function &F); void cloneCommonBlocks(Function &F); void removeImplausibleInstructions(Function &F); void cleanupPreparedFunclets(Function &F); void verifyPreparedFunclets(Function &F); // All fields are reset by runOnFunction. EHPersonality Personality = EHPersonality::Unknown; DenseMap BlockColors; MapVector> FuncletBlocks; }; } // end anonymous namespace char WinEHPrepare::ID = 0; INITIALIZE_TM_PASS(WinEHPrepare, "winehprepare", "Prepare Windows exceptions", false, false) FunctionPass *llvm::createWinEHPass(const TargetMachine *TM) { return new WinEHPrepare(TM); } bool WinEHPrepare::runOnFunction(Function &Fn) { if (!Fn.hasPersonalityFn()) return false; // Classify the personality to see what kind of preparation we need. Personality = classifyEHPersonality(Fn.getPersonalityFn()); // Do nothing if this is not a funclet-based personality. if (!isFuncletEHPersonality(Personality)) return false; return prepareExplicitEH(Fn); } bool WinEHPrepare::doFinalization(Module &M) { return false; } void WinEHPrepare::getAnalysisUsage(AnalysisUsage &AU) const {} static int addUnwindMapEntry(WinEHFuncInfo &FuncInfo, int ToState, const BasicBlock *BB) { CxxUnwindMapEntry UME; UME.ToState = ToState; UME.Cleanup = BB; FuncInfo.CxxUnwindMap.push_back(UME); return FuncInfo.getLastStateNumber(); } static void addTryBlockMapEntry(WinEHFuncInfo &FuncInfo, int TryLow, int TryHigh, int CatchHigh, ArrayRef Handlers) { WinEHTryBlockMapEntry TBME; TBME.TryLow = TryLow; TBME.TryHigh = TryHigh; TBME.CatchHigh = CatchHigh; assert(TBME.TryLow <= TBME.TryHigh); for (const CatchPadInst *CPI : Handlers) { WinEHHandlerType HT; Constant *TypeInfo = cast(CPI->getArgOperand(0)); if (TypeInfo->isNullValue()) HT.TypeDescriptor = nullptr; else HT.TypeDescriptor = cast(TypeInfo->stripPointerCasts()); HT.Adjectives = cast(CPI->getArgOperand(1))->getZExtValue(); HT.Handler = CPI->getParent(); if (auto *AI = dyn_cast(CPI->getArgOperand(2)->stripPointerCasts())) HT.CatchObj.Alloca = AI; else HT.CatchObj.Alloca = nullptr; TBME.HandlerArray.push_back(HT); } FuncInfo.TryBlockMap.push_back(TBME); } static BasicBlock *getCleanupRetUnwindDest(const CleanupPadInst *CleanupPad) { for (const User *U : CleanupPad->users()) if (const auto *CRI = dyn_cast(U)) return CRI->getUnwindDest(); return nullptr; } static void calculateStateNumbersForInvokes(const Function *Fn, WinEHFuncInfo &FuncInfo) { auto *F = const_cast(Fn); DenseMap BlockColors = colorEHFunclets(*F); for (BasicBlock &BB : *F) { auto *II = dyn_cast(BB.getTerminator()); if (!II) continue; auto &BBColors = BlockColors[&BB]; assert(BBColors.size() == 1 && "multi-color BB not removed by preparation"); BasicBlock *FuncletEntryBB = BBColors.front(); BasicBlock *FuncletUnwindDest; auto *FuncletPad = dyn_cast(FuncletEntryBB->getFirstNonPHI()); assert(FuncletPad || FuncletEntryBB == &Fn->getEntryBlock()); if (!FuncletPad) FuncletUnwindDest = nullptr; else if (auto *CatchPad = dyn_cast(FuncletPad)) FuncletUnwindDest = CatchPad->getCatchSwitch()->getUnwindDest(); else if (auto *CleanupPad = dyn_cast(FuncletPad)) FuncletUnwindDest = getCleanupRetUnwindDest(CleanupPad); else llvm_unreachable("unexpected funclet pad!"); BasicBlock *InvokeUnwindDest = II->getUnwindDest(); int BaseState = -1; if (FuncletUnwindDest == InvokeUnwindDest) { auto BaseStateI = FuncInfo.FuncletBaseStateMap.find(FuncletPad); if (BaseStateI != FuncInfo.FuncletBaseStateMap.end()) BaseState = BaseStateI->second; } if (BaseState != -1) { FuncInfo.InvokeStateMap[II] = BaseState; } else { Instruction *PadInst = InvokeUnwindDest->getFirstNonPHI(); assert(FuncInfo.EHPadStateMap.count(PadInst) && "EH Pad has no state!"); FuncInfo.InvokeStateMap[II] = FuncInfo.EHPadStateMap[PadInst]; } } } // Given BB which ends in an unwind edge, return the EHPad that this BB belongs // to. If the unwind edge came from an invoke, return null. static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB, Value *ParentPad) { const TerminatorInst *TI = BB->getTerminator(); if (isa(TI)) return nullptr; if (auto *CatchSwitch = dyn_cast(TI)) { if (CatchSwitch->getParentPad() != ParentPad) return nullptr; return BB; } assert(!TI->isEHPad() && "unexpected EHPad!"); auto *CleanupPad = cast(TI)->getCleanupPad(); if (CleanupPad->getParentPad() != ParentPad) return nullptr; return CleanupPad->getParent(); } static void calculateCXXStateNumbers(WinEHFuncInfo &FuncInfo, const Instruction *FirstNonPHI, int ParentState) { const BasicBlock *BB = FirstNonPHI->getParent(); assert(BB->isEHPad() && "not a funclet!"); if (auto *CatchSwitch = dyn_cast(FirstNonPHI)) { assert(FuncInfo.EHPadStateMap.count(CatchSwitch) == 0 && "shouldn't revist catch funclets!"); SmallVector Handlers; for (const BasicBlock *CatchPadBB : CatchSwitch->handlers()) { auto *CatchPad = cast(CatchPadBB->getFirstNonPHI()); Handlers.push_back(CatchPad); } int TryLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr); FuncInfo.EHPadStateMap[CatchSwitch] = TryLow; for (const BasicBlock *PredBlock : predecessors(BB)) if ((PredBlock = getEHPadFromPredecessor(PredBlock, CatchSwitch->getParentPad()))) calculateCXXStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(), TryLow); int CatchLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr); // catchpads are separate funclets in C++ EH due to the way rethrow works. int TryHigh = CatchLow - 1; for (const auto *CatchPad : Handlers) { FuncInfo.FuncletBaseStateMap[CatchPad] = CatchLow; for (const User *U : CatchPad->users()) { const auto *UserI = cast(U); if (auto *InnerCatchSwitch = dyn_cast(UserI)) if (InnerCatchSwitch->getUnwindDest() == CatchSwitch->getUnwindDest()) calculateCXXStateNumbers(FuncInfo, UserI, CatchLow); - if (auto *InnerCleanupPad = dyn_cast(UserI)) - if (getCleanupRetUnwindDest(InnerCleanupPad) == - CatchSwitch->getUnwindDest()) + if (auto *InnerCleanupPad = dyn_cast(UserI)) { + BasicBlock *UnwindDest = getCleanupRetUnwindDest(InnerCleanupPad); + // If a nested cleanup pad reports a null unwind destination and the + // enclosing catch pad doesn't it must be post-dominated by an + // unreachable instruction. + if (!UnwindDest || UnwindDest == CatchSwitch->getUnwindDest()) calculateCXXStateNumbers(FuncInfo, UserI, CatchLow); + } } } int CatchHigh = FuncInfo.getLastStateNumber(); addTryBlockMapEntry(FuncInfo, TryLow, TryHigh, CatchHigh, Handlers); DEBUG(dbgs() << "TryLow[" << BB->getName() << "]: " << TryLow << '\n'); DEBUG(dbgs() << "TryHigh[" << BB->getName() << "]: " << TryHigh << '\n'); DEBUG(dbgs() << "CatchHigh[" << BB->getName() << "]: " << CatchHigh << '\n'); } else { auto *CleanupPad = cast(FirstNonPHI); // It's possible for a cleanup to be visited twice: it might have multiple // cleanupret instructions. if (FuncInfo.EHPadStateMap.count(CleanupPad)) return; int CleanupState = addUnwindMapEntry(FuncInfo, ParentState, BB); FuncInfo.EHPadStateMap[CleanupPad] = CleanupState; DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB " << BB->getName() << '\n'); for (const BasicBlock *PredBlock : predecessors(BB)) { if ((PredBlock = getEHPadFromPredecessor(PredBlock, CleanupPad->getParentPad()))) { calculateCXXStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(), CleanupState); } } for (const User *U : CleanupPad->users()) { const auto *UserI = cast(U); if (UserI->isEHPad()) report_fatal_error("Cleanup funclets for the MSVC++ personality cannot " "contain exceptional actions"); } } } static int addSEHExcept(WinEHFuncInfo &FuncInfo, int ParentState, const Function *Filter, const BasicBlock *Handler) { SEHUnwindMapEntry Entry; Entry.ToState = ParentState; Entry.IsFinally = false; Entry.Filter = Filter; Entry.Handler = Handler; FuncInfo.SEHUnwindMap.push_back(Entry); return FuncInfo.SEHUnwindMap.size() - 1; } static int addSEHFinally(WinEHFuncInfo &FuncInfo, int ParentState, const BasicBlock *Handler) { SEHUnwindMapEntry Entry; Entry.ToState = ParentState; Entry.IsFinally = true; Entry.Filter = nullptr; Entry.Handler = Handler; FuncInfo.SEHUnwindMap.push_back(Entry); return FuncInfo.SEHUnwindMap.size() - 1; } static void calculateSEHStateNumbers(WinEHFuncInfo &FuncInfo, const Instruction *FirstNonPHI, int ParentState) { const BasicBlock *BB = FirstNonPHI->getParent(); assert(BB->isEHPad() && "no a funclet!"); if (auto *CatchSwitch = dyn_cast(FirstNonPHI)) { assert(FuncInfo.EHPadStateMap.count(CatchSwitch) == 0 && "shouldn't revist catch funclets!"); // Extract the filter function and the __except basic block and create a // state for them. assert(CatchSwitch->getNumHandlers() == 1 && "SEH doesn't have multiple handlers per __try"); const auto *CatchPad = cast((*CatchSwitch->handler_begin())->getFirstNonPHI()); const BasicBlock *CatchPadBB = CatchPad->getParent(); const Constant *FilterOrNull = cast(CatchPad->getArgOperand(0)->stripPointerCasts()); const Function *Filter = dyn_cast(FilterOrNull); assert((Filter || FilterOrNull->isNullValue()) && "unexpected filter value"); int TryState = addSEHExcept(FuncInfo, ParentState, Filter, CatchPadBB); // Everything in the __try block uses TryState as its parent state. FuncInfo.EHPadStateMap[CatchSwitch] = TryState; DEBUG(dbgs() << "Assigning state #" << TryState << " to BB " << CatchPadBB->getName() << '\n'); for (const BasicBlock *PredBlock : predecessors(BB)) if ((PredBlock = getEHPadFromPredecessor(PredBlock, CatchSwitch->getParentPad()))) calculateSEHStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(), TryState); // Everything in the __except block unwinds to ParentState, just like code // outside the __try. for (const User *U : CatchPad->users()) { const auto *UserI = cast(U); if (auto *InnerCatchSwitch = dyn_cast(UserI)) if (InnerCatchSwitch->getUnwindDest() == CatchSwitch->getUnwindDest()) calculateSEHStateNumbers(FuncInfo, UserI, ParentState); - if (auto *InnerCleanupPad = dyn_cast(UserI)) - if (getCleanupRetUnwindDest(InnerCleanupPad) == - CatchSwitch->getUnwindDest()) + if (auto *InnerCleanupPad = dyn_cast(UserI)) { + BasicBlock *UnwindDest = getCleanupRetUnwindDest(InnerCleanupPad); + // If a nested cleanup pad reports a null unwind destination and the + // enclosing catch pad doesn't it must be post-dominated by an + // unreachable instruction. + if (!UnwindDest || UnwindDest == CatchSwitch->getUnwindDest()) calculateSEHStateNumbers(FuncInfo, UserI, ParentState); + } } } else { auto *CleanupPad = cast(FirstNonPHI); // It's possible for a cleanup to be visited twice: it might have multiple // cleanupret instructions. if (FuncInfo.EHPadStateMap.count(CleanupPad)) return; int CleanupState = addSEHFinally(FuncInfo, ParentState, BB); FuncInfo.EHPadStateMap[CleanupPad] = CleanupState; DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB " << BB->getName() << '\n'); for (const BasicBlock *PredBlock : predecessors(BB)) if ((PredBlock = getEHPadFromPredecessor(PredBlock, CleanupPad->getParentPad()))) calculateSEHStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(), CleanupState); for (const User *U : CleanupPad->users()) { const auto *UserI = cast(U); if (UserI->isEHPad()) report_fatal_error("Cleanup funclets for the SEH personality cannot " "contain exceptional actions"); } } } static bool isTopLevelPadForMSVC(const Instruction *EHPad) { if (auto *CatchSwitch = dyn_cast(EHPad)) return isa(CatchSwitch->getParentPad()) && CatchSwitch->unwindsToCaller(); if (auto *CleanupPad = dyn_cast(EHPad)) return isa(CleanupPad->getParentPad()) && getCleanupRetUnwindDest(CleanupPad) == nullptr; if (isa(EHPad)) return false; llvm_unreachable("unexpected EHPad!"); } void llvm::calculateSEHStateNumbers(const Function *Fn, WinEHFuncInfo &FuncInfo) { // Don't compute state numbers twice. if (!FuncInfo.SEHUnwindMap.empty()) return; for (const BasicBlock &BB : *Fn) { if (!BB.isEHPad()) continue; const Instruction *FirstNonPHI = BB.getFirstNonPHI(); if (!isTopLevelPadForMSVC(FirstNonPHI)) continue; ::calculateSEHStateNumbers(FuncInfo, FirstNonPHI, -1); } calculateStateNumbersForInvokes(Fn, FuncInfo); } void llvm::calculateWinCXXEHStateNumbers(const Function *Fn, WinEHFuncInfo &FuncInfo) { // Return if it's already been done. if (!FuncInfo.EHPadStateMap.empty()) return; for (const BasicBlock &BB : *Fn) { if (!BB.isEHPad()) continue; const Instruction *FirstNonPHI = BB.getFirstNonPHI(); if (!isTopLevelPadForMSVC(FirstNonPHI)) continue; calculateCXXStateNumbers(FuncInfo, FirstNonPHI, -1); } calculateStateNumbersForInvokes(Fn, FuncInfo); } static int addClrEHHandler(WinEHFuncInfo &FuncInfo, int HandlerParentState, int TryParentState, ClrHandlerType HandlerType, uint32_t TypeToken, const BasicBlock *Handler) { ClrEHUnwindMapEntry Entry; Entry.HandlerParentState = HandlerParentState; Entry.TryParentState = TryParentState; Entry.Handler = Handler; Entry.HandlerType = HandlerType; Entry.TypeToken = TypeToken; FuncInfo.ClrEHUnwindMap.push_back(Entry); return FuncInfo.ClrEHUnwindMap.size() - 1; } void llvm::calculateClrEHStateNumbers(const Function *Fn, WinEHFuncInfo &FuncInfo) { // Return if it's already been done. if (!FuncInfo.EHPadStateMap.empty()) return; // This numbering assigns one state number to each catchpad and cleanuppad. // It also computes two tree-like relations over states: // 1) Each state has a "HandlerParentState", which is the state of the next // outer handler enclosing this state's handler (same as nearest ancestor // per the ParentPad linkage on EH pads, but skipping over catchswitches). // 2) Each state has a "TryParentState", which: // a) for a catchpad that's not the last handler on its catchswitch, is // the state of the next catchpad on that catchswitch // b) for all other pads, is the state of the pad whose try region is the // next outer try region enclosing this state's try region. The "try // regions are not present as such in the IR, but will be inferred // based on the placement of invokes and pads which reach each other // by exceptional exits // Catchswitches do not get their own states, but each gets mapped to the // state of its first catchpad. // Step one: walk down from outermost to innermost funclets, assigning each // catchpad and cleanuppad a state number. Add an entry to the // ClrEHUnwindMap for each state, recording its HandlerParentState and // handler attributes. Record the TryParentState as well for each catchpad // that's not the last on its catchswitch, but initialize all other entries' // TryParentStates to a sentinel -1 value that the next pass will update. // Seed a worklist with pads that have no parent. SmallVector, 8> Worklist; for (const BasicBlock &BB : *Fn) { const Instruction *FirstNonPHI = BB.getFirstNonPHI(); const Value *ParentPad; if (const auto *CPI = dyn_cast(FirstNonPHI)) ParentPad = CPI->getParentPad(); else if (const auto *CSI = dyn_cast(FirstNonPHI)) ParentPad = CSI->getParentPad(); else continue; if (isa(ParentPad)) Worklist.emplace_back(FirstNonPHI, -1); } // Use the worklist to visit all pads, from outer to inner. Record // HandlerParentState for all pads. Record TryParentState only for catchpads // that aren't the last on their catchswitch (setting all other entries' // TryParentStates to an initial value of -1). This loop is also responsible // for setting the EHPadStateMap entry for all catchpads, cleanuppads, and // catchswitches. while (!Worklist.empty()) { const Instruction *Pad; int HandlerParentState; std::tie(Pad, HandlerParentState) = Worklist.pop_back_val(); if (const auto *Cleanup = dyn_cast(Pad)) { // Create the entry for this cleanup with the appropriate handler // properties. Finaly and fault handlers are distinguished by arity. ClrHandlerType HandlerType = (Cleanup->getNumArgOperands() ? ClrHandlerType::Fault : ClrHandlerType::Finally); int CleanupState = addClrEHHandler(FuncInfo, HandlerParentState, -1, HandlerType, 0, Pad->getParent()); // Queue any child EH pads on the worklist. for (const User *U : Cleanup->users()) if (const auto *I = dyn_cast(U)) if (I->isEHPad()) Worklist.emplace_back(I, CleanupState); // Remember this pad's state. FuncInfo.EHPadStateMap[Cleanup] = CleanupState; } else { // Walk the handlers of this catchswitch in reverse order since all but // the last need to set the following one as its TryParentState. const auto *CatchSwitch = cast(Pad); int CatchState = -1, FollowerState = -1; SmallVector CatchBlocks(CatchSwitch->handlers()); for (auto CBI = CatchBlocks.rbegin(), CBE = CatchBlocks.rend(); CBI != CBE; ++CBI, FollowerState = CatchState) { const BasicBlock *CatchBlock = *CBI; // Create the entry for this catch with the appropriate handler // properties. const auto *Catch = cast(CatchBlock->getFirstNonPHI()); uint32_t TypeToken = static_cast( cast(Catch->getArgOperand(0))->getZExtValue()); CatchState = addClrEHHandler(FuncInfo, HandlerParentState, FollowerState, ClrHandlerType::Catch, TypeToken, CatchBlock); // Queue any child EH pads on the worklist. for (const User *U : Catch->users()) if (const auto *I = dyn_cast(U)) if (I->isEHPad()) Worklist.emplace_back(I, CatchState); // Remember this catch's state. FuncInfo.EHPadStateMap[Catch] = CatchState; } // Associate the catchswitch with the state of its first catch. assert(CatchSwitch->getNumHandlers()); FuncInfo.EHPadStateMap[CatchSwitch] = CatchState; } } // Step two: record the TryParentState of each state. For cleanuppads that // don't have cleanuprets, we may need to infer this from their child pads, // so visit pads in descendant-most to ancestor-most order. for (auto Entry = FuncInfo.ClrEHUnwindMap.rbegin(), End = FuncInfo.ClrEHUnwindMap.rend(); Entry != End; ++Entry) { const Instruction *Pad = Entry->Handler.get()->getFirstNonPHI(); // For most pads, the TryParentState is the state associated with the // unwind dest of exceptional exits from it. const BasicBlock *UnwindDest; if (const auto *Catch = dyn_cast(Pad)) { // If a catch is not the last in its catchswitch, its TryParentState is // the state associated with the next catch in the switch, even though // that's not the unwind dest of exceptions escaping the catch. Those // cases were already assigned a TryParentState in the first pass, so // skip them. if (Entry->TryParentState != -1) continue; // Otherwise, get the unwind dest from the catchswitch. UnwindDest = Catch->getCatchSwitch()->getUnwindDest(); } else { const auto *Cleanup = cast(Pad); UnwindDest = nullptr; for (const User *U : Cleanup->users()) { if (auto *CleanupRet = dyn_cast(U)) { // Common and unambiguous case -- cleanupret indicates cleanup's // unwind dest. UnwindDest = CleanupRet->getUnwindDest(); break; } // Get an unwind dest for the user const BasicBlock *UserUnwindDest = nullptr; if (auto *Invoke = dyn_cast(U)) { UserUnwindDest = Invoke->getUnwindDest(); } else if (auto *CatchSwitch = dyn_cast(U)) { UserUnwindDest = CatchSwitch->getUnwindDest(); } else if (auto *ChildCleanup = dyn_cast(U)) { int UserState = FuncInfo.EHPadStateMap[ChildCleanup]; int UserUnwindState = FuncInfo.ClrEHUnwindMap[UserState].TryParentState; if (UserUnwindState != -1) UserUnwindDest = FuncInfo.ClrEHUnwindMap[UserUnwindState] .Handler.get(); } // Not having an unwind dest for this user might indicate that it // doesn't unwind, so can't be taken as proof that the cleanup itself // may unwind to caller (see e.g. SimplifyUnreachable and // RemoveUnwindEdge). if (!UserUnwindDest) continue; // Now we have an unwind dest for the user, but we need to see if it // unwinds all the way out of the cleanup or if it stays within it. const Instruction *UserUnwindPad = UserUnwindDest->getFirstNonPHI(); const Value *UserUnwindParent; if (auto *CSI = dyn_cast(UserUnwindPad)) UserUnwindParent = CSI->getParentPad(); else UserUnwindParent = cast(UserUnwindPad)->getParentPad(); // The unwind stays within the cleanup iff it targets a child of the // cleanup. if (UserUnwindParent == Cleanup) continue; // This unwind exits the cleanup, so its dest is the cleanup's dest. UnwindDest = UserUnwindDest; break; } } // Record the state of the unwind dest as the TryParentState. int UnwindDestState; // If UnwindDest is null at this point, either the pad in question can // be exited by unwind to caller, or it cannot be exited by unwind. In // either case, reporting such cases as unwinding to caller is correct. // This can lead to EH tables that "look strange" -- if this pad's is in // a parent funclet which has other children that do unwind to an enclosing // pad, the try region for this pad will be missing the "duplicate" EH // clause entries that you'd expect to see covering the whole parent. That // should be benign, since the unwind never actually happens. If it were // an issue, we could add a subsequent pass that pushes unwind dests down // from parents that have them to children that appear to unwind to caller. if (!UnwindDest) { UnwindDestState = -1; } else { UnwindDestState = FuncInfo.EHPadStateMap[UnwindDest->getFirstNonPHI()]; } Entry->TryParentState = UnwindDestState; } // Step three: transfer information from pads to invokes. calculateStateNumbersForInvokes(Fn, FuncInfo); } void WinEHPrepare::colorFunclets(Function &F) { BlockColors = colorEHFunclets(F); // Invert the map from BB to colors to color to BBs. for (BasicBlock &BB : F) { ColorVector &Colors = BlockColors[&BB]; for (BasicBlock *Color : Colors) FuncletBlocks[Color].push_back(&BB); } } void WinEHPrepare::demotePHIsOnFunclets(Function &F) { // Strip PHI nodes off of EH pads. SmallVector PHINodes; for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE;) { BasicBlock *BB = &*FI++; if (!BB->isEHPad()) continue; for (BasicBlock::iterator BI = BB->begin(), BE = BB->end(); BI != BE;) { Instruction *I = &*BI++; auto *PN = dyn_cast(I); // Stop at the first non-PHI. if (!PN) break; AllocaInst *SpillSlot = insertPHILoads(PN, F); if (SpillSlot) insertPHIStores(PN, SpillSlot); PHINodes.push_back(PN); } } for (auto *PN : PHINodes) { // There may be lingering uses on other EH PHIs being removed PN->replaceAllUsesWith(UndefValue::get(PN->getType())); PN->eraseFromParent(); } } void WinEHPrepare::cloneCommonBlocks(Function &F) { // We need to clone all blocks which belong to multiple funclets. Values are // remapped throughout the funclet to propogate both the new instructions // *and* the new basic blocks themselves. for (auto &Funclets : FuncletBlocks) { BasicBlock *FuncletPadBB = Funclets.first; std::vector &BlocksInFunclet = Funclets.second; Value *FuncletToken; if (FuncletPadBB == &F.getEntryBlock()) FuncletToken = ConstantTokenNone::get(F.getContext()); else FuncletToken = FuncletPadBB->getFirstNonPHI(); std::vector> Orig2Clone; ValueToValueMapTy VMap; for (BasicBlock *BB : BlocksInFunclet) { ColorVector &ColorsForBB = BlockColors[BB]; // We don't need to do anything if the block is monochromatic. size_t NumColorsForBB = ColorsForBB.size(); if (NumColorsForBB == 1) continue; DEBUG_WITH_TYPE("winehprepare-coloring", dbgs() << " Cloning block \'" << BB->getName() << "\' for funclet \'" << FuncletPadBB->getName() << "\'.\n"); // Create a new basic block and copy instructions into it! BasicBlock *CBB = CloneBasicBlock(BB, VMap, Twine(".for.", FuncletPadBB->getName())); // Insert the clone immediately after the original to ensure determinism // and to keep the same relative ordering of any funclet's blocks. CBB->insertInto(&F, BB->getNextNode()); // Add basic block mapping. VMap[BB] = CBB; // Record delta operations that we need to perform to our color mappings. Orig2Clone.emplace_back(BB, CBB); } // If nothing was cloned, we're done cloning in this funclet. if (Orig2Clone.empty()) continue; // Update our color mappings to reflect that one block has lost a color and // another has gained a color. for (auto &BBMapping : Orig2Clone) { BasicBlock *OldBlock = BBMapping.first; BasicBlock *NewBlock = BBMapping.second; BlocksInFunclet.push_back(NewBlock); ColorVector &NewColors = BlockColors[NewBlock]; assert(NewColors.empty() && "A new block should only have one color!"); NewColors.push_back(FuncletPadBB); DEBUG_WITH_TYPE("winehprepare-coloring", dbgs() << " Assigned color \'" << FuncletPadBB->getName() << "\' to block \'" << NewBlock->getName() << "\'.\n"); BlocksInFunclet.erase( std::remove(BlocksInFunclet.begin(), BlocksInFunclet.end(), OldBlock), BlocksInFunclet.end()); ColorVector &OldColors = BlockColors[OldBlock]; OldColors.erase( std::remove(OldColors.begin(), OldColors.end(), FuncletPadBB), OldColors.end()); DEBUG_WITH_TYPE("winehprepare-coloring", dbgs() << " Removed color \'" << FuncletPadBB->getName() << "\' from block \'" << OldBlock->getName() << "\'.\n"); } // Loop over all of the instructions in this funclet, fixing up operand // references as we go. This uses VMap to do all the hard work. for (BasicBlock *BB : BlocksInFunclet) // Loop over all instructions, fixing each one as we find it... for (Instruction &I : *BB) RemapInstruction(&I, VMap, RF_IgnoreMissingEntries | RF_NoModuleLevelChanges); // Catchrets targeting cloned blocks need to be updated separately from // the loop above because they are not in the current funclet. SmallVector FixupCatchrets; for (auto &BBMapping : Orig2Clone) { BasicBlock *OldBlock = BBMapping.first; BasicBlock *NewBlock = BBMapping.second; FixupCatchrets.clear(); for (BasicBlock *Pred : predecessors(OldBlock)) if (auto *CatchRet = dyn_cast(Pred->getTerminator())) if (CatchRet->getParentPad() == FuncletToken) FixupCatchrets.push_back(CatchRet); for (CatchReturnInst *CatchRet : FixupCatchrets) CatchRet->setSuccessor(NewBlock); } auto UpdatePHIOnClonedBlock = [&](PHINode *PN, bool IsForOldBlock) { unsigned NumPreds = PN->getNumIncomingValues(); for (unsigned PredIdx = 0, PredEnd = NumPreds; PredIdx != PredEnd; ++PredIdx) { BasicBlock *IncomingBlock = PN->getIncomingBlock(PredIdx); bool EdgeTargetsFunclet; if (auto *CRI = dyn_cast(IncomingBlock->getTerminator())) { EdgeTargetsFunclet = (CRI->getParentPad() == FuncletToken); } else { ColorVector &IncomingColors = BlockColors[IncomingBlock]; assert(!IncomingColors.empty() && "Block not colored!"); assert((IncomingColors.size() == 1 || llvm::all_of(IncomingColors, [&](BasicBlock *Color) { return Color != FuncletPadBB; })) && "Cloning should leave this funclet's blocks monochromatic"); EdgeTargetsFunclet = (IncomingColors.front() == FuncletPadBB); } if (IsForOldBlock != EdgeTargetsFunclet) continue; PN->removeIncomingValue(IncomingBlock, /*DeletePHIIfEmpty=*/false); // Revisit the next entry. --PredIdx; --PredEnd; } }; for (auto &BBMapping : Orig2Clone) { BasicBlock *OldBlock = BBMapping.first; BasicBlock *NewBlock = BBMapping.second; for (Instruction &OldI : *OldBlock) { auto *OldPN = dyn_cast(&OldI); if (!OldPN) break; UpdatePHIOnClonedBlock(OldPN, /*IsForOldBlock=*/true); } for (Instruction &NewI : *NewBlock) { auto *NewPN = dyn_cast(&NewI); if (!NewPN) break; UpdatePHIOnClonedBlock(NewPN, /*IsForOldBlock=*/false); } } // Check to see if SuccBB has PHI nodes. If so, we need to add entries to // the PHI nodes for NewBB now. for (auto &BBMapping : Orig2Clone) { BasicBlock *OldBlock = BBMapping.first; BasicBlock *NewBlock = BBMapping.second; for (BasicBlock *SuccBB : successors(NewBlock)) { for (Instruction &SuccI : *SuccBB) { auto *SuccPN = dyn_cast(&SuccI); if (!SuccPN) break; // Ok, we have a PHI node. Figure out what the incoming value was for // the OldBlock. int OldBlockIdx = SuccPN->getBasicBlockIndex(OldBlock); if (OldBlockIdx == -1) break; Value *IV = SuccPN->getIncomingValue(OldBlockIdx); // Remap the value if necessary. if (auto *Inst = dyn_cast(IV)) { ValueToValueMapTy::iterator I = VMap.find(Inst); if (I != VMap.end()) IV = I->second; } SuccPN->addIncoming(IV, NewBlock); } } } for (ValueToValueMapTy::value_type VT : VMap) { // If there were values defined in BB that are used outside the funclet, // then we now have to update all uses of the value to use either the // original value, the cloned value, or some PHI derived value. This can // require arbitrary PHI insertion, of which we are prepared to do, clean // these up now. SmallVector UsesToRename; auto *OldI = dyn_cast(const_cast(VT.first)); if (!OldI) continue; auto *NewI = cast(VT.second); // Scan all uses of this instruction to see if it is used outside of its // funclet, and if so, record them in UsesToRename. for (Use &U : OldI->uses()) { Instruction *UserI = cast(U.getUser()); BasicBlock *UserBB = UserI->getParent(); ColorVector &ColorsForUserBB = BlockColors[UserBB]; assert(!ColorsForUserBB.empty()); if (ColorsForUserBB.size() > 1 || *ColorsForUserBB.begin() != FuncletPadBB) UsesToRename.push_back(&U); } // If there are no uses outside the block, we're done with this // instruction. if (UsesToRename.empty()) continue; // We found a use of OldI outside of the funclet. Rename all uses of OldI // that are outside its funclet to be uses of the appropriate PHI node // etc. SSAUpdater SSAUpdate; SSAUpdate.Initialize(OldI->getType(), OldI->getName()); SSAUpdate.AddAvailableValue(OldI->getParent(), OldI); SSAUpdate.AddAvailableValue(NewI->getParent(), NewI); while (!UsesToRename.empty()) SSAUpdate.RewriteUseAfterInsertions(*UsesToRename.pop_back_val()); } } } void WinEHPrepare::removeImplausibleInstructions(Function &F) { // Remove implausible terminators and replace them with UnreachableInst. for (auto &Funclet : FuncletBlocks) { BasicBlock *FuncletPadBB = Funclet.first; std::vector &BlocksInFunclet = Funclet.second; Instruction *FirstNonPHI = FuncletPadBB->getFirstNonPHI(); auto *FuncletPad = dyn_cast(FirstNonPHI); auto *CatchPad = dyn_cast_or_null(FuncletPad); auto *CleanupPad = dyn_cast_or_null(FuncletPad); for (BasicBlock *BB : BlocksInFunclet) { for (Instruction &I : *BB) { CallSite CS(&I); if (!CS) continue; Value *FuncletBundleOperand = nullptr; if (auto BU = CS.getOperandBundle(LLVMContext::OB_funclet)) FuncletBundleOperand = BU->Inputs.front(); if (FuncletBundleOperand == FuncletPad) continue; // Skip call sites which are nounwind intrinsics. auto *CalledFn = dyn_cast(CS.getCalledValue()->stripPointerCasts()); if (CalledFn && CalledFn->isIntrinsic() && CS.doesNotThrow()) continue; // This call site was not part of this funclet, remove it. if (CS.isInvoke()) { // Remove the unwind edge if it was an invoke. removeUnwindEdge(BB); // Get a pointer to the new call. BasicBlock::iterator CallI = std::prev(BB->getTerminator()->getIterator()); auto *CI = cast(&*CallI); changeToUnreachable(CI, /*UseLLVMTrap=*/false); } else { changeToUnreachable(&I, /*UseLLVMTrap=*/false); } // There are no more instructions in the block (except for unreachable), // we are done. break; } TerminatorInst *TI = BB->getTerminator(); // CatchPadInst and CleanupPadInst can't transfer control to a ReturnInst. bool IsUnreachableRet = isa(TI) && FuncletPad; // The token consumed by a CatchReturnInst must match the funclet token. bool IsUnreachableCatchret = false; if (auto *CRI = dyn_cast(TI)) IsUnreachableCatchret = CRI->getCatchPad() != CatchPad; // The token consumed by a CleanupReturnInst must match the funclet token. bool IsUnreachableCleanupret = false; if (auto *CRI = dyn_cast(TI)) IsUnreachableCleanupret = CRI->getCleanupPad() != CleanupPad; if (IsUnreachableRet || IsUnreachableCatchret || IsUnreachableCleanupret) { changeToUnreachable(TI, /*UseLLVMTrap=*/false); } else if (isa(TI)) { if (Personality == EHPersonality::MSVC_CXX && CleanupPad) { // Invokes within a cleanuppad for the MSVC++ personality never // transfer control to their unwind edge: the personality will // terminate the program. removeUnwindEdge(BB); } } } } } void WinEHPrepare::cleanupPreparedFunclets(Function &F) { // Clean-up some of the mess we made by removing useles PHI nodes, trivial // branches, etc. for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE;) { BasicBlock *BB = &*FI++; SimplifyInstructionsInBlock(BB); ConstantFoldTerminator(BB, /*DeleteDeadConditions=*/true); MergeBlockIntoPredecessor(BB); } // We might have some unreachable blocks after cleaning up some impossible // control flow. removeUnreachableBlocks(F); } void WinEHPrepare::verifyPreparedFunclets(Function &F) { for (BasicBlock &BB : F) { size_t NumColors = BlockColors[&BB].size(); assert(NumColors == 1 && "Expected monochromatic BB!"); if (NumColors == 0) report_fatal_error("Uncolored BB!"); if (NumColors > 1) report_fatal_error("Multicolor BB!"); assert((DisableDemotion || !(BB.isEHPad() && isa(BB.begin()))) && "EH Pad still has a PHI!"); } } bool WinEHPrepare::prepareExplicitEH(Function &F) { // Remove unreachable blocks. It is not valuable to assign them a color and // their existence can trick us into thinking values are alive when they are // not. removeUnreachableBlocks(F); // Determine which blocks are reachable from which funclet entries. colorFunclets(F); cloneCommonBlocks(F); if (!DisableDemotion) demotePHIsOnFunclets(F); if (!DisableCleanups) { DEBUG(verifyFunction(F)); removeImplausibleInstructions(F); DEBUG(verifyFunction(F)); cleanupPreparedFunclets(F); } DEBUG(verifyPreparedFunclets(F)); // Recolor the CFG to verify that all is well. DEBUG(colorFunclets(F)); DEBUG(verifyPreparedFunclets(F)); BlockColors.clear(); FuncletBlocks.clear(); return true; } // TODO: Share loads when one use dominates another, or when a catchpad exit // dominates uses (needs dominators). AllocaInst *WinEHPrepare::insertPHILoads(PHINode *PN, Function &F) { BasicBlock *PHIBlock = PN->getParent(); AllocaInst *SpillSlot = nullptr; Instruction *EHPad = PHIBlock->getFirstNonPHI(); if (!isa(EHPad)) { // If the EHPad isn't a terminator, then we can insert a load in this block // that will dominate all uses. SpillSlot = new AllocaInst(PN->getType(), nullptr, Twine(PN->getName(), ".wineh.spillslot"), &F.getEntryBlock().front()); Value *V = new LoadInst(SpillSlot, Twine(PN->getName(), ".wineh.reload"), &*PHIBlock->getFirstInsertionPt()); PN->replaceAllUsesWith(V); return SpillSlot; } // Otherwise, we have a PHI on a terminator EHPad, and we give up and insert // loads of the slot before every use. DenseMap Loads; for (Value::use_iterator UI = PN->use_begin(), UE = PN->use_end(); UI != UE;) { Use &U = *UI++; auto *UsingInst = cast(U.getUser()); if (isa(UsingInst) && UsingInst->getParent()->isEHPad()) { // Use is on an EH pad phi. Leave it alone; we'll insert loads and // stores for it separately. continue; } replaceUseWithLoad(PN, U, SpillSlot, Loads, F); } return SpillSlot; } // TODO: improve store placement. Inserting at def is probably good, but need // to be careful not to introduce interfering stores (needs liveness analysis). // TODO: identify related phi nodes that can share spill slots, and share them // (also needs liveness). void WinEHPrepare::insertPHIStores(PHINode *OriginalPHI, AllocaInst *SpillSlot) { // Use a worklist of (Block, Value) pairs -- the given Value needs to be // stored to the spill slot by the end of the given Block. SmallVector, 4> Worklist; Worklist.push_back({OriginalPHI->getParent(), OriginalPHI}); while (!Worklist.empty()) { BasicBlock *EHBlock; Value *InVal; std::tie(EHBlock, InVal) = Worklist.pop_back_val(); PHINode *PN = dyn_cast(InVal); if (PN && PN->getParent() == EHBlock) { // The value is defined by another PHI we need to remove, with no room to // insert a store after the PHI, so each predecessor needs to store its // incoming value. for (unsigned i = 0, e = PN->getNumIncomingValues(); i < e; ++i) { Value *PredVal = PN->getIncomingValue(i); // Undef can safely be skipped. if (isa(PredVal)) continue; insertPHIStore(PN->getIncomingBlock(i), PredVal, SpillSlot, Worklist); } } else { // We need to store InVal, which dominates EHBlock, but can't put a store // in EHBlock, so need to put stores in each predecessor. for (BasicBlock *PredBlock : predecessors(EHBlock)) { insertPHIStore(PredBlock, InVal, SpillSlot, Worklist); } } } } void WinEHPrepare::insertPHIStore( BasicBlock *PredBlock, Value *PredVal, AllocaInst *SpillSlot, SmallVectorImpl> &Worklist) { if (PredBlock->isEHPad() && isa(PredBlock->getFirstNonPHI())) { // Pred is unsplittable, so we need to queue it on the worklist. Worklist.push_back({PredBlock, PredVal}); return; } // Otherwise, insert the store at the end of the basic block. new StoreInst(PredVal, SpillSlot, PredBlock->getTerminator()); } void WinEHPrepare::replaceUseWithLoad(Value *V, Use &U, AllocaInst *&SpillSlot, DenseMap &Loads, Function &F) { // Lazilly create the spill slot. if (!SpillSlot) SpillSlot = new AllocaInst(V->getType(), nullptr, Twine(V->getName(), ".wineh.spillslot"), &F.getEntryBlock().front()); auto *UsingInst = cast(U.getUser()); if (auto *UsingPHI = dyn_cast(UsingInst)) { // If this is a PHI node, we can't insert a load of the value before // the use. Instead insert the load in the predecessor block // corresponding to the incoming value. // // Note that if there are multiple edges from a basic block to this // PHI node that we cannot have multiple loads. The problem is that // the resulting PHI node will have multiple values (from each load) // coming in from the same block, which is illegal SSA form. // For this reason, we keep track of and reuse loads we insert. BasicBlock *IncomingBlock = UsingPHI->getIncomingBlock(U); if (auto *CatchRet = dyn_cast(IncomingBlock->getTerminator())) { // Putting a load above a catchret and use on the phi would still leave // a cross-funclet def/use. We need to split the edge, change the // catchret to target the new block, and put the load there. BasicBlock *PHIBlock = UsingInst->getParent(); BasicBlock *NewBlock = SplitEdge(IncomingBlock, PHIBlock); // SplitEdge gives us: // IncomingBlock: // ... // br label %NewBlock // NewBlock: // catchret label %PHIBlock // But we need: // IncomingBlock: // ... // catchret label %NewBlock // NewBlock: // br label %PHIBlock // So move the terminators to each others' blocks and swap their // successors. BranchInst *Goto = cast(IncomingBlock->getTerminator()); Goto->removeFromParent(); CatchRet->removeFromParent(); IncomingBlock->getInstList().push_back(CatchRet); NewBlock->getInstList().push_back(Goto); Goto->setSuccessor(0, PHIBlock); CatchRet->setSuccessor(NewBlock); // Update the color mapping for the newly split edge. ColorVector &ColorsForPHIBlock = BlockColors[PHIBlock]; BlockColors[NewBlock] = ColorsForPHIBlock; for (BasicBlock *FuncletPad : ColorsForPHIBlock) FuncletBlocks[FuncletPad].push_back(NewBlock); // Treat the new block as incoming for load insertion. IncomingBlock = NewBlock; } Value *&Load = Loads[IncomingBlock]; // Insert the load into the predecessor block if (!Load) Load = new LoadInst(SpillSlot, Twine(V->getName(), ".wineh.reload"), /*Volatile=*/false, IncomingBlock->getTerminator()); U.set(Load); } else { // Reload right before the old use. auto *Load = new LoadInst(SpillSlot, Twine(V->getName(), ".wineh.reload"), /*Volatile=*/false, UsingInst); U.set(Load); } } void WinEHFuncInfo::addIPToStateRange(const InvokeInst *II, MCSymbol *InvokeBegin, MCSymbol *InvokeEnd) { assert(InvokeStateMap.count(II) && "should get invoke with precomputed state"); LabelToStateMap[InvokeBegin] = std::make_pair(InvokeStateMap[II], InvokeEnd); } WinEHFuncInfo::WinEHFuncInfo() {} Index: projects/clang380-import/contrib/llvm/lib/Support/Triple.cpp =================================================================== --- projects/clang380-import/contrib/llvm/lib/Support/Triple.cpp (revision 295858) +++ projects/clang380-import/contrib/llvm/lib/Support/Triple.cpp (revision 295859) @@ -1,1441 +1,1441 @@ //===--- Triple.cpp - Target triple helper class --------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/ADT/Triple.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TargetParser.h" #include "llvm/Support/Host.h" #include using namespace llvm; const char *Triple::getArchTypeName(ArchType Kind) { switch (Kind) { case UnknownArch: return "unknown"; case aarch64: return "aarch64"; case aarch64_be: return "aarch64_be"; case arm: return "arm"; case armeb: return "armeb"; case avr: return "avr"; case bpfel: return "bpfel"; case bpfeb: return "bpfeb"; case hexagon: return "hexagon"; case mips: return "mips"; case mipsel: return "mipsel"; case mips64: return "mips64"; case mips64el: return "mips64el"; case msp430: return "msp430"; case ppc64: return "powerpc64"; case ppc64le: return "powerpc64le"; case ppc: return "powerpc"; case r600: return "r600"; case amdgcn: return "amdgcn"; case sparc: return "sparc"; case sparcv9: return "sparcv9"; case sparcel: return "sparcel"; case systemz: return "s390x"; case tce: return "tce"; case thumb: return "thumb"; case thumbeb: return "thumbeb"; case x86: return "i386"; case x86_64: return "x86_64"; case xcore: return "xcore"; case nvptx: return "nvptx"; case nvptx64: return "nvptx64"; case le32: return "le32"; case le64: return "le64"; case amdil: return "amdil"; case amdil64: return "amdil64"; case hsail: return "hsail"; case hsail64: return "hsail64"; case spir: return "spir"; case spir64: return "spir64"; case kalimba: return "kalimba"; case shave: return "shave"; case wasm32: return "wasm32"; case wasm64: return "wasm64"; } llvm_unreachable("Invalid ArchType!"); } const char *Triple::getArchTypePrefix(ArchType Kind) { switch (Kind) { default: return nullptr; case aarch64: case aarch64_be: return "aarch64"; case arm: case armeb: case thumb: case thumbeb: return "arm"; case avr: return "avr"; case ppc64: case ppc64le: case ppc: return "ppc"; case mips: case mipsel: case mips64: case mips64el: return "mips"; case hexagon: return "hexagon"; case amdgcn: case r600: return "amdgpu"; case bpfel: case bpfeb: return "bpf"; case sparcv9: case sparcel: case sparc: return "sparc"; case systemz: return "s390"; case x86: case x86_64: return "x86"; case xcore: return "xcore"; case nvptx: return "nvptx"; case nvptx64: return "nvptx"; case le32: return "le32"; case le64: return "le64"; case amdil: case amdil64: return "amdil"; case hsail: case hsail64: return "hsail"; case spir: case spir64: return "spir"; case kalimba: return "kalimba"; case shave: return "shave"; case wasm32: case wasm64: return "wasm"; } } const char *Triple::getVendorTypeName(VendorType Kind) { switch (Kind) { case UnknownVendor: return "unknown"; case Apple: return "apple"; case PC: return "pc"; case SCEI: return "scei"; case BGP: return "bgp"; case BGQ: return "bgq"; case Freescale: return "fsl"; case IBM: return "ibm"; case ImaginationTechnologies: return "img"; case MipsTechnologies: return "mti"; case NVIDIA: return "nvidia"; case CSR: return "csr"; case Myriad: return "myriad"; } llvm_unreachable("Invalid VendorType!"); } const char *Triple::getOSTypeName(OSType Kind) { switch (Kind) { case UnknownOS: return "unknown"; case CloudABI: return "cloudabi"; case Darwin: return "darwin"; case DragonFly: return "dragonfly"; case FreeBSD: return "freebsd"; case IOS: return "ios"; case KFreeBSD: return "kfreebsd"; case Linux: return "linux"; case Lv2: return "lv2"; case MacOSX: return "macosx"; case NetBSD: return "netbsd"; case OpenBSD: return "openbsd"; case Solaris: return "solaris"; case Win32: return "windows"; case Haiku: return "haiku"; case Minix: return "minix"; case RTEMS: return "rtems"; case NaCl: return "nacl"; case CNK: return "cnk"; case Bitrig: return "bitrig"; case AIX: return "aix"; case CUDA: return "cuda"; case NVCL: return "nvcl"; case AMDHSA: return "amdhsa"; case PS4: return "ps4"; case ELFIAMCU: return "elfiamcu"; case TvOS: return "tvos"; case WatchOS: return "watchos"; } llvm_unreachable("Invalid OSType"); } const char *Triple::getEnvironmentTypeName(EnvironmentType Kind) { switch (Kind) { case UnknownEnvironment: return "unknown"; case GNU: return "gnu"; case GNUEABIHF: return "gnueabihf"; case GNUEABI: return "gnueabi"; case GNUX32: return "gnux32"; case CODE16: return "code16"; case EABI: return "eabi"; case EABIHF: return "eabihf"; case Android: return "android"; case MSVC: return "msvc"; case Itanium: return "itanium"; case Cygnus: return "cygnus"; case AMDOpenCL: return "amdopencl"; case CoreCLR: return "coreclr"; } llvm_unreachable("Invalid EnvironmentType!"); } static Triple::ArchType parseBPFArch(StringRef ArchName) { if (ArchName.equals("bpf")) { if (sys::IsLittleEndianHost) return Triple::bpfel; else return Triple::bpfeb; } else if (ArchName.equals("bpf_be") || ArchName.equals("bpfeb")) { return Triple::bpfeb; } else if (ArchName.equals("bpf_le") || ArchName.equals("bpfel")) { return Triple::bpfel; } else { return Triple::UnknownArch; } } Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { Triple::ArchType BPFArch(parseBPFArch(Name)); return StringSwitch(Name) .Case("aarch64", aarch64) .Case("aarch64_be", aarch64_be) .Case("arm64", aarch64) // "arm64" is an alias for "aarch64" .Case("arm", arm) .Case("armeb", armeb) .Case("avr", avr) .StartsWith("bpf", BPFArch) .Case("mips", mips) .Case("mipsel", mipsel) .Case("mips64", mips64) .Case("mips64el", mips64el) .Case("msp430", msp430) .Case("ppc64", ppc64) .Case("ppc32", ppc) .Case("ppc", ppc) .Case("ppc64le", ppc64le) .Case("r600", r600) .Case("amdgcn", amdgcn) .Case("hexagon", hexagon) .Case("sparc", sparc) .Case("sparcel", sparcel) .Case("sparcv9", sparcv9) .Case("systemz", systemz) .Case("tce", tce) .Case("thumb", thumb) .Case("thumbeb", thumbeb) .Case("x86", x86) .Case("x86-64", x86_64) .Case("xcore", xcore) .Case("nvptx", nvptx) .Case("nvptx64", nvptx64) .Case("le32", le32) .Case("le64", le64) .Case("amdil", amdil) .Case("amdil64", amdil64) .Case("hsail", hsail) .Case("hsail64", hsail64) .Case("spir", spir) .Case("spir64", spir64) .Case("kalimba", kalimba) .Case("shave", shave) .Case("wasm32", wasm32) .Case("wasm64", wasm64) .Default(UnknownArch); } static Triple::ArchType parseARMArch(StringRef ArchName) { unsigned ISA = ARM::parseArchISA(ArchName); unsigned ENDIAN = ARM::parseArchEndian(ArchName); Triple::ArchType arch = Triple::UnknownArch; switch (ENDIAN) { case ARM::EK_LITTLE: { switch (ISA) { case ARM::IK_ARM: arch = Triple::arm; break; case ARM::IK_THUMB: arch = Triple::thumb; break; case ARM::IK_AARCH64: arch = Triple::aarch64; break; } break; } case ARM::EK_BIG: { switch (ISA) { case ARM::IK_ARM: arch = Triple::armeb; break; case ARM::IK_THUMB: arch = Triple::thumbeb; break; case ARM::IK_AARCH64: arch = Triple::aarch64_be; break; } break; } } ArchName = ARM::getCanonicalArchName(ArchName); if (ArchName.empty()) return Triple::UnknownArch; // Thumb only exists in v4+ if (ISA == ARM::IK_THUMB && (ArchName.startswith("v2") || ArchName.startswith("v3"))) return Triple::UnknownArch; // Thumb only for v6m unsigned Profile = ARM::parseArchProfile(ArchName); unsigned Version = ARM::parseArchVersion(ArchName); if (Profile == ARM::PK_M && Version == 6) { if (ENDIAN == ARM::EK_BIG) return Triple::thumbeb; else return Triple::thumb; } return arch; } static Triple::ArchType parseArch(StringRef ArchName) { auto AT = StringSwitch(ArchName) .Cases("i386", "i486", "i586", "i686", Triple::x86) // FIXME: Do we need to support these? .Cases("i786", "i886", "i986", Triple::x86) .Cases("amd64", "x86_64", "x86_64h", Triple::x86_64) - .Case("powerpc", Triple::ppc) - .Cases("powerpc64", "ppu", Triple::ppc64) - .Case("powerpc64le", Triple::ppc64le) + .Cases("powerpc", "ppc32", Triple::ppc) + .Cases("powerpc64", "ppu", "ppc64", Triple::ppc64) + .Cases("powerpc64le", "ppc64le", Triple::ppc64le) .Case("xscale", Triple::arm) .Case("xscaleeb", Triple::armeb) .Case("aarch64", Triple::aarch64) .Case("aarch64_be", Triple::aarch64_be) .Case("arm64", Triple::aarch64) .Case("arm", Triple::arm) .Case("armeb", Triple::armeb) .Case("thumb", Triple::thumb) .Case("thumbeb", Triple::thumbeb) .Case("avr", Triple::avr) .Case("msp430", Triple::msp430) .Cases("mips", "mipseb", "mipsallegrex", Triple::mips) .Cases("mipsel", "mipsallegrexel", Triple::mipsel) .Cases("mips64", "mips64eb", Triple::mips64) .Case("mips64el", Triple::mips64el) .Case("r600", Triple::r600) .Case("amdgcn", Triple::amdgcn) .Case("hexagon", Triple::hexagon) - .Case("s390x", Triple::systemz) + .Cases("s390x", "systemz", Triple::systemz) .Case("sparc", Triple::sparc) .Case("sparcel", Triple::sparcel) .Cases("sparcv9", "sparc64", Triple::sparcv9) .Case("tce", Triple::tce) .Case("xcore", Triple::xcore) .Case("nvptx", Triple::nvptx) .Case("nvptx64", Triple::nvptx64) .Case("le32", Triple::le32) .Case("le64", Triple::le64) .Case("amdil", Triple::amdil) .Case("amdil64", Triple::amdil64) .Case("hsail", Triple::hsail) .Case("hsail64", Triple::hsail64) .Case("spir", Triple::spir) .Case("spir64", Triple::spir64) .StartsWith("kalimba", Triple::kalimba) .Case("shave", Triple::shave) .Case("wasm32", Triple::wasm32) .Case("wasm64", Triple::wasm64) .Default(Triple::UnknownArch); // Some architectures require special parsing logic just to compute the // ArchType result. if (AT == Triple::UnknownArch) { if (ArchName.startswith("arm") || ArchName.startswith("thumb") || ArchName.startswith("aarch64")) return parseARMArch(ArchName); if (ArchName.startswith("bpf")) return parseBPFArch(ArchName); } return AT; } static Triple::VendorType parseVendor(StringRef VendorName) { return StringSwitch(VendorName) .Case("apple", Triple::Apple) .Case("pc", Triple::PC) .Case("scei", Triple::SCEI) .Case("bgp", Triple::BGP) .Case("bgq", Triple::BGQ) .Case("fsl", Triple::Freescale) .Case("ibm", Triple::IBM) .Case("img", Triple::ImaginationTechnologies) .Case("mti", Triple::MipsTechnologies) .Case("nvidia", Triple::NVIDIA) .Case("csr", Triple::CSR) .Case("myriad", Triple::Myriad) .Default(Triple::UnknownVendor); } static Triple::OSType parseOS(StringRef OSName) { return StringSwitch(OSName) .StartsWith("cloudabi", Triple::CloudABI) .StartsWith("darwin", Triple::Darwin) .StartsWith("dragonfly", Triple::DragonFly) .StartsWith("freebsd", Triple::FreeBSD) .StartsWith("ios", Triple::IOS) .StartsWith("kfreebsd", Triple::KFreeBSD) .StartsWith("linux", Triple::Linux) .StartsWith("lv2", Triple::Lv2) .StartsWith("macosx", Triple::MacOSX) .StartsWith("netbsd", Triple::NetBSD) .StartsWith("openbsd", Triple::OpenBSD) .StartsWith("solaris", Triple::Solaris) .StartsWith("win32", Triple::Win32) .StartsWith("windows", Triple::Win32) .StartsWith("haiku", Triple::Haiku) .StartsWith("minix", Triple::Minix) .StartsWith("rtems", Triple::RTEMS) .StartsWith("nacl", Triple::NaCl) .StartsWith("cnk", Triple::CNK) .StartsWith("bitrig", Triple::Bitrig) .StartsWith("aix", Triple::AIX) .StartsWith("cuda", Triple::CUDA) .StartsWith("nvcl", Triple::NVCL) .StartsWith("amdhsa", Triple::AMDHSA) .StartsWith("ps4", Triple::PS4) .StartsWith("elfiamcu", Triple::ELFIAMCU) .StartsWith("tvos", Triple::TvOS) .StartsWith("watchos", Triple::WatchOS) .Default(Triple::UnknownOS); } static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) { return StringSwitch(EnvironmentName) .StartsWith("eabihf", Triple::EABIHF) .StartsWith("eabi", Triple::EABI) .StartsWith("gnueabihf", Triple::GNUEABIHF) .StartsWith("gnueabi", Triple::GNUEABI) .StartsWith("gnux32", Triple::GNUX32) .StartsWith("code16", Triple::CODE16) .StartsWith("gnu", Triple::GNU) .StartsWith("android", Triple::Android) .StartsWith("msvc", Triple::MSVC) .StartsWith("itanium", Triple::Itanium) .StartsWith("cygnus", Triple::Cygnus) .StartsWith("amdopencl", Triple::AMDOpenCL) .StartsWith("coreclr", Triple::CoreCLR) .Default(Triple::UnknownEnvironment); } static Triple::ObjectFormatType parseFormat(StringRef EnvironmentName) { return StringSwitch(EnvironmentName) .EndsWith("coff", Triple::COFF) .EndsWith("elf", Triple::ELF) .EndsWith("macho", Triple::MachO) .Default(Triple::UnknownObjectFormat); } static Triple::SubArchType parseSubArch(StringRef SubArchName) { StringRef ARMSubArch = ARM::getCanonicalArchName(SubArchName); // For now, this is the small part. Early return. if (ARMSubArch.empty()) return StringSwitch(SubArchName) .EndsWith("kalimba3", Triple::KalimbaSubArch_v3) .EndsWith("kalimba4", Triple::KalimbaSubArch_v4) .EndsWith("kalimba5", Triple::KalimbaSubArch_v5) .Default(Triple::NoSubArch); // ARM sub arch. switch(ARM::parseArch(ARMSubArch)) { case ARM::AK_ARMV4: return Triple::NoSubArch; case ARM::AK_ARMV4T: return Triple::ARMSubArch_v4t; case ARM::AK_ARMV5T: return Triple::ARMSubArch_v5; case ARM::AK_ARMV5TE: case ARM::AK_IWMMXT: case ARM::AK_IWMMXT2: case ARM::AK_XSCALE: case ARM::AK_ARMV5TEJ: return Triple::ARMSubArch_v5te; case ARM::AK_ARMV6: return Triple::ARMSubArch_v6; case ARM::AK_ARMV6K: case ARM::AK_ARMV6KZ: return Triple::ARMSubArch_v6k; case ARM::AK_ARMV6T2: return Triple::ARMSubArch_v6t2; case ARM::AK_ARMV6M: return Triple::ARMSubArch_v6m; case ARM::AK_ARMV7A: case ARM::AK_ARMV7R: return Triple::ARMSubArch_v7; case ARM::AK_ARMV7K: return Triple::ARMSubArch_v7k; case ARM::AK_ARMV7M: return Triple::ARMSubArch_v7m; case ARM::AK_ARMV7S: return Triple::ARMSubArch_v7s; case ARM::AK_ARMV7EM: return Triple::ARMSubArch_v7em; case ARM::AK_ARMV8A: return Triple::ARMSubArch_v8; case ARM::AK_ARMV8_1A: return Triple::ARMSubArch_v8_1a; case ARM::AK_ARMV8_2A: return Triple::ARMSubArch_v8_2a; default: return Triple::NoSubArch; } } static const char *getObjectFormatTypeName(Triple::ObjectFormatType Kind) { switch (Kind) { case Triple::UnknownObjectFormat: return ""; case Triple::COFF: return "coff"; case Triple::ELF: return "elf"; case Triple::MachO: return "macho"; } llvm_unreachable("unknown object format type"); } static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { switch (T.getArch()) { case Triple::UnknownArch: case Triple::aarch64: case Triple::arm: case Triple::thumb: case Triple::x86: case Triple::x86_64: if (T.isOSDarwin()) return Triple::MachO; else if (T.isOSWindows()) return Triple::COFF; return Triple::ELF; case Triple::aarch64_be: case Triple::amdgcn: case Triple::amdil: case Triple::amdil64: case Triple::armeb: case Triple::avr: case Triple::bpfeb: case Triple::bpfel: case Triple::hexagon: case Triple::hsail: case Triple::hsail64: case Triple::kalimba: case Triple::le32: case Triple::le64: case Triple::mips: case Triple::mips64: case Triple::mips64el: case Triple::mipsel: case Triple::msp430: case Triple::nvptx: case Triple::nvptx64: case Triple::ppc64le: case Triple::r600: case Triple::shave: case Triple::sparc: case Triple::sparcel: case Triple::sparcv9: case Triple::spir: case Triple::spir64: case Triple::systemz: case Triple::tce: case Triple::thumbeb: case Triple::wasm32: case Triple::wasm64: case Triple::xcore: return Triple::ELF; case Triple::ppc: case Triple::ppc64: if (T.isOSDarwin()) return Triple::MachO; return Triple::ELF; } llvm_unreachable("unknown architecture"); } /// \brief Construct a triple from the string representation provided. /// /// This stores the string representation and parses the various pieces into /// enum members. Triple::Triple(const Twine &Str) : Data(Str.str()), Arch(UnknownArch), SubArch(NoSubArch), Vendor(UnknownVendor), OS(UnknownOS), Environment(UnknownEnvironment), ObjectFormat(UnknownObjectFormat) { // Do minimal parsing by hand here. SmallVector Components; StringRef(Data).split(Components, '-', /*MaxSplit*/ 3); if (Components.size() > 0) { Arch = parseArch(Components[0]); SubArch = parseSubArch(Components[0]); if (Components.size() > 1) { Vendor = parseVendor(Components[1]); if (Components.size() > 2) { OS = parseOS(Components[2]); if (Components.size() > 3) { Environment = parseEnvironment(Components[3]); ObjectFormat = parseFormat(Components[3]); } } } } if (ObjectFormat == UnknownObjectFormat) ObjectFormat = getDefaultFormat(*this); } /// \brief Construct a triple from string representations of the architecture, /// vendor, and OS. /// /// This joins each argument into a canonical string representation and parses /// them into enum members. It leaves the environment unknown and omits it from /// the string representation. Triple::Triple(const Twine &ArchStr, const Twine &VendorStr, const Twine &OSStr) : Data((ArchStr + Twine('-') + VendorStr + Twine('-') + OSStr).str()), Arch(parseArch(ArchStr.str())), SubArch(parseSubArch(ArchStr.str())), Vendor(parseVendor(VendorStr.str())), OS(parseOS(OSStr.str())), Environment(), ObjectFormat(Triple::UnknownObjectFormat) { ObjectFormat = getDefaultFormat(*this); } /// \brief Construct a triple from string representations of the architecture, /// vendor, OS, and environment. /// /// This joins each argument into a canonical string representation and parses /// them into enum members. Triple::Triple(const Twine &ArchStr, const Twine &VendorStr, const Twine &OSStr, const Twine &EnvironmentStr) : Data((ArchStr + Twine('-') + VendorStr + Twine('-') + OSStr + Twine('-') + EnvironmentStr).str()), Arch(parseArch(ArchStr.str())), SubArch(parseSubArch(ArchStr.str())), Vendor(parseVendor(VendorStr.str())), OS(parseOS(OSStr.str())), Environment(parseEnvironment(EnvironmentStr.str())), ObjectFormat(parseFormat(EnvironmentStr.str())) { if (ObjectFormat == Triple::UnknownObjectFormat) ObjectFormat = getDefaultFormat(*this); } std::string Triple::normalize(StringRef Str) { bool IsMinGW32 = false; bool IsCygwin = false; // Parse into components. SmallVector Components; Str.split(Components, '-'); // If the first component corresponds to a known architecture, preferentially // use it for the architecture. If the second component corresponds to a // known vendor, preferentially use it for the vendor, etc. This avoids silly // component movement when a component parses as (eg) both a valid arch and a // valid os. ArchType Arch = UnknownArch; if (Components.size() > 0) Arch = parseArch(Components[0]); VendorType Vendor = UnknownVendor; if (Components.size() > 1) Vendor = parseVendor(Components[1]); OSType OS = UnknownOS; if (Components.size() > 2) { OS = parseOS(Components[2]); IsCygwin = Components[2].startswith("cygwin"); IsMinGW32 = Components[2].startswith("mingw"); } EnvironmentType Environment = UnknownEnvironment; if (Components.size() > 3) Environment = parseEnvironment(Components[3]); ObjectFormatType ObjectFormat = UnknownObjectFormat; if (Components.size() > 4) ObjectFormat = parseFormat(Components[4]); // Note which components are already in their final position. These will not // be moved. bool Found[4]; Found[0] = Arch != UnknownArch; Found[1] = Vendor != UnknownVendor; Found[2] = OS != UnknownOS; Found[3] = Environment != UnknownEnvironment; // If they are not there already, permute the components into their canonical // positions by seeing if they parse as a valid architecture, and if so moving // the component to the architecture position etc. for (unsigned Pos = 0; Pos != array_lengthof(Found); ++Pos) { if (Found[Pos]) continue; // Already in the canonical position. for (unsigned Idx = 0; Idx != Components.size(); ++Idx) { // Do not reparse any components that already matched. if (Idx < array_lengthof(Found) && Found[Idx]) continue; // Does this component parse as valid for the target position? bool Valid = false; StringRef Comp = Components[Idx]; switch (Pos) { default: llvm_unreachable("unexpected component type!"); case 0: Arch = parseArch(Comp); Valid = Arch != UnknownArch; break; case 1: Vendor = parseVendor(Comp); Valid = Vendor != UnknownVendor; break; case 2: OS = parseOS(Comp); IsCygwin = Comp.startswith("cygwin"); IsMinGW32 = Comp.startswith("mingw"); Valid = OS != UnknownOS || IsCygwin || IsMinGW32; break; case 3: Environment = parseEnvironment(Comp); Valid = Environment != UnknownEnvironment; if (!Valid) { ObjectFormat = parseFormat(Comp); Valid = ObjectFormat != UnknownObjectFormat; } break; } if (!Valid) continue; // Nope, try the next component. // Move the component to the target position, pushing any non-fixed // components that are in the way to the right. This tends to give // good results in the common cases of a forgotten vendor component // or a wrongly positioned environment. if (Pos < Idx) { // Insert left, pushing the existing components to the right. For // example, a-b-i386 -> i386-a-b when moving i386 to the front. StringRef CurrentComponent(""); // The empty component. // Replace the component we are moving with an empty component. std::swap(CurrentComponent, Components[Idx]); // Insert the component being moved at Pos, displacing any existing // components to the right. for (unsigned i = Pos; !CurrentComponent.empty(); ++i) { // Skip over any fixed components. while (i < array_lengthof(Found) && Found[i]) ++i; // Place the component at the new position, getting the component // that was at this position - it will be moved right. std::swap(CurrentComponent, Components[i]); } } else if (Pos > Idx) { // Push right by inserting empty components until the component at Idx // reaches the target position Pos. For example, pc-a -> -pc-a when // moving pc to the second position. do { // Insert one empty component at Idx. StringRef CurrentComponent(""); // The empty component. for (unsigned i = Idx; i < Components.size();) { // Place the component at the new position, getting the component // that was at this position - it will be moved right. std::swap(CurrentComponent, Components[i]); // If it was placed on top of an empty component then we are done. if (CurrentComponent.empty()) break; // Advance to the next component, skipping any fixed components. while (++i < array_lengthof(Found) && Found[i]) ; } // The last component was pushed off the end - append it. if (!CurrentComponent.empty()) Components.push_back(CurrentComponent); // Advance Idx to the component's new position. while (++Idx < array_lengthof(Found) && Found[Idx]) ; } while (Idx < Pos); // Add more until the final position is reached. } assert(Pos < Components.size() && Components[Pos] == Comp && "Component moved wrong!"); Found[Pos] = true; break; } } // Special case logic goes here. At this point Arch, Vendor and OS have the // correct values for the computed components. std::string NormalizedEnvironment; if (Environment == Triple::Android && Components[3].startswith("androideabi")) { StringRef AndroidVersion = Components[3].drop_front(strlen("androideabi")); if (AndroidVersion.empty()) { Components[3] = "android"; } else { NormalizedEnvironment = Twine("android", AndroidVersion).str(); Components[3] = NormalizedEnvironment; } } if (OS == Triple::Win32) { Components.resize(4); Components[2] = "windows"; if (Environment == UnknownEnvironment) { if (ObjectFormat == UnknownObjectFormat || ObjectFormat == Triple::COFF) Components[3] = "msvc"; else Components[3] = getObjectFormatTypeName(ObjectFormat); } } else if (IsMinGW32) { Components.resize(4); Components[2] = "windows"; Components[3] = "gnu"; } else if (IsCygwin) { Components.resize(4); Components[2] = "windows"; Components[3] = "cygnus"; } if (IsMinGW32 || IsCygwin || (OS == Triple::Win32 && Environment != UnknownEnvironment)) { if (ObjectFormat != UnknownObjectFormat && ObjectFormat != Triple::COFF) { Components.resize(5); Components[4] = getObjectFormatTypeName(ObjectFormat); } } // Stick the corrected components back together to form the normalized string. std::string Normalized; for (unsigned i = 0, e = Components.size(); i != e; ++i) { if (i) Normalized += '-'; Normalized += Components[i]; } return Normalized; } StringRef Triple::getArchName() const { return StringRef(Data).split('-').first; // Isolate first component } StringRef Triple::getVendorName() const { StringRef Tmp = StringRef(Data).split('-').second; // Strip first component return Tmp.split('-').first; // Isolate second component } StringRef Triple::getOSName() const { StringRef Tmp = StringRef(Data).split('-').second; // Strip first component Tmp = Tmp.split('-').second; // Strip second component return Tmp.split('-').first; // Isolate third component } StringRef Triple::getEnvironmentName() const { StringRef Tmp = StringRef(Data).split('-').second; // Strip first component Tmp = Tmp.split('-').second; // Strip second component return Tmp.split('-').second; // Strip third component } StringRef Triple::getOSAndEnvironmentName() const { StringRef Tmp = StringRef(Data).split('-').second; // Strip first component return Tmp.split('-').second; // Strip second component } static unsigned EatNumber(StringRef &Str) { assert(!Str.empty() && Str[0] >= '0' && Str[0] <= '9' && "Not a number"); unsigned Result = 0; do { // Consume the leading digit. Result = Result*10 + (Str[0] - '0'); // Eat the digit. Str = Str.substr(1); } while (!Str.empty() && Str[0] >= '0' && Str[0] <= '9'); return Result; } static void parseVersionFromName(StringRef Name, unsigned &Major, unsigned &Minor, unsigned &Micro) { // Any unset version defaults to 0. Major = Minor = Micro = 0; // Parse up to three components. unsigned *Components[3] = {&Major, &Minor, &Micro}; for (unsigned i = 0; i != 3; ++i) { if (Name.empty() || Name[0] < '0' || Name[0] > '9') break; // Consume the leading number. *Components[i] = EatNumber(Name); // Consume the separator, if present. if (Name.startswith(".")) Name = Name.substr(1); } } void Triple::getEnvironmentVersion(unsigned &Major, unsigned &Minor, unsigned &Micro) const { StringRef EnvironmentName = getEnvironmentName(); StringRef EnvironmentTypeName = getEnvironmentTypeName(getEnvironment()); if (EnvironmentName.startswith(EnvironmentTypeName)) EnvironmentName = EnvironmentName.substr(EnvironmentTypeName.size()); parseVersionFromName(EnvironmentName, Major, Minor, Micro); } void Triple::getOSVersion(unsigned &Major, unsigned &Minor, unsigned &Micro) const { StringRef OSName = getOSName(); // Assume that the OS portion of the triple starts with the canonical name. StringRef OSTypeName = getOSTypeName(getOS()); if (OSName.startswith(OSTypeName)) OSName = OSName.substr(OSTypeName.size()); parseVersionFromName(OSName, Major, Minor, Micro); } bool Triple::getMacOSXVersion(unsigned &Major, unsigned &Minor, unsigned &Micro) const { getOSVersion(Major, Minor, Micro); switch (getOS()) { default: llvm_unreachable("unexpected OS for Darwin triple"); case Darwin: // Default to darwin8, i.e., MacOSX 10.4. if (Major == 0) Major = 8; // Darwin version numbers are skewed from OS X versions. if (Major < 4) return false; Micro = 0; Minor = Major - 4; Major = 10; break; case MacOSX: // Default to 10.4. if (Major == 0) { Major = 10; Minor = 4; } if (Major != 10) return false; break; case IOS: case TvOS: case WatchOS: // Ignore the version from the triple. This is only handled because the // the clang driver combines OS X and IOS support into a common Darwin // toolchain that wants to know the OS X version number even when targeting // IOS. Major = 10; Minor = 4; Micro = 0; break; } return true; } void Triple::getiOSVersion(unsigned &Major, unsigned &Minor, unsigned &Micro) const { switch (getOS()) { default: llvm_unreachable("unexpected OS for Darwin triple"); case Darwin: case MacOSX: // Ignore the version from the triple. This is only handled because the // the clang driver combines OS X and IOS support into a common Darwin // toolchain that wants to know the iOS version number even when targeting // OS X. Major = 5; Minor = 0; Micro = 0; break; case IOS: case TvOS: getOSVersion(Major, Minor, Micro); // Default to 5.0 (or 7.0 for arm64). if (Major == 0) Major = (getArch() == aarch64) ? 7 : 5; break; case WatchOS: llvm_unreachable("conflicting triple info"); } } void Triple::getWatchOSVersion(unsigned &Major, unsigned &Minor, unsigned &Micro) const { switch (getOS()) { default: llvm_unreachable("unexpected OS for Darwin triple"); case Darwin: case MacOSX: // Ignore the version from the triple. This is only handled because the // the clang driver combines OS X and IOS support into a common Darwin // toolchain that wants to know the iOS version number even when targeting // OS X. Major = 2; Minor = 0; Micro = 0; break; case WatchOS: getOSVersion(Major, Minor, Micro); if (Major == 0) Major = 2; break; case IOS: llvm_unreachable("conflicting triple info"); } } void Triple::setTriple(const Twine &Str) { *this = Triple(Str); } void Triple::setArch(ArchType Kind) { setArchName(getArchTypeName(Kind)); } void Triple::setVendor(VendorType Kind) { setVendorName(getVendorTypeName(Kind)); } void Triple::setOS(OSType Kind) { setOSName(getOSTypeName(Kind)); } void Triple::setEnvironment(EnvironmentType Kind) { if (ObjectFormat == getDefaultFormat(*this)) return setEnvironmentName(getEnvironmentTypeName(Kind)); setEnvironmentName((getEnvironmentTypeName(Kind) + Twine("-") + getObjectFormatTypeName(ObjectFormat)).str()); } void Triple::setObjectFormat(ObjectFormatType Kind) { if (Environment == UnknownEnvironment) return setEnvironmentName(getObjectFormatTypeName(Kind)); setEnvironmentName((getEnvironmentTypeName(Environment) + Twine("-") + getObjectFormatTypeName(Kind)).str()); } void Triple::setArchName(StringRef Str) { // Work around a miscompilation bug for Twines in gcc 4.0.3. SmallString<64> Triple; Triple += Str; Triple += "-"; Triple += getVendorName(); Triple += "-"; Triple += getOSAndEnvironmentName(); setTriple(Triple); } void Triple::setVendorName(StringRef Str) { setTriple(getArchName() + "-" + Str + "-" + getOSAndEnvironmentName()); } void Triple::setOSName(StringRef Str) { if (hasEnvironment()) setTriple(getArchName() + "-" + getVendorName() + "-" + Str + "-" + getEnvironmentName()); else setTriple(getArchName() + "-" + getVendorName() + "-" + Str); } void Triple::setEnvironmentName(StringRef Str) { setTriple(getArchName() + "-" + getVendorName() + "-" + getOSName() + "-" + Str); } void Triple::setOSAndEnvironmentName(StringRef Str) { setTriple(getArchName() + "-" + getVendorName() + "-" + Str); } static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { switch (Arch) { case llvm::Triple::UnknownArch: return 0; case llvm::Triple::avr: case llvm::Triple::msp430: return 16; case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::hexagon: case llvm::Triple::le32: case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::nvptx: case llvm::Triple::ppc: case llvm::Triple::r600: case llvm::Triple::sparc: case llvm::Triple::sparcel: case llvm::Triple::tce: case llvm::Triple::thumb: case llvm::Triple::thumbeb: case llvm::Triple::x86: case llvm::Triple::xcore: case llvm::Triple::amdil: case llvm::Triple::hsail: case llvm::Triple::spir: case llvm::Triple::kalimba: case llvm::Triple::shave: case llvm::Triple::wasm32: return 32; case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: case llvm::Triple::amdgcn: case llvm::Triple::bpfel: case llvm::Triple::bpfeb: case llvm::Triple::le64: case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::nvptx64: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: case llvm::Triple::sparcv9: case llvm::Triple::systemz: case llvm::Triple::x86_64: case llvm::Triple::amdil64: case llvm::Triple::hsail64: case llvm::Triple::spir64: case llvm::Triple::wasm64: return 64; } llvm_unreachable("Invalid architecture value"); } bool Triple::isArch64Bit() const { return getArchPointerBitWidth(getArch()) == 64; } bool Triple::isArch32Bit() const { return getArchPointerBitWidth(getArch()) == 32; } bool Triple::isArch16Bit() const { return getArchPointerBitWidth(getArch()) == 16; } Triple Triple::get32BitArchVariant() const { Triple T(*this); switch (getArch()) { case Triple::UnknownArch: case Triple::amdgcn: case Triple::avr: case Triple::bpfel: case Triple::bpfeb: case Triple::msp430: case Triple::systemz: case Triple::ppc64le: T.setArch(UnknownArch); break; case Triple::amdil: case Triple::hsail: case Triple::spir: case Triple::arm: case Triple::armeb: case Triple::hexagon: case Triple::kalimba: case Triple::le32: case Triple::mips: case Triple::mipsel: case Triple::nvptx: case Triple::ppc: case Triple::r600: case Triple::sparc: case Triple::sparcel: case Triple::tce: case Triple::thumb: case Triple::thumbeb: case Triple::x86: case Triple::xcore: case Triple::shave: case Triple::wasm32: // Already 32-bit. break; case Triple::aarch64: T.setArch(Triple::arm); break; case Triple::aarch64_be: T.setArch(Triple::armeb); break; case Triple::le64: T.setArch(Triple::le32); break; case Triple::mips64: T.setArch(Triple::mips); break; case Triple::mips64el: T.setArch(Triple::mipsel); break; case Triple::nvptx64: T.setArch(Triple::nvptx); break; case Triple::ppc64: T.setArch(Triple::ppc); break; case Triple::sparcv9: T.setArch(Triple::sparc); break; case Triple::x86_64: T.setArch(Triple::x86); break; case Triple::amdil64: T.setArch(Triple::amdil); break; case Triple::hsail64: T.setArch(Triple::hsail); break; case Triple::spir64: T.setArch(Triple::spir); break; case Triple::wasm64: T.setArch(Triple::wasm32); break; } return T; } Triple Triple::get64BitArchVariant() const { Triple T(*this); switch (getArch()) { case Triple::UnknownArch: case Triple::avr: case Triple::hexagon: case Triple::kalimba: case Triple::msp430: case Triple::r600: case Triple::tce: case Triple::xcore: case Triple::sparcel: case Triple::shave: T.setArch(UnknownArch); break; case Triple::aarch64: case Triple::aarch64_be: case Triple::bpfel: case Triple::bpfeb: case Triple::le64: case Triple::amdil64: case Triple::amdgcn: case Triple::hsail64: case Triple::spir64: case Triple::mips64: case Triple::mips64el: case Triple::nvptx64: case Triple::ppc64: case Triple::ppc64le: case Triple::sparcv9: case Triple::systemz: case Triple::x86_64: case Triple::wasm64: // Already 64-bit. break; case Triple::arm: T.setArch(Triple::aarch64); break; case Triple::armeb: T.setArch(Triple::aarch64_be); break; case Triple::le32: T.setArch(Triple::le64); break; case Triple::mips: T.setArch(Triple::mips64); break; case Triple::mipsel: T.setArch(Triple::mips64el); break; case Triple::nvptx: T.setArch(Triple::nvptx64); break; case Triple::ppc: T.setArch(Triple::ppc64); break; case Triple::sparc: T.setArch(Triple::sparcv9); break; case Triple::x86: T.setArch(Triple::x86_64); break; case Triple::amdil: T.setArch(Triple::amdil64); break; case Triple::hsail: T.setArch(Triple::hsail64); break; case Triple::spir: T.setArch(Triple::spir64); break; case Triple::thumb: T.setArch(Triple::aarch64); break; case Triple::thumbeb: T.setArch(Triple::aarch64_be); break; case Triple::wasm32: T.setArch(Triple::wasm64); break; } return T; } Triple Triple::getBigEndianArchVariant() const { Triple T(*this); switch (getArch()) { case Triple::UnknownArch: case Triple::amdgcn: case Triple::amdil64: case Triple::amdil: case Triple::avr: case Triple::hexagon: case Triple::hsail64: case Triple::hsail: case Triple::kalimba: case Triple::le32: case Triple::le64: case Triple::msp430: case Triple::nvptx64: case Triple::nvptx: case Triple::r600: case Triple::shave: case Triple::spir64: case Triple::spir: case Triple::wasm32: case Triple::wasm64: case Triple::x86: case Triple::x86_64: case Triple::xcore: // ARM is intentionally unsupported here, changing the architecture would // drop any arch suffixes. case Triple::arm: case Triple::thumb: T.setArch(UnknownArch); break; case Triple::aarch64_be: case Triple::armeb: case Triple::bpfeb: case Triple::mips64: case Triple::mips: case Triple::ppc64: case Triple::ppc: case Triple::sparc: case Triple::sparcv9: case Triple::systemz: case Triple::tce: case Triple::thumbeb: // Already big endian. break; case Triple::aarch64: T.setArch(Triple::aarch64_be); break; case Triple::bpfel: T.setArch(Triple::bpfeb); break; case Triple::mips64el:T.setArch(Triple::mips64); break; case Triple::mipsel: T.setArch(Triple::mips); break; case Triple::ppc64le: T.setArch(Triple::ppc64); break; case Triple::sparcel: T.setArch(Triple::sparc); break; } return T; } Triple Triple::getLittleEndianArchVariant() const { Triple T(*this); switch (getArch()) { case Triple::UnknownArch: case Triple::ppc: case Triple::sparcv9: case Triple::systemz: case Triple::tce: // ARM is intentionally unsupported here, changing the architecture would // drop any arch suffixes. case Triple::armeb: case Triple::thumbeb: T.setArch(UnknownArch); break; case Triple::aarch64: case Triple::amdgcn: case Triple::amdil64: case Triple::amdil: case Triple::arm: case Triple::avr: case Triple::bpfel: case Triple::hexagon: case Triple::hsail64: case Triple::hsail: case Triple::kalimba: case Triple::le32: case Triple::le64: case Triple::mips64el: case Triple::mipsel: case Triple::msp430: case Triple::nvptx64: case Triple::nvptx: case Triple::ppc64le: case Triple::r600: case Triple::shave: case Triple::sparcel: case Triple::spir64: case Triple::spir: case Triple::thumb: case Triple::wasm32: case Triple::wasm64: case Triple::x86: case Triple::x86_64: case Triple::xcore: // Already little endian. break; case Triple::aarch64_be: T.setArch(Triple::aarch64); break; case Triple::bpfeb: T.setArch(Triple::bpfel); break; case Triple::mips64: T.setArch(Triple::mips64el); break; case Triple::mips: T.setArch(Triple::mipsel); break; case Triple::ppc64: T.setArch(Triple::ppc64le); break; case Triple::sparc: T.setArch(Triple::sparcel); break; } return T; } StringRef Triple::getARMCPUForArch(StringRef MArch) const { if (MArch.empty()) MArch = getArchName(); MArch = ARM::getCanonicalArchName(MArch); // Some defaults are forced. switch (getOS()) { case llvm::Triple::FreeBSD: case llvm::Triple::NetBSD: if (!MArch.empty() && MArch == "v6") return "arm1176jzf-s"; break; case llvm::Triple::Win32: // FIXME: this is invalid for WindowsCE return "cortex-a9"; case llvm::Triple::MacOSX: case llvm::Triple::IOS: case llvm::Triple::WatchOS: if (MArch == "v7k") return "cortex-a7"; break; default: break; } if (MArch.empty()) return StringRef(); StringRef CPU = ARM::getDefaultCPU(MArch); if (!CPU.empty()) return CPU; // If no specific architecture version is requested, return the minimum CPU // required by the OS and environment. switch (getOS()) { case llvm::Triple::NetBSD: switch (getEnvironment()) { case llvm::Triple::GNUEABIHF: case llvm::Triple::GNUEABI: case llvm::Triple::EABIHF: case llvm::Triple::EABI: return "arm926ej-s"; default: return "strongarm"; } case llvm::Triple::NaCl: return "cortex-a8"; default: switch (getEnvironment()) { case llvm::Triple::EABIHF: case llvm::Triple::GNUEABIHF: return "arm1176jzf-s"; default: return "arm7tdmi"; } } llvm_unreachable("invalid arch name"); } Index: projects/clang380-import/contrib/llvm/lib/Target/Sparc/SparcInstrAliases.td =================================================================== --- projects/clang380-import/contrib/llvm/lib/Target/Sparc/SparcInstrAliases.td (revision 295858) +++ projects/clang380-import/contrib/llvm/lib/Target/Sparc/SparcInstrAliases.td (revision 295859) @@ -1,461 +1,461 @@ //===-- SparcInstrAliases.td - Instruction Aliases for Sparc Target -------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains instruction aliases for Sparc. //===----------------------------------------------------------------------===// // Instruction aliases for conditional moves. // mov rs2, rd multiclass intcond_mov_alias { // mov (%icc|%xcc), rs2, rd def : InstAlias; // mov (%icc|%xcc), simm11, rd def : InstAlias; // fmovs (%icc|%xcc), $rs2, $rd def : InstAlias; // fmovd (%icc|%xcc), $rs2, $rd def : InstAlias; } // mov rs2, rd multiclass fpcond_mov_alias { // mov %fcc[0-3], rs2, rd def : InstAlias; // mov %fcc[0-3], simm11, rd def : InstAlias; // fmovs %fcc[0-3], $rs2, $rd def : InstAlias; // fmovd %fcc[0-3], $rs2, $rd def : InstAlias; } // Instruction aliases for integer conditional branches and moves. multiclass int_cond_alias { // b $imm def : InstAlias; // b,a $imm def : InstAlias; // b %icc, $imm def : InstAlias, Requires<[HasV9]>; // b,pt %icc, $imm def : InstAlias, Requires<[HasV9]>; // b,a %icc, $imm def : InstAlias, Requires<[HasV9]>; // b,a,pt %icc, $imm def : InstAlias, Requires<[HasV9]>; // b,pn %icc, $imm def : InstAlias, Requires<[HasV9]>; // b,a,pn %icc, $imm def : InstAlias, Requires<[HasV9]>; // b %xcc, $imm def : InstAlias, Requires<[Is64Bit]>; // b,pt %xcc, $imm def : InstAlias, Requires<[Is64Bit]>; // b,a %xcc, $imm def : InstAlias, Requires<[Is64Bit]>; // b,a,pt %xcc, $imm def : InstAlias, Requires<[Is64Bit]>; // b,pn %xcc, $imm def : InstAlias, Requires<[Is64Bit]>; // b,a,pn %xcc, $imm def : InstAlias, Requires<[Is64Bit]>; defm : intcond_mov_alias, Requires<[HasV9]>; defm : intcond_mov_alias, Requires<[Is64Bit]>; // fmovq (%icc|%xcc), $rs2, $rd def : InstAlias, Requires<[HasV9, HasHardQuad]>; def : InstAlias, Requires<[Is64Bit, HasHardQuad]>; // t %icc, rs1 + rs2 def : InstAlias, Requires<[HasV9]>; // t %icc, rs => t %icc, G0 + rs def : InstAlias, Requires<[HasV9]>; // t %xcc, rs1 + rs2 def : InstAlias, Requires<[HasV9]>; // t %xcc, rs => t %xcc, G0 + rs def : InstAlias, Requires<[HasV9]>; // t rs1 + rs2 => t %icc, rs1 + rs2 def : InstAlias; // t rs=> t %icc, G0 + rs2 def : InstAlias; // t %icc, rs1 + imm def : InstAlias, Requires<[HasV9]>; // t %icc, imm => t %icc, G0 + imm def : InstAlias, Requires<[HasV9]>; // t %xcc, rs1 + imm def : InstAlias, Requires<[HasV9]>; // t %xcc, imm => t %xcc, G0 + imm def : InstAlias, Requires<[HasV9]>; // t rs1 + imm => t %icc, rs1 + imm def : InstAlias; // t imm => t %icc, G0 + imm def : InstAlias; } // Instruction aliases for floating point conditional branches and moves. multiclass fp_cond_alias { // fb $imm def : InstAlias; // fb,a $imm def : InstAlias; // fb %fcc0, $imm def : InstAlias, Requires<[HasV9]>; // fb,pt %fcc0, $imm def : InstAlias, Requires<[HasV9]>; // fb,a %fcc0, $imm def : InstAlias, Requires<[HasV9]>; // fb,a,pt %fcc0, $imm def : InstAlias, Requires<[HasV9]>; // fb,pn %fcc0, $imm def : InstAlias, Requires<[HasV9]>; // fb,a,pn %fcc0, $imm def : InstAlias, Requires<[HasV9]>; defm : fpcond_mov_alias, Requires<[HasV9]>; // fmovq %fcc0, $rs2, $rd def : InstAlias, Requires<[HasV9, HasHardQuad]>; } defm : int_cond_alias<"a", 0b1000>; defm : int_cond_alias<"", 0b1000>; // same as a; gnu asm, not in manual defm : int_cond_alias<"n", 0b0000>; defm : int_cond_alias<"ne", 0b1001>; defm : int_cond_alias<"nz", 0b1001>; // same as ne defm : int_cond_alias<"e", 0b0001>; defm : int_cond_alias<"eq", 0b0001>; // same as e defm : int_cond_alias<"z", 0b0001>; // same as e defm : int_cond_alias<"g", 0b1010>; defm : int_cond_alias<"le", 0b0010>; defm : int_cond_alias<"ge", 0b1011>; defm : int_cond_alias<"l", 0b0011>; defm : int_cond_alias<"gu", 0b1100>; defm : int_cond_alias<"leu", 0b0100>; defm : int_cond_alias<"cc", 0b1101>; defm : int_cond_alias<"geu", 0b1101>; // same as cc defm : int_cond_alias<"cs", 0b0101>; defm : int_cond_alias<"lu", 0b0101>; // same as cs defm : int_cond_alias<"pos", 0b1110>; defm : int_cond_alias<"neg", 0b0110>; defm : int_cond_alias<"vc", 0b1111>; defm : int_cond_alias<"vs", 0b0111>; -defm : fp_cond_alias<"a", 0b0000>; -defm : fp_cond_alias<"", 0b0000>; // same as a; gnu asm, not in manual -defm : fp_cond_alias<"n", 0b1000>; +defm : fp_cond_alias<"a", 0b1000>; +defm : fp_cond_alias<"", 0b1000>; // same as a; gnu asm, not in manual +defm : fp_cond_alias<"n", 0b0000>; defm : fp_cond_alias<"u", 0b0111>; defm : fp_cond_alias<"g", 0b0110>; defm : fp_cond_alias<"ug", 0b0101>; defm : fp_cond_alias<"l", 0b0100>; defm : fp_cond_alias<"ul", 0b0011>; defm : fp_cond_alias<"lg", 0b0010>; defm : fp_cond_alias<"ne", 0b0001>; defm : fp_cond_alias<"nz", 0b0001>; // same as ne defm : fp_cond_alias<"e", 0b1001>; defm : fp_cond_alias<"z", 0b1001>; // same as e defm : fp_cond_alias<"ue", 0b1010>; defm : fp_cond_alias<"ge", 0b1011>; defm : fp_cond_alias<"uge", 0b1100>; defm : fp_cond_alias<"le", 0b1101>; defm : fp_cond_alias<"ule", 0b1110>; defm : fp_cond_alias<"o", 0b1111>; // Section A.3 Synthetic Instructions // Most are marked as Emit=0, so that they are not used for disassembly. This is // an aesthetic issue, but the chosen policy is to typically prefer using the // non-alias form, except for the most obvious and clarifying aliases: cmp, jmp, // call, tst, ret, retl. // Note: cmp is handled in SparcInstrInfo. // jmp/call/ret/retl have special case handling for output in // SparcInstPrinter.cpp // jmp addr -> jmpl addr, %g0 def : InstAlias<"jmp $addr", (JMPLrr G0, MEMrr:$addr), 0>; def : InstAlias<"jmp $addr", (JMPLri G0, MEMri:$addr), 0>; // call addr -> jmpl addr, %o7 def : InstAlias<"call $addr", (JMPLrr O7, MEMrr:$addr), 0>; def : InstAlias<"call $addr", (JMPLri O7, MEMri:$addr), 0>; // tst reg -> orcc %g0, reg, %g0 def : InstAlias<"tst $rs2", (ORCCrr G0, IntRegs:$rs2, G0)>; // ret -> jmpl %i7+8, %g0 (aka RET 8) def : InstAlias<"ret", (RET 8)>; // retl -> jmpl %o7+8, %g0 (aka RETL 8) def : InstAlias<"retl", (RETL 8)>; // restore -> restore %g0, %g0, %g0 def : InstAlias<"restore", (RESTORErr G0, G0, G0)>; // save -> restore %g0, %g0, %g0 def : InstAlias<"save", (SAVErr G0, G0, G0)>; // set value, rd // (turns into a sequence of sethi+or, depending on the value) // def : InstAlias<"set $val, $rd", (ORri IntRegs:$rd, (SETHIi (HI22 imm:$val)), (LO10 imm:$val))>; def SET : AsmPseudoInst<(outs IntRegs:$rd), (ins i32imm:$val), "set $val, $rd">; // not rd -> xnor rd, %g0, rd def : InstAlias<"not $rd", (XNORrr IntRegs:$rd, IntRegs:$rd, G0), 0>; // not reg, rd -> xnor reg, %g0, rd def : InstAlias<"not $rs1, $rd", (XNORrr IntRegs:$rd, IntRegs:$rs1, G0), 0>; // neg rd -> sub %g0, rd, rd def : InstAlias<"neg $rd", (SUBrr IntRegs:$rd, G0, IntRegs:$rd), 0>; // neg reg, rd -> sub %g0, reg, rd def : InstAlias<"neg $rs2, $rd", (SUBrr IntRegs:$rd, G0, IntRegs:$rs2), 0>; // inc rd -> add rd, 1, rd def : InstAlias<"inc $rd", (ADDri IntRegs:$rd, IntRegs:$rd, 1), 0>; // inc simm13, rd -> add rd, simm13, rd def : InstAlias<"inc $simm13, $rd", (ADDri IntRegs:$rd, IntRegs:$rd, i32imm:$simm13), 0>; // inccc rd -> addcc rd, 1, rd def : InstAlias<"inccc $rd", (ADDCCri IntRegs:$rd, IntRegs:$rd, 1), 0>; // inccc simm13, rd -> addcc rd, simm13, rd def : InstAlias<"inccc $simm13, $rd", (ADDCCri IntRegs:$rd, IntRegs:$rd, i32imm:$simm13), 0>; // dec rd -> sub rd, 1, rd def : InstAlias<"dec $rd", (SUBri IntRegs:$rd, IntRegs:$rd, 1), 0>; // dec simm13, rd -> sub rd, simm13, rd def : InstAlias<"dec $simm13, $rd", (SUBri IntRegs:$rd, IntRegs:$rd, i32imm:$simm13), 0>; // deccc rd -> subcc rd, 1, rd def : InstAlias<"deccc $rd", (SUBCCri IntRegs:$rd, IntRegs:$rd, 1), 0>; // deccc simm13, rd -> subcc rd, simm13, rd def : InstAlias<"deccc $simm13, $rd", (SUBCCri IntRegs:$rd, IntRegs:$rd, i32imm:$simm13), 0>; // btst reg_or_imm, reg -> andcc reg,reg_or_imm,%g0 def : InstAlias<"btst $rs2, $rs1", (ANDCCrr G0, IntRegs:$rs1, IntRegs:$rs2), 0>; def : InstAlias<"btst $simm13, $rs1", (ANDCCri G0, IntRegs:$rs1, i32imm:$simm13), 0>; // bset reg_or_imm, rd -> or rd,reg_or_imm,rd def : InstAlias<"bset $rs2, $rd", (ORrr IntRegs:$rd, IntRegs:$rd, IntRegs:$rs2), 0>; def : InstAlias<"bset $simm13, $rd", (ORri IntRegs:$rd, IntRegs:$rd, i32imm:$simm13), 0>; // bclr reg_or_imm, rd -> andn rd,reg_or_imm,rd def : InstAlias<"bclr $rs2, $rd", (ANDNrr IntRegs:$rd, IntRegs:$rd, IntRegs:$rs2), 0>; def : InstAlias<"bclr $simm13, $rd", (ANDNri IntRegs:$rd, IntRegs:$rd, i32imm:$simm13), 0>; // btog reg_or_imm, rd -> xor rd,reg_or_imm,rd def : InstAlias<"btog $rs2, $rd", (XORrr IntRegs:$rd, IntRegs:$rd, IntRegs:$rs2), 0>; def : InstAlias<"btog $simm13, $rd", (XORri IntRegs:$rd, IntRegs:$rd, i32imm:$simm13), 0>; // clr rd -> or %g0, %g0, rd def : InstAlias<"clr $rd", (ORrr IntRegs:$rd, G0, G0), 0>; // clr{b,h,} [addr] -> st{b,h,} %g0, [addr] def : InstAlias<"clrb [$addr]", (STBrr MEMrr:$addr, G0), 0>; def : InstAlias<"clrb [$addr]", (STBri MEMri:$addr, G0), 0>; def : InstAlias<"clrh [$addr]", (STHrr MEMrr:$addr, G0), 0>; def : InstAlias<"clrh [$addr]", (STHri MEMri:$addr, G0), 0>; def : InstAlias<"clr [$addr]", (STrr MEMrr:$addr, G0), 0>; def : InstAlias<"clr [$addr]", (STri MEMri:$addr, G0), 0>; // mov reg_or_imm, rd -> or %g0, reg_or_imm, rd def : InstAlias<"mov $rs2, $rd", (ORrr IntRegs:$rd, G0, IntRegs:$rs2)>; def : InstAlias<"mov $simm13, $rd", (ORri IntRegs:$rd, G0, i32imm:$simm13)>; // mov specialreg, rd -> rd specialreg, rd def : InstAlias<"mov $asr, $rd", (RDASR IntRegs:$rd, ASRRegs:$asr), 0>; def : InstAlias<"mov %psr, $rd", (RDPSR IntRegs:$rd), 0>; def : InstAlias<"mov %wim, $rd", (RDWIM IntRegs:$rd), 0>; def : InstAlias<"mov %tbr, $rd", (RDTBR IntRegs:$rd), 0>; // mov reg_or_imm, specialreg -> wr %g0, reg_or_imm, specialreg def : InstAlias<"mov $rs2, $asr", (WRASRrr ASRRegs:$asr, G0, IntRegs:$rs2), 0>; def : InstAlias<"mov $simm13, $asr", (WRASRri ASRRegs:$asr, G0, i32imm:$simm13), 0>; def : InstAlias<"mov $rs2, %psr", (WRPSRrr G0, IntRegs:$rs2), 0>; def : InstAlias<"mov $simm13, %psr", (WRPSRri G0, i32imm:$simm13), 0>; def : InstAlias<"mov $rs2, %wim", (WRWIMrr G0, IntRegs:$rs2), 0>; def : InstAlias<"mov $simm13, %wim", (WRWIMri G0, i32imm:$simm13), 0>; def : InstAlias<"mov $rs2, %tbr", (WRTBRrr G0, IntRegs:$rs2), 0>; def : InstAlias<"mov $simm13, %tbr", (WRTBRri G0, i32imm:$simm13), 0>; // End of Section A.3 // wr reg_or_imm, specialreg -> wr %g0, reg_or_imm, specialreg // (aka: omit the first arg when it's g0. This is not in the manual, but is // supported by gnu and solaris as) def : InstAlias<"wr $rs2, $asr", (WRASRrr ASRRegs:$asr, G0, IntRegs:$rs2), 0>; def : InstAlias<"wr $simm13, $asr", (WRASRri ASRRegs:$asr, G0, i32imm:$simm13), 0>; def : InstAlias<"wr $rs2, %psr", (WRPSRrr G0, IntRegs:$rs2), 0>; def : InstAlias<"wr $simm13, %psr", (WRPSRri G0, i32imm:$simm13), 0>; def : InstAlias<"wr $rs2, %wim", (WRWIMrr G0, IntRegs:$rs2), 0>; def : InstAlias<"wr $simm13, %wim", (WRWIMri G0, i32imm:$simm13), 0>; def : InstAlias<"wr $rs2, %tbr", (WRTBRrr G0, IntRegs:$rs2), 0>; def : InstAlias<"wr $simm13, %tbr", (WRTBRri G0, i32imm:$simm13), 0>; // flush -> flush %g0 def : InstAlias<"flush", (FLUSH), 0>; def : MnemonicAlias<"lduw", "ld">, Requires<[HasV9]>; def : MnemonicAlias<"lduwa", "lda">, Requires<[HasV9]>; def : MnemonicAlias<"return", "rett">, Requires<[HasV9]>; def : MnemonicAlias<"addc", "addx">, Requires<[HasV9]>; def : MnemonicAlias<"addccc", "addxcc">, Requires<[HasV9]>; def : MnemonicAlias<"subc", "subx">, Requires<[HasV9]>; def : MnemonicAlias<"subccc", "subxcc">, Requires<[HasV9]>; def : InstAlias<"fcmps $rs1, $rs2", (V9FCMPS FCC0, FPRegs:$rs1, FPRegs:$rs2)>; def : InstAlias<"fcmpd $rs1, $rs2", (V9FCMPD FCC0, DFPRegs:$rs1, DFPRegs:$rs2)>; def : InstAlias<"fcmpq $rs1, $rs2", (V9FCMPQ FCC0, QFPRegs:$rs1, QFPRegs:$rs2)>, Requires<[HasHardQuad]>; def : InstAlias<"fcmpes $rs1, $rs2", (V9FCMPES FCC0, FPRegs:$rs1, FPRegs:$rs2)>; def : InstAlias<"fcmped $rs1, $rs2", (V9FCMPED FCC0, DFPRegs:$rs1, DFPRegs:$rs2)>; def : InstAlias<"fcmpeq $rs1, $rs2", (V9FCMPEQ FCC0, QFPRegs:$rs1, QFPRegs:$rs2)>, Requires<[HasHardQuad]>; // signx rd -> sra rd, %g0, rd def : InstAlias<"signx $rd", (SRArr IntRegs:$rd, IntRegs:$rd, G0), 0>, Requires<[HasV9]>; // signx reg, rd -> sra reg, %g0, rd def : InstAlias<"signx $rs1, $rd", (SRArr IntRegs:$rd, IntRegs:$rs1, G0), 0>, Requires<[HasV9]>; Index: projects/clang380-import/contrib/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp =================================================================== --- projects/clang380-import/contrib/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp (revision 295858) +++ projects/clang380-import/contrib/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp (revision 295859) @@ -1,855 +1,837 @@ //===-- X86AsmBackend.cpp - X86 Assembler Backend -------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "MCTargetDesc/X86BaseInfo.h" #include "MCTargetDesc/X86FixupKinds.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCELFObjectWriter.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCMachObjectWriter.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MachO.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; static unsigned getFixupKindLog2Size(unsigned Kind) { switch (Kind) { default: llvm_unreachable("invalid fixup kind!"); case FK_PCRel_1: case FK_SecRel_1: case FK_Data_1: return 0; case FK_PCRel_2: case FK_SecRel_2: case FK_Data_2: return 1; case FK_PCRel_4: case X86::reloc_riprel_4byte: case X86::reloc_riprel_4byte_movq_load: case X86::reloc_signed_4byte: case X86::reloc_global_offset_table: case FK_SecRel_4: case FK_Data_4: return 2; case FK_PCRel_8: case FK_SecRel_8: case FK_Data_8: case X86::reloc_global_offset_table8: return 3; } } namespace { class X86ELFObjectWriter : public MCELFObjectTargetWriter { public: X86ELFObjectWriter(bool is64Bit, uint8_t OSABI, uint16_t EMachine, bool HasRelocationAddend, bool foobar) : MCELFObjectTargetWriter(is64Bit, OSABI, EMachine, HasRelocationAddend) {} }; class X86AsmBackend : public MCAsmBackend { const StringRef CPU; bool HasNopl; - uint64_t MaxNopLength; + const uint64_t MaxNopLength; public: - X86AsmBackend(const Target &T, StringRef CPU) : MCAsmBackend(), CPU(CPU) { + X86AsmBackend(const Target &T, StringRef CPU) + : MCAsmBackend(), CPU(CPU), MaxNopLength(CPU == "slm" ? 7 : 15) { HasNopl = CPU != "generic" && CPU != "i386" && CPU != "i486" && CPU != "i586" && CPU != "pentium" && CPU != "pentium-mmx" && CPU != "i686" && CPU != "k6" && CPU != "k6-2" && CPU != "k6-3" && CPU != "geode" && CPU != "winchip-c6" && CPU != "winchip2" && CPU != "c3" && CPU != "c3-2"; - // Max length of true long nop instruction is 15 bytes. - // Max length of long nop replacement instruction is 7 bytes. - // Taking into account SilverMont architecture features max length of nops - // is reduced for it to achieve better performance. - MaxNopLength = (!HasNopl || CPU == "slm") ? 7 : 15; } unsigned getNumFixupKinds() const override { return X86::NumTargetFixupKinds; } const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override { const static MCFixupKindInfo Infos[X86::NumTargetFixupKinds] = { { "reloc_riprel_4byte", 0, 4 * 8, MCFixupKindInfo::FKF_IsPCRel }, { "reloc_riprel_4byte_movq_load", 0, 4 * 8, MCFixupKindInfo::FKF_IsPCRel}, { "reloc_signed_4byte", 0, 4 * 8, 0}, { "reloc_global_offset_table", 0, 4 * 8, 0} }; if (Kind < FirstTargetFixupKind) return MCAsmBackend::getFixupKindInfo(Kind); assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && "Invalid kind!"); return Infos[Kind - FirstTargetFixupKind]; } void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, uint64_t Value, bool IsPCRel) const override { unsigned Size = 1 << getFixupKindLog2Size(Fixup.getKind()); assert(Fixup.getOffset() + Size <= DataSize && "Invalid fixup offset!"); // Check that uppper bits are either all zeros or all ones. // Specifically ignore overflow/underflow as long as the leakage is // limited to the lower bits. This is to remain compatible with // other assemblers. assert(isIntN(Size * 8 + 1, Value) && "Value does not fit in the Fixup field"); for (unsigned i = 0; i != Size; ++i) Data[Fixup.getOffset() + i] = uint8_t(Value >> (i * 8)); } bool mayNeedRelaxation(const MCInst &Inst) const override; bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, const MCRelaxableFragment *DF, const MCAsmLayout &Layout) const override; void relaxInstruction(const MCInst &Inst, MCInst &Res) const override; bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override; }; } // end anonymous namespace static unsigned getRelaxedOpcodeBranch(unsigned Op) { switch (Op) { default: return Op; case X86::JAE_1: return X86::JAE_4; case X86::JA_1: return X86::JA_4; case X86::JBE_1: return X86::JBE_4; case X86::JB_1: return X86::JB_4; case X86::JE_1: return X86::JE_4; case X86::JGE_1: return X86::JGE_4; case X86::JG_1: return X86::JG_4; case X86::JLE_1: return X86::JLE_4; case X86::JL_1: return X86::JL_4; case X86::JMP_1: return X86::JMP_4; case X86::JNE_1: return X86::JNE_4; case X86::JNO_1: return X86::JNO_4; case X86::JNP_1: return X86::JNP_4; case X86::JNS_1: return X86::JNS_4; case X86::JO_1: return X86::JO_4; case X86::JP_1: return X86::JP_4; case X86::JS_1: return X86::JS_4; } } static unsigned getRelaxedOpcodeArith(unsigned Op) { switch (Op) { default: return Op; // IMUL case X86::IMUL16rri8: return X86::IMUL16rri; case X86::IMUL16rmi8: return X86::IMUL16rmi; case X86::IMUL32rri8: return X86::IMUL32rri; case X86::IMUL32rmi8: return X86::IMUL32rmi; case X86::IMUL64rri8: return X86::IMUL64rri32; case X86::IMUL64rmi8: return X86::IMUL64rmi32; // AND case X86::AND16ri8: return X86::AND16ri; case X86::AND16mi8: return X86::AND16mi; case X86::AND32ri8: return X86::AND32ri; case X86::AND32mi8: return X86::AND32mi; case X86::AND64ri8: return X86::AND64ri32; case X86::AND64mi8: return X86::AND64mi32; // OR case X86::OR16ri8: return X86::OR16ri; case X86::OR16mi8: return X86::OR16mi; case X86::OR32ri8: return X86::OR32ri; case X86::OR32mi8: return X86::OR32mi; case X86::OR64ri8: return X86::OR64ri32; case X86::OR64mi8: return X86::OR64mi32; // XOR case X86::XOR16ri8: return X86::XOR16ri; case X86::XOR16mi8: return X86::XOR16mi; case X86::XOR32ri8: return X86::XOR32ri; case X86::XOR32mi8: return X86::XOR32mi; case X86::XOR64ri8: return X86::XOR64ri32; case X86::XOR64mi8: return X86::XOR64mi32; // ADD case X86::ADD16ri8: return X86::ADD16ri; case X86::ADD16mi8: return X86::ADD16mi; case X86::ADD32ri8: return X86::ADD32ri; case X86::ADD32mi8: return X86::ADD32mi; case X86::ADD64ri8: return X86::ADD64ri32; case X86::ADD64mi8: return X86::ADD64mi32; // ADC case X86::ADC16ri8: return X86::ADC16ri; case X86::ADC16mi8: return X86::ADC16mi; case X86::ADC32ri8: return X86::ADC32ri; case X86::ADC32mi8: return X86::ADC32mi; case X86::ADC64ri8: return X86::ADC64ri32; case X86::ADC64mi8: return X86::ADC64mi32; // SUB case X86::SUB16ri8: return X86::SUB16ri; case X86::SUB16mi8: return X86::SUB16mi; case X86::SUB32ri8: return X86::SUB32ri; case X86::SUB32mi8: return X86::SUB32mi; case X86::SUB64ri8: return X86::SUB64ri32; case X86::SUB64mi8: return X86::SUB64mi32; // SBB case X86::SBB16ri8: return X86::SBB16ri; case X86::SBB16mi8: return X86::SBB16mi; case X86::SBB32ri8: return X86::SBB32ri; case X86::SBB32mi8: return X86::SBB32mi; case X86::SBB64ri8: return X86::SBB64ri32; case X86::SBB64mi8: return X86::SBB64mi32; // CMP case X86::CMP16ri8: return X86::CMP16ri; case X86::CMP16mi8: return X86::CMP16mi; case X86::CMP32ri8: return X86::CMP32ri; case X86::CMP32mi8: return X86::CMP32mi; case X86::CMP64ri8: return X86::CMP64ri32; case X86::CMP64mi8: return X86::CMP64mi32; // PUSH case X86::PUSH32i8: return X86::PUSHi32; case X86::PUSH16i8: return X86::PUSHi16; case X86::PUSH64i8: return X86::PUSH64i32; } } static unsigned getRelaxedOpcode(unsigned Op) { unsigned R = getRelaxedOpcodeArith(Op); if (R != Op) return R; return getRelaxedOpcodeBranch(Op); } bool X86AsmBackend::mayNeedRelaxation(const MCInst &Inst) const { // Branches can always be relaxed. if (getRelaxedOpcodeBranch(Inst.getOpcode()) != Inst.getOpcode()) return true; // Check if this instruction is ever relaxable. if (getRelaxedOpcodeArith(Inst.getOpcode()) == Inst.getOpcode()) return false; // Check if the relaxable operand has an expression. For the current set of // relaxable instructions, the relaxable operand is always the last operand. unsigned RelaxableOp = Inst.getNumOperands() - 1; if (Inst.getOperand(RelaxableOp).isExpr()) return true; return false; } bool X86AsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, const MCRelaxableFragment *DF, const MCAsmLayout &Layout) const { // Relax if the value is too big for a (signed) i8. return int64_t(Value) != int64_t(int8_t(Value)); } // FIXME: Can tblgen help at all here to verify there aren't other instructions // we can relax? void X86AsmBackend::relaxInstruction(const MCInst &Inst, MCInst &Res) const { // The only relaxations X86 does is from a 1byte pcrel to a 4byte pcrel. unsigned RelaxedOp = getRelaxedOpcode(Inst.getOpcode()); if (RelaxedOp == Inst.getOpcode()) { SmallString<256> Tmp; raw_svector_ostream OS(Tmp); Inst.dump_pretty(OS); OS << "\n"; report_fatal_error("unexpected instruction to relax: " + OS.str()); } Res = Inst; Res.setOpcode(RelaxedOp); } /// \brief Write a sequence of optimal nops to the output, covering \p Count /// bytes. /// \return - true on success, false on failure bool X86AsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const { - static const uint8_t TrueNops[10][10] = { + static const uint8_t Nops[10][10] = { // nop {0x90}, // xchg %ax,%ax {0x66, 0x90}, // nopl (%[re]ax) {0x0f, 0x1f, 0x00}, // nopl 0(%[re]ax) {0x0f, 0x1f, 0x40, 0x00}, // nopl 0(%[re]ax,%[re]ax,1) {0x0f, 0x1f, 0x44, 0x00, 0x00}, // nopw 0(%[re]ax,%[re]ax,1) {0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00}, // nopl 0L(%[re]ax) {0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}, // nopl 0L(%[re]ax,%[re]ax,1) {0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, // nopw 0L(%[re]ax,%[re]ax,1) {0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, // nopw %cs:0L(%[re]ax,%[re]ax,1) {0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, }; - // Alternative nop instructions for CPUs which don't support long nops. - static const uint8_t AltNops[7][10] = { - // nop - {0x90}, - // xchg %ax,%ax - {0x66, 0x90}, - // lea 0x0(%esi),%esi - {0x8d, 0x76, 0x00}, - // lea 0x0(%esi),%esi - {0x8d, 0x74, 0x26, 0x00}, - // nop + lea 0x0(%esi),%esi - {0x90, 0x8d, 0x74, 0x26, 0x00}, - // lea 0x0(%esi),%esi - {0x8d, 0xb6, 0x00, 0x00, 0x00, 0x00 }, - // lea 0x0(%esi),%esi - {0x8d, 0xb4, 0x26, 0x00, 0x00, 0x00, 0x00}, - }; + // This CPU doesn't support long nops. If needed add more. + // FIXME: Can we get this from the subtarget somehow? + // FIXME: We could generated something better than plain 0x90. + if (!HasNopl) { + for (uint64_t i = 0; i < Count; ++i) + OW->write8(0x90); + return true; + } - // Select the right NOP table. - // FIXME: Can we get if CPU supports long nops from the subtarget somehow? - const uint8_t (*Nops)[10] = HasNopl ? TrueNops : AltNops; - assert(HasNopl || MaxNopLength <= 7); - - // Emit as many largest nops as needed, then emit a nop of the remaining - // length. + // 15 is the longest single nop instruction. Emit as many 15-byte nops as + // needed, then emit a nop of the remaining length. do { const uint8_t ThisNopLength = (uint8_t) std::min(Count, MaxNopLength); const uint8_t Prefixes = ThisNopLength <= 10 ? 0 : ThisNopLength - 10; for (uint8_t i = 0; i < Prefixes; i++) OW->write8(0x66); const uint8_t Rest = ThisNopLength - Prefixes; for (uint8_t i = 0; i < Rest; i++) OW->write8(Nops[Rest - 1][i]); Count -= ThisNopLength; } while (Count != 0); return true; } /* *** */ namespace { class ELFX86AsmBackend : public X86AsmBackend { public: uint8_t OSABI; ELFX86AsmBackend(const Target &T, uint8_t OSABI, StringRef CPU) : X86AsmBackend(T, CPU), OSABI(OSABI) {} }; class ELFX86_32AsmBackend : public ELFX86AsmBackend { public: ELFX86_32AsmBackend(const Target &T, uint8_t OSABI, StringRef CPU) : ELFX86AsmBackend(T, OSABI, CPU) {} MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { return createX86ELFObjectWriter(OS, /*IsELF64*/ false, OSABI, ELF::EM_386); } }; class ELFX86_X32AsmBackend : public ELFX86AsmBackend { public: ELFX86_X32AsmBackend(const Target &T, uint8_t OSABI, StringRef CPU) : ELFX86AsmBackend(T, OSABI, CPU) {} MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { return createX86ELFObjectWriter(OS, /*IsELF64*/ false, OSABI, ELF::EM_X86_64); } }; class ELFX86_IAMCUAsmBackend : public ELFX86AsmBackend { public: ELFX86_IAMCUAsmBackend(const Target &T, uint8_t OSABI, StringRef CPU) : ELFX86AsmBackend(T, OSABI, CPU) {} MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { return createX86ELFObjectWriter(OS, /*IsELF64*/ false, OSABI, ELF::EM_IAMCU); } }; class ELFX86_64AsmBackend : public ELFX86AsmBackend { public: ELFX86_64AsmBackend(const Target &T, uint8_t OSABI, StringRef CPU) : ELFX86AsmBackend(T, OSABI, CPU) {} MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { return createX86ELFObjectWriter(OS, /*IsELF64*/ true, OSABI, ELF::EM_X86_64); } }; class WindowsX86AsmBackend : public X86AsmBackend { bool Is64Bit; public: WindowsX86AsmBackend(const Target &T, bool is64Bit, StringRef CPU) : X86AsmBackend(T, CPU) , Is64Bit(is64Bit) { } MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { return createX86WinCOFFObjectWriter(OS, Is64Bit); } }; namespace CU { /// Compact unwind encoding values. enum CompactUnwindEncodings { /// [RE]BP based frame where [RE]BP is pused on the stack immediately after /// the return address, then [RE]SP is moved to [RE]BP. UNWIND_MODE_BP_FRAME = 0x01000000, /// A frameless function with a small constant stack size. UNWIND_MODE_STACK_IMMD = 0x02000000, /// A frameless function with a large constant stack size. UNWIND_MODE_STACK_IND = 0x03000000, /// No compact unwind encoding is available. UNWIND_MODE_DWARF = 0x04000000, /// Mask for encoding the frame registers. UNWIND_BP_FRAME_REGISTERS = 0x00007FFF, /// Mask for encoding the frameless registers. UNWIND_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF }; } // end CU namespace class DarwinX86AsmBackend : public X86AsmBackend { const MCRegisterInfo &MRI; /// \brief Number of registers that can be saved in a compact unwind encoding. enum { CU_NUM_SAVED_REGS = 6 }; mutable unsigned SavedRegs[CU_NUM_SAVED_REGS]; bool Is64Bit; unsigned OffsetSize; ///< Offset of a "push" instruction. unsigned MoveInstrSize; ///< Size of a "move" instruction. unsigned StackDivide; ///< Amount to adjust stack size by. protected: /// \brief Size of a "push" instruction for the given register. unsigned PushInstrSize(unsigned Reg) const { switch (Reg) { case X86::EBX: case X86::ECX: case X86::EDX: case X86::EDI: case X86::ESI: case X86::EBP: case X86::RBX: case X86::RBP: return 1; case X86::R12: case X86::R13: case X86::R14: case X86::R15: return 2; } return 1; } /// \brief Implementation of algorithm to generate the compact unwind encoding /// for the CFI instructions. uint32_t generateCompactUnwindEncodingImpl(ArrayRef Instrs) const { if (Instrs.empty()) return 0; // Reset the saved registers. unsigned SavedRegIdx = 0; memset(SavedRegs, 0, sizeof(SavedRegs)); bool HasFP = false; // Encode that we are using EBP/RBP as the frame pointer. uint32_t CompactUnwindEncoding = 0; unsigned SubtractInstrIdx = Is64Bit ? 3 : 2; unsigned InstrOffset = 0; unsigned StackAdjust = 0; unsigned StackSize = 0; unsigned PrevStackSize = 0; unsigned NumDefCFAOffsets = 0; for (unsigned i = 0, e = Instrs.size(); i != e; ++i) { const MCCFIInstruction &Inst = Instrs[i]; switch (Inst.getOperation()) { default: // Any other CFI directives indicate a frame that we aren't prepared // to represent via compact unwind, so just bail out. return 0; case MCCFIInstruction::OpDefCfaRegister: { // Defines a frame pointer. E.g. // // movq %rsp, %rbp // L0: // .cfi_def_cfa_register %rbp // HasFP = true; assert(MRI.getLLVMRegNum(Inst.getRegister(), true) == (Is64Bit ? X86::RBP : X86::EBP) && "Invalid frame pointer!"); // Reset the counts. memset(SavedRegs, 0, sizeof(SavedRegs)); StackAdjust = 0; SavedRegIdx = 0; InstrOffset += MoveInstrSize; break; } case MCCFIInstruction::OpDefCfaOffset: { // Defines a new offset for the CFA. E.g. // // With frame: // // pushq %rbp // L0: // .cfi_def_cfa_offset 16 // // Without frame: // // subq $72, %rsp // L0: // .cfi_def_cfa_offset 80 // PrevStackSize = StackSize; StackSize = std::abs(Inst.getOffset()) / StackDivide; ++NumDefCFAOffsets; break; } case MCCFIInstruction::OpOffset: { // Defines a "push" of a callee-saved register. E.g. // // pushq %r15 // pushq %r14 // pushq %rbx // L0: // subq $120, %rsp // L1: // .cfi_offset %rbx, -40 // .cfi_offset %r14, -32 // .cfi_offset %r15, -24 // if (SavedRegIdx == CU_NUM_SAVED_REGS) // If there are too many saved registers, we cannot use a compact // unwind encoding. return CU::UNWIND_MODE_DWARF; unsigned Reg = MRI.getLLVMRegNum(Inst.getRegister(), true); SavedRegs[SavedRegIdx++] = Reg; StackAdjust += OffsetSize; InstrOffset += PushInstrSize(Reg); break; } } } StackAdjust /= StackDivide; if (HasFP) { if ((StackAdjust & 0xFF) != StackAdjust) // Offset was too big for a compact unwind encoding. return CU::UNWIND_MODE_DWARF; // Get the encoding of the saved registers when we have a frame pointer. uint32_t RegEnc = encodeCompactUnwindRegistersWithFrame(); if (RegEnc == ~0U) return CU::UNWIND_MODE_DWARF; CompactUnwindEncoding |= CU::UNWIND_MODE_BP_FRAME; CompactUnwindEncoding |= (StackAdjust & 0xFF) << 16; CompactUnwindEncoding |= RegEnc & CU::UNWIND_BP_FRAME_REGISTERS; } else { // If the amount of the stack allocation is the size of a register, then // we "push" the RAX/EAX register onto the stack instead of adjusting the // stack pointer with a SUB instruction. We don't support the push of the // RAX/EAX register with compact unwind. So we check for that situation // here. if ((NumDefCFAOffsets == SavedRegIdx + 1 && StackSize - PrevStackSize == 1) || (Instrs.size() == 1 && NumDefCFAOffsets == 1 && StackSize == 2)) return CU::UNWIND_MODE_DWARF; SubtractInstrIdx += InstrOffset; ++StackAdjust; if ((StackSize & 0xFF) == StackSize) { // Frameless stack with a small stack size. CompactUnwindEncoding |= CU::UNWIND_MODE_STACK_IMMD; // Encode the stack size. CompactUnwindEncoding |= (StackSize & 0xFF) << 16; } else { if ((StackAdjust & 0x7) != StackAdjust) // The extra stack adjustments are too big for us to handle. return CU::UNWIND_MODE_DWARF; // Frameless stack with an offset too large for us to encode compactly. CompactUnwindEncoding |= CU::UNWIND_MODE_STACK_IND; // Encode the offset to the nnnnnn value in the 'subl $nnnnnn, ESP' // instruction. CompactUnwindEncoding |= (SubtractInstrIdx & 0xFF) << 16; // Encode any extra stack stack adjustments (done via push // instructions). CompactUnwindEncoding |= (StackAdjust & 0x7) << 13; } // Encode the number of registers saved. (Reverse the list first.) std::reverse(&SavedRegs[0], &SavedRegs[SavedRegIdx]); CompactUnwindEncoding |= (SavedRegIdx & 0x7) << 10; // Get the encoding of the saved registers when we don't have a frame // pointer. uint32_t RegEnc = encodeCompactUnwindRegistersWithoutFrame(SavedRegIdx); if (RegEnc == ~0U) return CU::UNWIND_MODE_DWARF; // Encode the register encoding. CompactUnwindEncoding |= RegEnc & CU::UNWIND_FRAMELESS_STACK_REG_PERMUTATION; } return CompactUnwindEncoding; } private: /// \brief Get the compact unwind number for a given register. The number /// corresponds to the enum lists in compact_unwind_encoding.h. int getCompactUnwindRegNum(unsigned Reg) const { static const MCPhysReg CU32BitRegs[7] = { X86::EBX, X86::ECX, X86::EDX, X86::EDI, X86::ESI, X86::EBP, 0 }; static const MCPhysReg CU64BitRegs[] = { X86::RBX, X86::R12, X86::R13, X86::R14, X86::R15, X86::RBP, 0 }; const MCPhysReg *CURegs = Is64Bit ? CU64BitRegs : CU32BitRegs; for (int Idx = 1; *CURegs; ++CURegs, ++Idx) if (*CURegs == Reg) return Idx; return -1; } /// \brief Return the registers encoded for a compact encoding with a frame /// pointer. uint32_t encodeCompactUnwindRegistersWithFrame() const { // Encode the registers in the order they were saved --- 3-bits per // register. The list of saved registers is assumed to be in reverse // order. The registers are numbered from 1 to CU_NUM_SAVED_REGS. uint32_t RegEnc = 0; for (int i = 0, Idx = 0; i != CU_NUM_SAVED_REGS; ++i) { unsigned Reg = SavedRegs[i]; if (Reg == 0) break; int CURegNum = getCompactUnwindRegNum(Reg); if (CURegNum == -1) return ~0U; // Encode the 3-bit register number in order, skipping over 3-bits for // each register. RegEnc |= (CURegNum & 0x7) << (Idx++ * 3); } assert((RegEnc & 0x3FFFF) == RegEnc && "Invalid compact register encoding!"); return RegEnc; } /// \brief Create the permutation encoding used with frameless stacks. It is /// passed the number of registers to be saved and an array of the registers /// saved. uint32_t encodeCompactUnwindRegistersWithoutFrame(unsigned RegCount) const { // The saved registers are numbered from 1 to 6. In order to encode the // order in which they were saved, we re-number them according to their // place in the register order. The re-numbering is relative to the last // re-numbered register. E.g., if we have registers {6, 2, 4, 5} saved in // that order: // // Orig Re-Num // ---- ------ // 6 6 // 2 2 // 4 3 // 5 3 // for (unsigned i = 0; i < RegCount; ++i) { int CUReg = getCompactUnwindRegNum(SavedRegs[i]); if (CUReg == -1) return ~0U; SavedRegs[i] = CUReg; } // Reverse the list. std::reverse(&SavedRegs[0], &SavedRegs[CU_NUM_SAVED_REGS]); uint32_t RenumRegs[CU_NUM_SAVED_REGS]; for (unsigned i = CU_NUM_SAVED_REGS - RegCount; i < CU_NUM_SAVED_REGS; ++i){ unsigned Countless = 0; for (unsigned j = CU_NUM_SAVED_REGS - RegCount; j < i; ++j) if (SavedRegs[j] < SavedRegs[i]) ++Countless; RenumRegs[i] = SavedRegs[i] - Countless - 1; } // Take the renumbered values and encode them into a 10-bit number. uint32_t permutationEncoding = 0; switch (RegCount) { case 6: permutationEncoding |= 120 * RenumRegs[0] + 24 * RenumRegs[1] + 6 * RenumRegs[2] + 2 * RenumRegs[3] + RenumRegs[4]; break; case 5: permutationEncoding |= 120 * RenumRegs[1] + 24 * RenumRegs[2] + 6 * RenumRegs[3] + 2 * RenumRegs[4] + RenumRegs[5]; break; case 4: permutationEncoding |= 60 * RenumRegs[2] + 12 * RenumRegs[3] + 3 * RenumRegs[4] + RenumRegs[5]; break; case 3: permutationEncoding |= 20 * RenumRegs[3] + 4 * RenumRegs[4] + RenumRegs[5]; break; case 2: permutationEncoding |= 5 * RenumRegs[4] + RenumRegs[5]; break; case 1: permutationEncoding |= RenumRegs[5]; break; } assert((permutationEncoding & 0x3FF) == permutationEncoding && "Invalid compact register encoding!"); return permutationEncoding; } public: DarwinX86AsmBackend(const Target &T, const MCRegisterInfo &MRI, StringRef CPU, bool Is64Bit) : X86AsmBackend(T, CPU), MRI(MRI), Is64Bit(Is64Bit) { memset(SavedRegs, 0, sizeof(SavedRegs)); OffsetSize = Is64Bit ? 8 : 4; MoveInstrSize = Is64Bit ? 3 : 2; StackDivide = Is64Bit ? 8 : 4; } }; class DarwinX86_32AsmBackend : public DarwinX86AsmBackend { public: DarwinX86_32AsmBackend(const Target &T, const MCRegisterInfo &MRI, StringRef CPU) : DarwinX86AsmBackend(T, MRI, CPU, false) {} MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { return createX86MachObjectWriter(OS, /*Is64Bit=*/false, MachO::CPU_TYPE_I386, MachO::CPU_SUBTYPE_I386_ALL); } /// \brief Generate the compact unwind encoding for the CFI instructions. uint32_t generateCompactUnwindEncoding( ArrayRef Instrs) const override { return generateCompactUnwindEncodingImpl(Instrs); } }; class DarwinX86_64AsmBackend : public DarwinX86AsmBackend { const MachO::CPUSubTypeX86 Subtype; public: DarwinX86_64AsmBackend(const Target &T, const MCRegisterInfo &MRI, StringRef CPU, MachO::CPUSubTypeX86 st) : DarwinX86AsmBackend(T, MRI, CPU, true), Subtype(st) {} MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { return createX86MachObjectWriter(OS, /*Is64Bit=*/true, MachO::CPU_TYPE_X86_64, Subtype); } /// \brief Generate the compact unwind encoding for the CFI instructions. uint32_t generateCompactUnwindEncoding( ArrayRef Instrs) const override { return generateCompactUnwindEncodingImpl(Instrs); } }; } // end anonymous namespace MCAsmBackend *llvm::createX86_32AsmBackend(const Target &T, const MCRegisterInfo &MRI, const Triple &TheTriple, StringRef CPU) { if (TheTriple.isOSBinFormatMachO()) return new DarwinX86_32AsmBackend(T, MRI, CPU); if (TheTriple.isOSWindows() && !TheTriple.isOSBinFormatELF()) return new WindowsX86AsmBackend(T, false, CPU); uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS()); if (TheTriple.isOSIAMCU()) return new ELFX86_IAMCUAsmBackend(T, OSABI, CPU); return new ELFX86_32AsmBackend(T, OSABI, CPU); } MCAsmBackend *llvm::createX86_64AsmBackend(const Target &T, const MCRegisterInfo &MRI, const Triple &TheTriple, StringRef CPU) { if (TheTriple.isOSBinFormatMachO()) { MachO::CPUSubTypeX86 CS = StringSwitch(TheTriple.getArchName()) .Case("x86_64h", MachO::CPU_SUBTYPE_X86_64_H) .Default(MachO::CPU_SUBTYPE_X86_64_ALL); return new DarwinX86_64AsmBackend(T, MRI, CPU, CS); } if (TheTriple.isOSWindows() && !TheTriple.isOSBinFormatELF()) return new WindowsX86AsmBackend(T, true, CPU); uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS()); if (TheTriple.getEnvironment() == Triple::GNUX32) return new ELFX86_X32AsmBackend(T, OSABI, CPU); return new ELFX86_64AsmBackend(T, OSABI, CPU); } Index: projects/clang380-import/contrib/llvm/lib/Target/X86/X86FrameLowering.cpp =================================================================== --- projects/clang380-import/contrib/llvm/lib/Target/X86/X86FrameLowering.cpp (revision 295858) +++ projects/clang380-import/contrib/llvm/lib/Target/X86/X86FrameLowering.cpp (revision 295859) @@ -1,2719 +1,2718 @@ //===-- X86FrameLowering.cpp - X86 Frame Information ----------------------===// // // 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 X86 implementation of TargetFrameLowering class. // //===----------------------------------------------------------------------===// #include "X86FrameLowering.h" #include "X86InstrBuilder.h" #include "X86InstrInfo.h" #include "X86MachineFunctionInfo.h" #include "X86Subtarget.h" #include "X86TargetMachine.h" #include "llvm/ADT/SmallSet.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Support/Debug.h" #include using namespace llvm; X86FrameLowering::X86FrameLowering(const X86Subtarget &STI, unsigned StackAlignOverride) : TargetFrameLowering(StackGrowsDown, StackAlignOverride, STI.is64Bit() ? -8 : -4), STI(STI), TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) { // Cache a bunch of frame-related predicates for this subtarget. SlotSize = TRI->getSlotSize(); Is64Bit = STI.is64Bit(); IsLP64 = STI.isTarget64BitLP64(); // standard x86_64 and NaCl use 64-bit frame/stack pointers, x32 - 32-bit. Uses64BitFramePtr = STI.isTarget64BitLP64() || STI.isTargetNaCl64(); StackPtr = TRI->getStackRegister(); } bool X86FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { return !MF.getFrameInfo()->hasVarSizedObjects() && !MF.getInfo()->getHasPushSequences(); } /// canSimplifyCallFramePseudos - If there is a reserved call frame, the /// call frame pseudos can be simplified. Having a FP, as in the default /// implementation, is not sufficient here since we can't always use it. /// Use a more nuanced condition. bool X86FrameLowering::canSimplifyCallFramePseudos(const MachineFunction &MF) const { return hasReservedCallFrame(MF) || (hasFP(MF) && !TRI->needsStackRealignment(MF)) || TRI->hasBasePointer(MF); } // needsFrameIndexResolution - Do we need to perform FI resolution for // this function. Normally, this is required only when the function // has any stack objects. However, FI resolution actually has another job, // not apparent from the title - it resolves callframesetup/destroy // that were not simplified earlier. // So, this is required for x86 functions that have push sequences even // when there are no stack objects. bool X86FrameLowering::needsFrameIndexResolution(const MachineFunction &MF) const { return MF.getFrameInfo()->hasStackObjects() || MF.getInfo()->getHasPushSequences(); } /// hasFP - Return true if the specified function should have a dedicated frame /// pointer register. This is true if the function has variable sized allocas /// or if frame pointer elimination is disabled. bool X86FrameLowering::hasFP(const MachineFunction &MF) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); const MachineModuleInfo &MMI = MF.getMMI(); return (MF.getTarget().Options.DisableFramePointerElim(MF) || TRI->needsStackRealignment(MF) || MFI->hasVarSizedObjects() || MFI->isFrameAddressTaken() || MFI->hasOpaqueSPAdjustment() || MF.getInfo()->getForceFramePointer() || MMI.callsUnwindInit() || MMI.hasEHFunclets() || MMI.callsEHReturn() || MFI->hasStackMap() || MFI->hasPatchPoint() || MFI->hasCopyImplyingStackAdjustment()); } static unsigned getSUBriOpcode(unsigned IsLP64, int64_t Imm) { if (IsLP64) { if (isInt<8>(Imm)) return X86::SUB64ri8; return X86::SUB64ri32; } else { if (isInt<8>(Imm)) return X86::SUB32ri8; return X86::SUB32ri; } } static unsigned getADDriOpcode(unsigned IsLP64, int64_t Imm) { if (IsLP64) { if (isInt<8>(Imm)) return X86::ADD64ri8; return X86::ADD64ri32; } else { if (isInt<8>(Imm)) return X86::ADD32ri8; return X86::ADD32ri; } } static unsigned getSUBrrOpcode(unsigned isLP64) { return isLP64 ? X86::SUB64rr : X86::SUB32rr; } static unsigned getADDrrOpcode(unsigned isLP64) { return isLP64 ? X86::ADD64rr : X86::ADD32rr; } static unsigned getANDriOpcode(bool IsLP64, int64_t Imm) { if (IsLP64) { if (isInt<8>(Imm)) return X86::AND64ri8; return X86::AND64ri32; } if (isInt<8>(Imm)) return X86::AND32ri8; return X86::AND32ri; } static unsigned getLEArOpcode(unsigned IsLP64) { return IsLP64 ? X86::LEA64r : X86::LEA32r; } /// findDeadCallerSavedReg - Return a caller-saved register that isn't live /// when it reaches the "return" instruction. We can then pop a stack object /// to this register without worry about clobbering it. static unsigned findDeadCallerSavedReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, const X86RegisterInfo *TRI, bool Is64Bit) { const MachineFunction *MF = MBB.getParent(); const Function *F = MF->getFunction(); if (!F || MF->getMMI().callsEHReturn()) return 0; const TargetRegisterClass &AvailableRegs = *TRI->getGPRsForTailCall(*MF); unsigned Opc = MBBI->getOpcode(); switch (Opc) { default: return 0; case X86::RETL: case X86::RETQ: case X86::RETIL: case X86::RETIQ: case X86::TCRETURNdi: case X86::TCRETURNri: case X86::TCRETURNmi: case X86::TCRETURNdi64: case X86::TCRETURNri64: case X86::TCRETURNmi64: case X86::EH_RETURN: case X86::EH_RETURN64: { SmallSet Uses; for (unsigned i = 0, e = MBBI->getNumOperands(); i != e; ++i) { MachineOperand &MO = MBBI->getOperand(i); if (!MO.isReg() || MO.isDef()) continue; unsigned Reg = MO.getReg(); if (!Reg) continue; for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI) Uses.insert(*AI); } for (auto CS : AvailableRegs) if (!Uses.count(CS) && CS != X86::RIP) return CS; } } return 0; } -static bool isEAXLiveIn(MachineFunction &MF) { - for (MachineRegisterInfo::livein_iterator II = MF.getRegInfo().livein_begin(), - EE = MF.getRegInfo().livein_end(); II != EE; ++II) { - unsigned Reg = II->first; +static bool isEAXLiveIn(MachineBasicBlock &MBB) { + for (MachineBasicBlock::RegisterMaskPair RegMask : MBB.liveins()) { + unsigned Reg = RegMask.PhysReg; if (Reg == X86::RAX || Reg == X86::EAX || Reg == X86::AX || Reg == X86::AH || Reg == X86::AL) return true; } return false; } /// Check if the flags need to be preserved before the terminators. /// This would be the case, if the eflags is live-in of the region /// composed by the terminators or live-out of that region, without /// being defined by a terminator. static bool flagsNeedToBePreservedBeforeTheTerminators(const MachineBasicBlock &MBB) { for (const MachineInstr &MI : MBB.terminators()) { bool BreakNext = false; for (const MachineOperand &MO : MI.operands()) { if (!MO.isReg()) continue; unsigned Reg = MO.getReg(); if (Reg != X86::EFLAGS) continue; // This terminator needs an eflags that is not defined // by a previous another terminator: // EFLAGS is live-in of the region composed by the terminators. if (!MO.isDef()) return true; // This terminator defines the eflags, i.e., we don't need to preserve it. // However, we still need to check this specific terminator does not // read a live-in value. BreakNext = true; } // We found a definition of the eflags, no need to preserve them. if (BreakNext) return false; } // None of the terminators use or define the eflags. // Check if they are live-out, that would imply we need to preserve them. for (const MachineBasicBlock *Succ : MBB.successors()) if (Succ->isLiveIn(X86::EFLAGS)) return true; return false; } /// emitSPUpdate - Emit a series of instructions to increment / decrement the /// stack pointer by a constant value. void X86FrameLowering::emitSPUpdate(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, int64_t NumBytes, bool InEpilogue) const { bool isSub = NumBytes < 0; uint64_t Offset = isSub ? -NumBytes : NumBytes; uint64_t Chunk = (1LL << 31) - 1; DebugLoc DL = MBB.findDebugLoc(MBBI); while (Offset) { if (Offset > Chunk) { // Rather than emit a long series of instructions for large offsets, // load the offset into a register and do one sub/add unsigned Reg = 0; - if (isSub && !isEAXLiveIn(*MBB.getParent())) + if (isSub && !isEAXLiveIn(MBB)) Reg = (unsigned)(Is64Bit ? X86::RAX : X86::EAX); else Reg = findDeadCallerSavedReg(MBB, MBBI, TRI, Is64Bit); if (Reg) { unsigned Opc = Is64Bit ? X86::MOV64ri : X86::MOV32ri; BuildMI(MBB, MBBI, DL, TII.get(Opc), Reg) .addImm(Offset); Opc = isSub ? getSUBrrOpcode(Is64Bit) : getADDrrOpcode(Is64Bit); MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opc), StackPtr) .addReg(StackPtr) .addReg(Reg); MI->getOperand(3).setIsDead(); // The EFLAGS implicit def is dead. Offset = 0; continue; } } uint64_t ThisVal = std::min(Offset, Chunk); if (ThisVal == (Is64Bit ? 8 : 4)) { // Use push / pop instead. unsigned Reg = isSub ? (unsigned)(Is64Bit ? X86::RAX : X86::EAX) : findDeadCallerSavedReg(MBB, MBBI, TRI, Is64Bit); if (Reg) { unsigned Opc = isSub ? (Is64Bit ? X86::PUSH64r : X86::PUSH32r) : (Is64Bit ? X86::POP64r : X86::POP32r); MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opc)) .addReg(Reg, getDefRegState(!isSub) | getUndefRegState(isSub)); if (isSub) MI->setFlag(MachineInstr::FrameSetup); else MI->setFlag(MachineInstr::FrameDestroy); Offset -= ThisVal; continue; } } MachineInstrBuilder MI = BuildStackAdjustment( MBB, MBBI, DL, isSub ? -ThisVal : ThisVal, InEpilogue); if (isSub) MI.setMIFlag(MachineInstr::FrameSetup); else MI.setMIFlag(MachineInstr::FrameDestroy); Offset -= ThisVal; } } MachineInstrBuilder X86FrameLowering::BuildStackAdjustment( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, DebugLoc DL, int64_t Offset, bool InEpilogue) const { assert(Offset != 0 && "zero offset stack adjustment requested"); // On Atom, using LEA to adjust SP is preferred, but using it in the epilogue // is tricky. bool UseLEA; if (!InEpilogue) { // Check if inserting the prologue at the beginning // of MBB would require to use LEA operations. // We need to use LEA operations if EFLAGS is live in, because // it means an instruction will read it before it gets defined. UseLEA = STI.useLeaForSP() || MBB.isLiveIn(X86::EFLAGS); } else { // If we can use LEA for SP but we shouldn't, check that none // of the terminators uses the eflags. Otherwise we will insert // a ADD that will redefine the eflags and break the condition. // Alternatively, we could move the ADD, but this may not be possible // and is an optimization anyway. UseLEA = canUseLEAForSPInEpilogue(*MBB.getParent()); if (UseLEA && !STI.useLeaForSP()) UseLEA = flagsNeedToBePreservedBeforeTheTerminators(MBB); // If that assert breaks, that means we do not do the right thing // in canUseAsEpilogue. assert((UseLEA || !flagsNeedToBePreservedBeforeTheTerminators(MBB)) && "We shouldn't have allowed this insertion point"); } MachineInstrBuilder MI; if (UseLEA) { MI = addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(getLEArOpcode(Uses64BitFramePtr)), StackPtr), StackPtr, false, Offset); } else { bool IsSub = Offset < 0; uint64_t AbsOffset = IsSub ? -Offset : Offset; unsigned Opc = IsSub ? getSUBriOpcode(Uses64BitFramePtr, AbsOffset) : getADDriOpcode(Uses64BitFramePtr, AbsOffset); MI = BuildMI(MBB, MBBI, DL, TII.get(Opc), StackPtr) .addReg(StackPtr) .addImm(AbsOffset); MI->getOperand(3).setIsDead(); // The EFLAGS implicit def is dead. } return MI; } int X86FrameLowering::mergeSPUpdates(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, bool doMergeWithPrevious) const { if ((doMergeWithPrevious && MBBI == MBB.begin()) || (!doMergeWithPrevious && MBBI == MBB.end())) return 0; MachineBasicBlock::iterator PI = doMergeWithPrevious ? std::prev(MBBI) : MBBI; MachineBasicBlock::iterator NI = doMergeWithPrevious ? nullptr : std::next(MBBI); unsigned Opc = PI->getOpcode(); int Offset = 0; if ((Opc == X86::ADD64ri32 || Opc == X86::ADD64ri8 || Opc == X86::ADD32ri || Opc == X86::ADD32ri8 || Opc == X86::LEA32r || Opc == X86::LEA64_32r) && PI->getOperand(0).getReg() == StackPtr){ Offset += PI->getOperand(2).getImm(); MBB.erase(PI); if (!doMergeWithPrevious) MBBI = NI; } else if ((Opc == X86::SUB64ri32 || Opc == X86::SUB64ri8 || Opc == X86::SUB32ri || Opc == X86::SUB32ri8) && PI->getOperand(0).getReg() == StackPtr) { Offset -= PI->getOperand(2).getImm(); MBB.erase(PI); if (!doMergeWithPrevious) MBBI = NI; } return Offset; } void X86FrameLowering::BuildCFI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, DebugLoc DL, MCCFIInstruction CFIInst) const { MachineFunction &MF = *MBB.getParent(); unsigned CFIIndex = MF.getMMI().addFrameInst(CFIInst); BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex); } void X86FrameLowering::emitCalleeSavedFrameMoves(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, DebugLoc DL) const { MachineFunction &MF = *MBB.getParent(); MachineFrameInfo *MFI = MF.getFrameInfo(); MachineModuleInfo &MMI = MF.getMMI(); const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); // Add callee saved registers to move list. const std::vector &CSI = MFI->getCalleeSavedInfo(); if (CSI.empty()) return; // Calculate offsets. for (std::vector::const_iterator I = CSI.begin(), E = CSI.end(); I != E; ++I) { int64_t Offset = MFI->getObjectOffset(I->getFrameIdx()); unsigned Reg = I->getReg(); unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true); BuildCFI(MBB, MBBI, DL, MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset)); } } MachineInstr *X86FrameLowering::emitStackProbe(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, DebugLoc DL, bool InProlog) const { const X86Subtarget &STI = MF.getSubtarget(); if (STI.isTargetWindowsCoreCLR()) { if (InProlog) { return emitStackProbeInlineStub(MF, MBB, MBBI, DL, true); } else { return emitStackProbeInline(MF, MBB, MBBI, DL, false); } } else { return emitStackProbeCall(MF, MBB, MBBI, DL, InProlog); } } void X86FrameLowering::inlineStackProbe(MachineFunction &MF, MachineBasicBlock &PrologMBB) const { const StringRef ChkStkStubSymbol = "__chkstk_stub"; MachineInstr *ChkStkStub = nullptr; for (MachineInstr &MI : PrologMBB) { if (MI.isCall() && MI.getOperand(0).isSymbol() && ChkStkStubSymbol == MI.getOperand(0).getSymbolName()) { ChkStkStub = &MI; break; } } if (ChkStkStub != nullptr) { MachineBasicBlock::iterator MBBI = std::next(ChkStkStub->getIterator()); assert(std::prev(MBBI).operator==(ChkStkStub) && "MBBI expected after __chkstk_stub."); DebugLoc DL = PrologMBB.findDebugLoc(MBBI); emitStackProbeInline(MF, PrologMBB, MBBI, DL, true); ChkStkStub->eraseFromParent(); } } MachineInstr *X86FrameLowering::emitStackProbeInline( MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, DebugLoc DL, bool InProlog) const { const X86Subtarget &STI = MF.getSubtarget(); assert(STI.is64Bit() && "different expansion needed for 32 bit"); assert(STI.isTargetWindowsCoreCLR() && "custom expansion expects CoreCLR"); const TargetInstrInfo &TII = *STI.getInstrInfo(); const BasicBlock *LLVM_BB = MBB.getBasicBlock(); // RAX contains the number of bytes of desired stack adjustment. // The handling here assumes this value has already been updated so as to // maintain stack alignment. // // We need to exit with RSP modified by this amount and execute suitable // page touches to notify the OS that we're growing the stack responsibly. // All stack probing must be done without modifying RSP. // // MBB: // SizeReg = RAX; // ZeroReg = 0 // CopyReg = RSP // Flags, TestReg = CopyReg - SizeReg // FinalReg = !Flags.Ovf ? TestReg : ZeroReg // LimitReg = gs magic thread env access // if FinalReg >= LimitReg goto ContinueMBB // RoundBB: // RoundReg = page address of FinalReg // LoopMBB: // LoopReg = PHI(LimitReg,ProbeReg) // ProbeReg = LoopReg - PageSize // [ProbeReg] = 0 // if (ProbeReg > RoundReg) goto LoopMBB // ContinueMBB: // RSP = RSP - RAX // [rest of original MBB] // Set up the new basic blocks MachineBasicBlock *RoundMBB = MF.CreateMachineBasicBlock(LLVM_BB); MachineBasicBlock *LoopMBB = MF.CreateMachineBasicBlock(LLVM_BB); MachineBasicBlock *ContinueMBB = MF.CreateMachineBasicBlock(LLVM_BB); MachineFunction::iterator MBBIter = std::next(MBB.getIterator()); MF.insert(MBBIter, RoundMBB); MF.insert(MBBIter, LoopMBB); MF.insert(MBBIter, ContinueMBB); // Split MBB and move the tail portion down to ContinueMBB. MachineBasicBlock::iterator BeforeMBBI = std::prev(MBBI); ContinueMBB->splice(ContinueMBB->begin(), &MBB, MBBI, MBB.end()); ContinueMBB->transferSuccessorsAndUpdatePHIs(&MBB); // Some useful constants const int64_t ThreadEnvironmentStackLimit = 0x10; const int64_t PageSize = 0x1000; const int64_t PageMask = ~(PageSize - 1); // Registers we need. For the normal case we use virtual // registers. For the prolog expansion we use RAX, RCX and RDX. MachineRegisterInfo &MRI = MF.getRegInfo(); const TargetRegisterClass *RegClass = &X86::GR64RegClass; const unsigned SizeReg = InProlog ? (unsigned)X86::RAX : MRI.createVirtualRegister(RegClass), ZeroReg = InProlog ? (unsigned)X86::RCX : MRI.createVirtualRegister(RegClass), CopyReg = InProlog ? (unsigned)X86::RDX : MRI.createVirtualRegister(RegClass), TestReg = InProlog ? (unsigned)X86::RDX : MRI.createVirtualRegister(RegClass), FinalReg = InProlog ? (unsigned)X86::RDX : MRI.createVirtualRegister(RegClass), RoundedReg = InProlog ? (unsigned)X86::RDX : MRI.createVirtualRegister(RegClass), LimitReg = InProlog ? (unsigned)X86::RCX : MRI.createVirtualRegister(RegClass), JoinReg = InProlog ? (unsigned)X86::RCX : MRI.createVirtualRegister(RegClass), ProbeReg = InProlog ? (unsigned)X86::RCX : MRI.createVirtualRegister(RegClass); // SP-relative offsets where we can save RCX and RDX. int64_t RCXShadowSlot = 0; int64_t RDXShadowSlot = 0; // If inlining in the prolog, save RCX and RDX. // Future optimization: don't save or restore if not live in. if (InProlog) { // Compute the offsets. We need to account for things already // pushed onto the stack at this point: return address, frame // pointer (if used), and callee saves. X86MachineFunctionInfo *X86FI = MF.getInfo(); const int64_t CalleeSaveSize = X86FI->getCalleeSavedFrameSize(); const bool HasFP = hasFP(MF); RCXShadowSlot = 8 + CalleeSaveSize + (HasFP ? 8 : 0); RDXShadowSlot = RCXShadowSlot + 8; // Emit the saves. addRegOffset(BuildMI(&MBB, DL, TII.get(X86::MOV64mr)), X86::RSP, false, RCXShadowSlot) .addReg(X86::RCX); addRegOffset(BuildMI(&MBB, DL, TII.get(X86::MOV64mr)), X86::RSP, false, RDXShadowSlot) .addReg(X86::RDX); } else { // Not in the prolog. Copy RAX to a virtual reg. BuildMI(&MBB, DL, TII.get(X86::MOV64rr), SizeReg).addReg(X86::RAX); } // Add code to MBB to check for overflow and set the new target stack pointer // to zero if so. BuildMI(&MBB, DL, TII.get(X86::XOR64rr), ZeroReg) .addReg(ZeroReg, RegState::Undef) .addReg(ZeroReg, RegState::Undef); BuildMI(&MBB, DL, TII.get(X86::MOV64rr), CopyReg).addReg(X86::RSP); BuildMI(&MBB, DL, TII.get(X86::SUB64rr), TestReg) .addReg(CopyReg) .addReg(SizeReg); BuildMI(&MBB, DL, TII.get(X86::CMOVB64rr), FinalReg) .addReg(TestReg) .addReg(ZeroReg); // FinalReg now holds final stack pointer value, or zero if // allocation would overflow. Compare against the current stack // limit from the thread environment block. Note this limit is the // lowest touched page on the stack, not the point at which the OS // will cause an overflow exception, so this is just an optimization // to avoid unnecessarily touching pages that are below the current // SP but already commited to the stack by the OS. BuildMI(&MBB, DL, TII.get(X86::MOV64rm), LimitReg) .addReg(0) .addImm(1) .addReg(0) .addImm(ThreadEnvironmentStackLimit) .addReg(X86::GS); BuildMI(&MBB, DL, TII.get(X86::CMP64rr)).addReg(FinalReg).addReg(LimitReg); // Jump if the desired stack pointer is at or above the stack limit. BuildMI(&MBB, DL, TII.get(X86::JAE_1)).addMBB(ContinueMBB); // Add code to roundMBB to round the final stack pointer to a page boundary. BuildMI(RoundMBB, DL, TII.get(X86::AND64ri32), RoundedReg) .addReg(FinalReg) .addImm(PageMask); BuildMI(RoundMBB, DL, TII.get(X86::JMP_1)).addMBB(LoopMBB); // LimitReg now holds the current stack limit, RoundedReg page-rounded // final RSP value. Add code to loopMBB to decrement LimitReg page-by-page // and probe until we reach RoundedReg. if (!InProlog) { BuildMI(LoopMBB, DL, TII.get(X86::PHI), JoinReg) .addReg(LimitReg) .addMBB(RoundMBB) .addReg(ProbeReg) .addMBB(LoopMBB); } addRegOffset(BuildMI(LoopMBB, DL, TII.get(X86::LEA64r), ProbeReg), JoinReg, false, -PageSize); // Probe by storing a byte onto the stack. BuildMI(LoopMBB, DL, TII.get(X86::MOV8mi)) .addReg(ProbeReg) .addImm(1) .addReg(0) .addImm(0) .addReg(0) .addImm(0); BuildMI(LoopMBB, DL, TII.get(X86::CMP64rr)) .addReg(RoundedReg) .addReg(ProbeReg); BuildMI(LoopMBB, DL, TII.get(X86::JNE_1)).addMBB(LoopMBB); MachineBasicBlock::iterator ContinueMBBI = ContinueMBB->getFirstNonPHI(); // If in prolog, restore RDX and RCX. if (InProlog) { addRegOffset(BuildMI(*ContinueMBB, ContinueMBBI, DL, TII.get(X86::MOV64rm), X86::RCX), X86::RSP, false, RCXShadowSlot); addRegOffset(BuildMI(*ContinueMBB, ContinueMBBI, DL, TII.get(X86::MOV64rm), X86::RDX), X86::RSP, false, RDXShadowSlot); } // Now that the probing is done, add code to continueMBB to update // the stack pointer for real. BuildMI(*ContinueMBB, ContinueMBBI, DL, TII.get(X86::SUB64rr), X86::RSP) .addReg(X86::RSP) .addReg(SizeReg); // Add the control flow edges we need. MBB.addSuccessor(ContinueMBB); MBB.addSuccessor(RoundMBB); RoundMBB->addSuccessor(LoopMBB); LoopMBB->addSuccessor(ContinueMBB); LoopMBB->addSuccessor(LoopMBB); // Mark all the instructions added to the prolog as frame setup. if (InProlog) { for (++BeforeMBBI; BeforeMBBI != MBB.end(); ++BeforeMBBI) { BeforeMBBI->setFlag(MachineInstr::FrameSetup); } for (MachineInstr &MI : *RoundMBB) { MI.setFlag(MachineInstr::FrameSetup); } for (MachineInstr &MI : *LoopMBB) { MI.setFlag(MachineInstr::FrameSetup); } for (MachineBasicBlock::iterator CMBBI = ContinueMBB->begin(); CMBBI != ContinueMBBI; ++CMBBI) { CMBBI->setFlag(MachineInstr::FrameSetup); } } // Possible TODO: physreg liveness for InProlog case. return ContinueMBBI; } MachineInstr *X86FrameLowering::emitStackProbeCall( MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, DebugLoc DL, bool InProlog) const { bool IsLargeCodeModel = MF.getTarget().getCodeModel() == CodeModel::Large; unsigned CallOp; if (Is64Bit) CallOp = IsLargeCodeModel ? X86::CALL64r : X86::CALL64pcrel32; else CallOp = X86::CALLpcrel32; const char *Symbol; if (Is64Bit) { if (STI.isTargetCygMing()) { Symbol = "___chkstk_ms"; } else { Symbol = "__chkstk"; } } else if (STI.isTargetCygMing()) Symbol = "_alloca"; else Symbol = "_chkstk"; MachineInstrBuilder CI; MachineBasicBlock::iterator ExpansionMBBI = std::prev(MBBI); // All current stack probes take AX and SP as input, clobber flags, and // preserve all registers. x86_64 probes leave RSP unmodified. if (Is64Bit && MF.getTarget().getCodeModel() == CodeModel::Large) { // For the large code model, we have to call through a register. Use R11, // as it is scratch in all supported calling conventions. BuildMI(MBB, MBBI, DL, TII.get(X86::MOV64ri), X86::R11) .addExternalSymbol(Symbol); CI = BuildMI(MBB, MBBI, DL, TII.get(CallOp)).addReg(X86::R11); } else { CI = BuildMI(MBB, MBBI, DL, TII.get(CallOp)).addExternalSymbol(Symbol); } unsigned AX = Is64Bit ? X86::RAX : X86::EAX; unsigned SP = Is64Bit ? X86::RSP : X86::ESP; CI.addReg(AX, RegState::Implicit) .addReg(SP, RegState::Implicit) .addReg(AX, RegState::Define | RegState::Implicit) .addReg(SP, RegState::Define | RegState::Implicit) .addReg(X86::EFLAGS, RegState::Define | RegState::Implicit); if (Is64Bit) { // MSVC x64's __chkstk and cygwin/mingw's ___chkstk_ms do not adjust %rsp // themselves. It also does not clobber %rax so we can reuse it when // adjusting %rsp. BuildMI(MBB, MBBI, DL, TII.get(X86::SUB64rr), X86::RSP) .addReg(X86::RSP) .addReg(X86::RAX); } if (InProlog) { // Apply the frame setup flag to all inserted instrs. for (++ExpansionMBBI; ExpansionMBBI != MBBI; ++ExpansionMBBI) ExpansionMBBI->setFlag(MachineInstr::FrameSetup); } return MBBI; } MachineInstr *X86FrameLowering::emitStackProbeInlineStub( MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, DebugLoc DL, bool InProlog) const { assert(InProlog && "ChkStkStub called outside prolog!"); BuildMI(MBB, MBBI, DL, TII.get(X86::CALLpcrel32)) .addExternalSymbol("__chkstk_stub"); return MBBI; } static unsigned calculateSetFPREG(uint64_t SPAdjust) { // Win64 ABI has a less restrictive limitation of 240; 128 works equally well // and might require smaller successive adjustments. const uint64_t Win64MaxSEHOffset = 128; uint64_t SEHFrameOffset = std::min(SPAdjust, Win64MaxSEHOffset); // Win64 ABI requires 16-byte alignment for the UWOP_SET_FPREG opcode. return SEHFrameOffset & -16; } // If we're forcing a stack realignment we can't rely on just the frame // info, we need to know the ABI stack alignment as well in case we // have a call out. Otherwise just make sure we have some alignment - we'll // go with the minimum SlotSize. uint64_t X86FrameLowering::calculateMaxStackAlign(const MachineFunction &MF) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); uint64_t MaxAlign = MFI->getMaxAlignment(); // Desired stack alignment. unsigned StackAlign = getStackAlignment(); if (MF.getFunction()->hasFnAttribute("stackrealign")) { if (MFI->hasCalls()) MaxAlign = (StackAlign > MaxAlign) ? StackAlign : MaxAlign; else if (MaxAlign < SlotSize) MaxAlign = SlotSize; } return MaxAlign; } void X86FrameLowering::BuildStackAlignAND(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, DebugLoc DL, unsigned Reg, uint64_t MaxAlign) const { uint64_t Val = -MaxAlign; unsigned AndOp = getANDriOpcode(Uses64BitFramePtr, Val); MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(AndOp), Reg) .addReg(Reg) .addImm(Val) .setMIFlag(MachineInstr::FrameSetup); // The EFLAGS implicit def is dead. MI->getOperand(3).setIsDead(); } /// emitPrologue - Push callee-saved registers onto the stack, which /// automatically adjust the stack pointer. Adjust the stack pointer to allocate /// space for local variables. Also emit labels used by the exception handler to /// generate the exception handling frames. /* Here's a gist of what gets emitted: ; Establish frame pointer, if needed [if needs FP] push %rbp .cfi_def_cfa_offset 16 .cfi_offset %rbp, -16 .seh_pushreg %rpb mov %rsp, %rbp .cfi_def_cfa_register %rbp ; Spill general-purpose registers [for all callee-saved GPRs] pushq % [if not needs FP] .cfi_def_cfa_offset (offset from RETADDR) .seh_pushreg % ; If the required stack alignment > default stack alignment ; rsp needs to be re-aligned. This creates a "re-alignment gap" ; of unknown size in the stack frame. [if stack needs re-alignment] and $MASK, %rsp ; Allocate space for locals [if target is Windows and allocated space > 4096 bytes] ; Windows needs special care for allocations larger ; than one page. mov $NNN, %rax call ___chkstk_ms/___chkstk sub %rax, %rsp [else] sub $NNN, %rsp [if needs FP] .seh_stackalloc (size of XMM spill slots) .seh_setframe %rbp, SEHFrameOffset ; = size of all spill slots [else] .seh_stackalloc NNN ; Spill XMMs ; Note, that while only Windows 64 ABI specifies XMMs as callee-preserved, ; they may get spilled on any platform, if the current function ; calls @llvm.eh.unwind.init [if needs FP] [for all callee-saved XMM registers] movaps %, -MMM(%rbp) [for all callee-saved XMM registers] .seh_savexmm %, (-MMM + SEHFrameOffset) ; i.e. the offset relative to (%rbp - SEHFrameOffset) [else] [for all callee-saved XMM registers] movaps %, KKK(%rsp) [for all callee-saved XMM registers] .seh_savexmm %, KKK .seh_endprologue [if needs base pointer] mov %rsp, %rbx [if needs to restore base pointer] mov %rsp, -MMM(%rbp) ; Emit CFI info [if needs FP] [for all callee-saved registers] .cfi_offset %, (offset from %rbp) [else] .cfi_def_cfa_offset (offset from RETADDR) [for all callee-saved registers] .cfi_offset %, (offset from %rsp) Notes: - .seh directives are emitted only for Windows 64 ABI - .cfi directives are emitted for all other ABIs - for 32-bit code, substitute %e?? registers for %r?? */ void X86FrameLowering::emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const { assert(&STI == &MF.getSubtarget() && "MF used frame lowering for wrong subtarget"); MachineBasicBlock::iterator MBBI = MBB.begin(); MachineFrameInfo *MFI = MF.getFrameInfo(); const Function *Fn = MF.getFunction(); MachineModuleInfo &MMI = MF.getMMI(); X86MachineFunctionInfo *X86FI = MF.getInfo(); uint64_t MaxAlign = calculateMaxStackAlign(MF); // Desired stack alignment. uint64_t StackSize = MFI->getStackSize(); // Number of bytes to allocate. bool IsFunclet = MBB.isEHFuncletEntry(); EHPersonality Personality = EHPersonality::Unknown; if (Fn->hasPersonalityFn()) Personality = classifyEHPersonality(Fn->getPersonalityFn()); bool FnHasClrFunclet = MMI.hasEHFunclets() && Personality == EHPersonality::CoreCLR; bool IsClrFunclet = IsFunclet && FnHasClrFunclet; bool HasFP = hasFP(MF); bool IsWin64CC = STI.isCallingConvWin64(Fn->getCallingConv()); bool IsWin64Prologue = MF.getTarget().getMCAsmInfo()->usesWindowsCFI(); bool NeedsWinCFI = IsWin64Prologue && Fn->needsUnwindTableEntry(); bool NeedsDwarfCFI = !IsWin64Prologue && (MMI.hasDebugInfo() || Fn->needsUnwindTableEntry()); unsigned FramePtr = TRI->getFrameRegister(MF); const unsigned MachineFramePtr = STI.isTarget64BitILP32() ? getX86SubSuperRegister(FramePtr, 64) : FramePtr; unsigned BasePtr = TRI->getBaseRegister(); // Debug location must be unknown since the first debug location is used // to determine the end of the prologue. DebugLoc DL; // Add RETADDR move area to callee saved frame size. int TailCallReturnAddrDelta = X86FI->getTCReturnAddrDelta(); if (TailCallReturnAddrDelta && IsWin64Prologue) report_fatal_error("Can't handle guaranteed tail call under win64 yet"); if (TailCallReturnAddrDelta < 0) X86FI->setCalleeSavedFrameSize( X86FI->getCalleeSavedFrameSize() - TailCallReturnAddrDelta); bool UseStackProbe = (STI.isOSWindows() && !STI.isTargetMachO()); // The default stack probe size is 4096 if the function has no stackprobesize // attribute. unsigned StackProbeSize = 4096; if (Fn->hasFnAttribute("stack-probe-size")) Fn->getFnAttribute("stack-probe-size") .getValueAsString() .getAsInteger(0, StackProbeSize); // If this is x86-64 and the Red Zone is not disabled, if we are a leaf // function, and use up to 128 bytes of stack space, don't have a frame // pointer, calls, or dynamic alloca then we do not need to adjust the // stack pointer (we fit in the Red Zone). We also check that we don't // push and pop from the stack. if (Is64Bit && !Fn->hasFnAttribute(Attribute::NoRedZone) && !TRI->needsStackRealignment(MF) && !MFI->hasVarSizedObjects() && // No dynamic alloca. !MFI->adjustsStack() && // No calls. !IsWin64CC && // Win64 has no Red Zone !MFI->hasCopyImplyingStackAdjustment() && // Don't push and pop. !MF.shouldSplitStack()) { // Regular stack uint64_t MinSize = X86FI->getCalleeSavedFrameSize(); if (HasFP) MinSize += SlotSize; StackSize = std::max(MinSize, StackSize > 128 ? StackSize - 128 : 0); MFI->setStackSize(StackSize); } // Insert stack pointer adjustment for later moving of return addr. Only // applies to tail call optimized functions where the callee argument stack // size is bigger than the callers. if (TailCallReturnAddrDelta < 0) { BuildStackAdjustment(MBB, MBBI, DL, TailCallReturnAddrDelta, /*InEpilogue=*/false) .setMIFlag(MachineInstr::FrameSetup); } // Mapping for machine moves: // // DST: VirtualFP AND // SRC: VirtualFP => DW_CFA_def_cfa_offset // ELSE => DW_CFA_def_cfa // // SRC: VirtualFP AND // DST: Register => DW_CFA_def_cfa_register // // ELSE // OFFSET < 0 => DW_CFA_offset_extended_sf // REG < 64 => DW_CFA_offset + Reg // ELSE => DW_CFA_offset_extended uint64_t NumBytes = 0; int stackGrowth = -SlotSize; // Find the funclet establisher parameter unsigned Establisher = X86::NoRegister; if (IsClrFunclet) Establisher = Uses64BitFramePtr ? X86::RCX : X86::ECX; else if (IsFunclet) Establisher = Uses64BitFramePtr ? X86::RDX : X86::EDX; if (IsWin64Prologue && IsFunclet && !IsClrFunclet) { // Immediately spill establisher into the home slot. // The runtime cares about this. // MOV64mr %rdx, 16(%rsp) unsigned MOVmr = Uses64BitFramePtr ? X86::MOV64mr : X86::MOV32mr; addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(MOVmr)), StackPtr, true, 16) .addReg(Establisher) .setMIFlag(MachineInstr::FrameSetup); MBB.addLiveIn(Establisher); } if (HasFP) { // Calculate required stack adjustment. uint64_t FrameSize = StackSize - SlotSize; // If required, include space for extra hidden slot for stashing base pointer. if (X86FI->getRestoreBasePointer()) FrameSize += SlotSize; NumBytes = FrameSize - X86FI->getCalleeSavedFrameSize(); // Callee-saved registers are pushed on stack before the stack is realigned. if (TRI->needsStackRealignment(MF) && !IsWin64Prologue) NumBytes = RoundUpToAlignment(NumBytes, MaxAlign); // Get the offset of the stack slot for the EBP register, which is // guaranteed to be the last slot by processFunctionBeforeFrameFinalized. // Update the frame offset adjustment. if (!IsFunclet) MFI->setOffsetAdjustment(-NumBytes); else assert(MFI->getOffsetAdjustment() == -(int)NumBytes && "should calculate same local variable offset for funclets"); // Save EBP/RBP into the appropriate stack slot. BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::PUSH64r : X86::PUSH32r)) .addReg(MachineFramePtr, RegState::Kill) .setMIFlag(MachineInstr::FrameSetup); if (NeedsDwarfCFI) { // Mark the place where EBP/RBP was saved. // Define the current CFA rule to use the provided offset. assert(StackSize); BuildCFI(MBB, MBBI, DL, MCCFIInstruction::createDefCfaOffset(nullptr, 2 * stackGrowth)); // Change the rule for the FramePtr to be an "offset" rule. unsigned DwarfFramePtr = TRI->getDwarfRegNum(MachineFramePtr, true); BuildCFI(MBB, MBBI, DL, MCCFIInstruction::createOffset( nullptr, DwarfFramePtr, 2 * stackGrowth)); } if (NeedsWinCFI) { BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_PushReg)) .addImm(FramePtr) .setMIFlag(MachineInstr::FrameSetup); } if (!IsWin64Prologue && !IsFunclet) { // Update EBP with the new base value. BuildMI(MBB, MBBI, DL, TII.get(Uses64BitFramePtr ? X86::MOV64rr : X86::MOV32rr), FramePtr) .addReg(StackPtr) .setMIFlag(MachineInstr::FrameSetup); if (NeedsDwarfCFI) { // Mark effective beginning of when frame pointer becomes valid. // Define the current CFA to use the EBP/RBP register. unsigned DwarfFramePtr = TRI->getDwarfRegNum(MachineFramePtr, true); BuildCFI(MBB, MBBI, DL, MCCFIInstruction::createDefCfaRegister( nullptr, DwarfFramePtr)); } } // Mark the FramePtr as live-in in every block. Don't do this again for // funclet prologues. if (!IsFunclet) { for (MachineBasicBlock &EveryMBB : MF) EveryMBB.addLiveIn(MachineFramePtr); } } else { assert(!IsFunclet && "funclets without FPs not yet implemented"); NumBytes = StackSize - X86FI->getCalleeSavedFrameSize(); } // For EH funclets, only allocate enough space for outgoing calls. Save the // NumBytes value that we would've used for the parent frame. unsigned ParentFrameNumBytes = NumBytes; if (IsFunclet) NumBytes = getWinEHFuncletFrameSize(MF); // Skip the callee-saved push instructions. bool PushedRegs = false; int StackOffset = 2 * stackGrowth; while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup) && (MBBI->getOpcode() == X86::PUSH32r || MBBI->getOpcode() == X86::PUSH64r)) { PushedRegs = true; unsigned Reg = MBBI->getOperand(0).getReg(); ++MBBI; if (!HasFP && NeedsDwarfCFI) { // Mark callee-saved push instruction. // Define the current CFA rule to use the provided offset. assert(StackSize); BuildCFI(MBB, MBBI, DL, MCCFIInstruction::createDefCfaOffset(nullptr, StackOffset)); StackOffset += stackGrowth; } if (NeedsWinCFI) { BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_PushReg)).addImm(Reg).setMIFlag( MachineInstr::FrameSetup); } } // Realign stack after we pushed callee-saved registers (so that we'll be // able to calculate their offsets from the frame pointer). // Don't do this for Win64, it needs to realign the stack after the prologue. if (!IsWin64Prologue && !IsFunclet && TRI->needsStackRealignment(MF)) { assert(HasFP && "There should be a frame pointer if stack is realigned."); BuildStackAlignAND(MBB, MBBI, DL, StackPtr, MaxAlign); } // If there is an SUB32ri of ESP immediately before this instruction, merge // the two. This can be the case when tail call elimination is enabled and // the callee has more arguments then the caller. NumBytes -= mergeSPUpdates(MBB, MBBI, true); // Adjust stack pointer: ESP -= numbytes. // Windows and cygwin/mingw require a prologue helper routine when allocating // more than 4K bytes on the stack. Windows uses __chkstk and cygwin/mingw // uses __alloca. __alloca and the 32-bit version of __chkstk will probe the // stack and adjust the stack pointer in one go. The 64-bit version of // __chkstk is only responsible for probing the stack. The 64-bit prologue is // responsible for adjusting the stack pointer. Touching the stack at 4K // increments is necessary to ensure that the guard pages used by the OS // virtual memory manager are allocated in correct sequence. uint64_t AlignedNumBytes = NumBytes; if (IsWin64Prologue && !IsFunclet && TRI->needsStackRealignment(MF)) AlignedNumBytes = RoundUpToAlignment(AlignedNumBytes, MaxAlign); if (AlignedNumBytes >= StackProbeSize && UseStackProbe) { - // Check whether EAX is livein for this function. - bool isEAXAlive = isEAXLiveIn(MF); + // Check whether EAX is livein for this block. + bool isEAXAlive = isEAXLiveIn(MBB); if (isEAXAlive) { // Sanity check that EAX is not livein for this function. // It should not be, so throw an assert. assert(!Is64Bit && "EAX is livein in x64 case!"); // Save EAX BuildMI(MBB, MBBI, DL, TII.get(X86::PUSH32r)) .addReg(X86::EAX, RegState::Kill) .setMIFlag(MachineInstr::FrameSetup); } if (Is64Bit) { // Handle the 64-bit Windows ABI case where we need to call __chkstk. // Function prologue is responsible for adjusting the stack pointer. if (isUInt<32>(NumBytes)) { BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32ri), X86::EAX) .addImm(NumBytes) .setMIFlag(MachineInstr::FrameSetup); } else if (isInt<32>(NumBytes)) { BuildMI(MBB, MBBI, DL, TII.get(X86::MOV64ri32), X86::RAX) .addImm(NumBytes) .setMIFlag(MachineInstr::FrameSetup); } else { BuildMI(MBB, MBBI, DL, TII.get(X86::MOV64ri), X86::RAX) .addImm(NumBytes) .setMIFlag(MachineInstr::FrameSetup); } } else { // Allocate NumBytes-4 bytes on stack in case of isEAXAlive. // We'll also use 4 already allocated bytes for EAX. BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32ri), X86::EAX) .addImm(isEAXAlive ? NumBytes - 4 : NumBytes) .setMIFlag(MachineInstr::FrameSetup); } // Call __chkstk, __chkstk_ms, or __alloca. emitStackProbe(MF, MBB, MBBI, DL, true); if (isEAXAlive) { // Restore EAX MachineInstr *MI = addRegOffset(BuildMI(MF, DL, TII.get(X86::MOV32rm), X86::EAX), StackPtr, false, NumBytes - 4); MI->setFlag(MachineInstr::FrameSetup); MBB.insert(MBBI, MI); } } else if (NumBytes) { emitSPUpdate(MBB, MBBI, -(int64_t)NumBytes, /*InEpilogue=*/false); } if (NeedsWinCFI && NumBytes) BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_StackAlloc)) .addImm(NumBytes) .setMIFlag(MachineInstr::FrameSetup); int SEHFrameOffset = 0; unsigned SPOrEstablisher; if (IsFunclet) { if (IsClrFunclet) { // The establisher parameter passed to a CLR funclet is actually a pointer // to the (mostly empty) frame of its nearest enclosing funclet; we have // to find the root function establisher frame by loading the PSPSym from // the intermediate frame. unsigned PSPSlotOffset = getPSPSlotOffsetFromSP(MF); MachinePointerInfo NoInfo; MBB.addLiveIn(Establisher); addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV64rm), Establisher), Establisher, false, PSPSlotOffset) .addMemOperand(MF.getMachineMemOperand( NoInfo, MachineMemOperand::MOLoad, SlotSize, SlotSize)); ; // Save the root establisher back into the current funclet's (mostly // empty) frame, in case a sub-funclet or the GC needs it. addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV64mr)), StackPtr, false, PSPSlotOffset) .addReg(Establisher) .addMemOperand( MF.getMachineMemOperand(NoInfo, MachineMemOperand::MOStore | MachineMemOperand::MOVolatile, SlotSize, SlotSize)); } SPOrEstablisher = Establisher; } else { SPOrEstablisher = StackPtr; } if (IsWin64Prologue && HasFP) { // Set RBP to a small fixed offset from RSP. In the funclet case, we base // this calculation on the incoming establisher, which holds the value of // RSP from the parent frame at the end of the prologue. SEHFrameOffset = calculateSetFPREG(ParentFrameNumBytes); if (SEHFrameOffset) addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::LEA64r), FramePtr), SPOrEstablisher, false, SEHFrameOffset); else BuildMI(MBB, MBBI, DL, TII.get(X86::MOV64rr), FramePtr) .addReg(SPOrEstablisher); // If this is not a funclet, emit the CFI describing our frame pointer. if (NeedsWinCFI && !IsFunclet) { BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_SetFrame)) .addImm(FramePtr) .addImm(SEHFrameOffset) .setMIFlag(MachineInstr::FrameSetup); if (isAsynchronousEHPersonality(Personality)) MF.getWinEHFuncInfo()->SEHSetFrameOffset = SEHFrameOffset; } } else if (IsFunclet && STI.is32Bit()) { // Reset EBP / ESI to something good for funclets. MBBI = restoreWin32EHStackPointers(MBB, MBBI, DL); // If we're a catch funclet, we can be returned to via catchret. Save ESP // into the registration node so that the runtime will restore it for us. if (!MBB.isCleanupFuncletEntry()) { assert(Personality == EHPersonality::MSVC_CXX); unsigned FrameReg; int FI = MF.getWinEHFuncInfo()->EHRegNodeFrameIndex; int64_t EHRegOffset = getFrameIndexReference(MF, FI, FrameReg); // ESP is the first field, so no extra displacement is needed. addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32mr)), FrameReg, false, EHRegOffset) .addReg(X86::ESP); } } while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup)) { const MachineInstr *FrameInstr = &*MBBI; ++MBBI; if (NeedsWinCFI) { int FI; if (unsigned Reg = TII.isStoreToStackSlot(FrameInstr, FI)) { if (X86::FR64RegClass.contains(Reg)) { unsigned IgnoredFrameReg; int Offset = getFrameIndexReference(MF, FI, IgnoredFrameReg); Offset += SEHFrameOffset; BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_SaveXMM)) .addImm(Reg) .addImm(Offset) .setMIFlag(MachineInstr::FrameSetup); } } } } if (NeedsWinCFI) BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_EndPrologue)) .setMIFlag(MachineInstr::FrameSetup); if (FnHasClrFunclet && !IsFunclet) { // Save the so-called Initial-SP (i.e. the value of the stack pointer // immediately after the prolog) into the PSPSlot so that funclets // and the GC can recover it. unsigned PSPSlotOffset = getPSPSlotOffsetFromSP(MF); auto PSPInfo = MachinePointerInfo::getFixedStack( MF, MF.getWinEHFuncInfo()->PSPSymFrameIdx); addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV64mr)), StackPtr, false, PSPSlotOffset) .addReg(StackPtr) .addMemOperand(MF.getMachineMemOperand( PSPInfo, MachineMemOperand::MOStore | MachineMemOperand::MOVolatile, SlotSize, SlotSize)); } // Realign stack after we spilled callee-saved registers (so that we'll be // able to calculate their offsets from the frame pointer). // Win64 requires aligning the stack after the prologue. if (IsWin64Prologue && TRI->needsStackRealignment(MF)) { assert(HasFP && "There should be a frame pointer if stack is realigned."); BuildStackAlignAND(MBB, MBBI, DL, SPOrEstablisher, MaxAlign); } // We already dealt with stack realignment and funclets above. if (IsFunclet && STI.is32Bit()) return; // If we need a base pointer, set it up here. It's whatever the value // of the stack pointer is at this point. Any variable size objects // will be allocated after this, so we can still use the base pointer // to reference locals. if (TRI->hasBasePointer(MF)) { // Update the base pointer with the current stack pointer. unsigned Opc = Uses64BitFramePtr ? X86::MOV64rr : X86::MOV32rr; BuildMI(MBB, MBBI, DL, TII.get(Opc), BasePtr) .addReg(SPOrEstablisher) .setMIFlag(MachineInstr::FrameSetup); if (X86FI->getRestoreBasePointer()) { // Stash value of base pointer. Saving RSP instead of EBP shortens // dependence chain. Used by SjLj EH. unsigned Opm = Uses64BitFramePtr ? X86::MOV64mr : X86::MOV32mr; addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(Opm)), FramePtr, true, X86FI->getRestoreBasePointerOffset()) .addReg(SPOrEstablisher) .setMIFlag(MachineInstr::FrameSetup); } if (X86FI->getHasSEHFramePtrSave() && !IsFunclet) { // Stash the value of the frame pointer relative to the base pointer for // Win32 EH. This supports Win32 EH, which does the inverse of the above: // it recovers the frame pointer from the base pointer rather than the // other way around. unsigned Opm = Uses64BitFramePtr ? X86::MOV64mr : X86::MOV32mr; unsigned UsedReg; int Offset = getFrameIndexReference(MF, X86FI->getSEHFramePtrSaveIndex(), UsedReg); assert(UsedReg == BasePtr); addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(Opm)), UsedReg, true, Offset) .addReg(FramePtr) .setMIFlag(MachineInstr::FrameSetup); } } if (((!HasFP && NumBytes) || PushedRegs) && NeedsDwarfCFI) { // Mark end of stack pointer adjustment. if (!HasFP && NumBytes) { // Define the current CFA rule to use the provided offset. assert(StackSize); BuildCFI(MBB, MBBI, DL, MCCFIInstruction::createDefCfaOffset( nullptr, -StackSize + stackGrowth)); } // Emit DWARF info specifying the offsets of the callee-saved registers. if (PushedRegs) emitCalleeSavedFrameMoves(MBB, MBBI, DL); } } bool X86FrameLowering::canUseLEAForSPInEpilogue( const MachineFunction &MF) const { // We can't use LEA instructions for adjusting the stack pointer if this is a // leaf function in the Win64 ABI. Only ADD instructions may be used to // deallocate the stack. // This means that we can use LEA for SP in two situations: // 1. We *aren't* using the Win64 ABI which means we are free to use LEA. // 2. We *have* a frame pointer which means we are permitted to use LEA. return !MF.getTarget().getMCAsmInfo()->usesWindowsCFI() || hasFP(MF); } static bool isFuncletReturnInstr(MachineInstr *MI) { switch (MI->getOpcode()) { case X86::CATCHRET: case X86::CLEANUPRET: return true; default: return false; } llvm_unreachable("impossible"); } // CLR funclets use a special "Previous Stack Pointer Symbol" slot on the // stack. It holds a pointer to the bottom of the root function frame. The // establisher frame pointer passed to a nested funclet may point to the // (mostly empty) frame of its parent funclet, but it will need to find // the frame of the root function to access locals. To facilitate this, // every funclet copies the pointer to the bottom of the root function // frame into a PSPSym slot in its own (mostly empty) stack frame. Using the // same offset for the PSPSym in the root function frame that's used in the // funclets' frames allows each funclet to dynamically accept any ancestor // frame as its establisher argument (the runtime doesn't guarantee the // immediate parent for some reason lost to history), and also allows the GC, // which uses the PSPSym for some bookkeeping, to find it in any funclet's // frame with only a single offset reported for the entire method. unsigned X86FrameLowering::getPSPSlotOffsetFromSP(const MachineFunction &MF) const { const WinEHFuncInfo &Info = *MF.getWinEHFuncInfo(); // getFrameIndexReferenceFromSP has an out ref parameter for the stack // pointer register; pass a dummy that we ignore unsigned SPReg; int Offset = getFrameIndexReferenceFromSP(MF, Info.PSPSymFrameIdx, SPReg); assert(Offset >= 0); return static_cast(Offset); } unsigned X86FrameLowering::getWinEHFuncletFrameSize(const MachineFunction &MF) const { // This is the size of the pushed CSRs. unsigned CSSize = MF.getInfo()->getCalleeSavedFrameSize(); // This is the amount of stack a funclet needs to allocate. unsigned UsedSize; EHPersonality Personality = classifyEHPersonality(MF.getFunction()->getPersonalityFn()); if (Personality == EHPersonality::CoreCLR) { // CLR funclets need to hold enough space to include the PSPSym, at the // same offset from the stack pointer (immediately after the prolog) as it // resides at in the main function. UsedSize = getPSPSlotOffsetFromSP(MF) + SlotSize; } else { // Other funclets just need enough stack for outgoing call arguments. UsedSize = MF.getFrameInfo()->getMaxCallFrameSize(); } // RBP is not included in the callee saved register block. After pushing RBP, // everything is 16 byte aligned. Everything we allocate before an outgoing // call must also be 16 byte aligned. unsigned FrameSizeMinusRBP = RoundUpToAlignment(CSSize + UsedSize, getStackAlignment()); // Subtract out the size of the callee saved registers. This is how much stack // each funclet will allocate. return FrameSizeMinusRBP - CSSize; } void X86FrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); X86MachineFunctionInfo *X86FI = MF.getInfo(); MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator(); DebugLoc DL; if (MBBI != MBB.end()) DL = MBBI->getDebugLoc(); // standard x86_64 and NaCl use 64-bit frame/stack pointers, x32 - 32-bit. const bool Is64BitILP32 = STI.isTarget64BitILP32(); unsigned FramePtr = TRI->getFrameRegister(MF); unsigned MachineFramePtr = Is64BitILP32 ? getX86SubSuperRegister(FramePtr, 64) : FramePtr; bool IsWin64Prologue = MF.getTarget().getMCAsmInfo()->usesWindowsCFI(); bool NeedsWinCFI = IsWin64Prologue && MF.getFunction()->needsUnwindTableEntry(); bool IsFunclet = isFuncletReturnInstr(MBBI); MachineBasicBlock *TargetMBB = nullptr; // Get the number of bytes to allocate from the FrameInfo. uint64_t StackSize = MFI->getStackSize(); uint64_t MaxAlign = calculateMaxStackAlign(MF); unsigned CSSize = X86FI->getCalleeSavedFrameSize(); uint64_t NumBytes = 0; if (MBBI->getOpcode() == X86::CATCHRET) { // SEH shouldn't use catchret. assert(!isAsynchronousEHPersonality( classifyEHPersonality(MF.getFunction()->getPersonalityFn())) && "SEH should not use CATCHRET"); NumBytes = getWinEHFuncletFrameSize(MF); assert(hasFP(MF) && "EH funclets without FP not yet implemented"); TargetMBB = MBBI->getOperand(0).getMBB(); // Pop EBP. BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r), MachineFramePtr) .setMIFlag(MachineInstr::FrameDestroy); } else if (MBBI->getOpcode() == X86::CLEANUPRET) { NumBytes = getWinEHFuncletFrameSize(MF); assert(hasFP(MF) && "EH funclets without FP not yet implemented"); BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r), MachineFramePtr) .setMIFlag(MachineInstr::FrameDestroy); } else if (hasFP(MF)) { // Calculate required stack adjustment. uint64_t FrameSize = StackSize - SlotSize; NumBytes = FrameSize - CSSize; // Callee-saved registers were pushed on stack before the stack was // realigned. if (TRI->needsStackRealignment(MF) && !IsWin64Prologue) NumBytes = RoundUpToAlignment(FrameSize, MaxAlign); // Pop EBP. BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r), MachineFramePtr) .setMIFlag(MachineInstr::FrameDestroy); } else { NumBytes = StackSize - CSSize; } uint64_t SEHStackAllocAmt = NumBytes; // Skip the callee-saved pop instructions. while (MBBI != MBB.begin()) { MachineBasicBlock::iterator PI = std::prev(MBBI); unsigned Opc = PI->getOpcode(); if ((Opc != X86::POP32r || !PI->getFlag(MachineInstr::FrameDestroy)) && (Opc != X86::POP64r || !PI->getFlag(MachineInstr::FrameDestroy)) && Opc != X86::DBG_VALUE && !PI->isTerminator()) break; --MBBI; } MachineBasicBlock::iterator FirstCSPop = MBBI; if (TargetMBB) { // Fill EAX/RAX with the address of the target block. unsigned ReturnReg = STI.is64Bit() ? X86::RAX : X86::EAX; if (STI.is64Bit()) { // LEA64r TargetMBB(%rip), %rax BuildMI(MBB, FirstCSPop, DL, TII.get(X86::LEA64r), ReturnReg) .addReg(X86::RIP) .addImm(0) .addReg(0) .addMBB(TargetMBB) .addReg(0); } else { // MOV32ri $TargetMBB, %eax BuildMI(MBB, FirstCSPop, DL, TII.get(X86::MOV32ri), ReturnReg) .addMBB(TargetMBB); } // Record that we've taken the address of TargetMBB and no longer just // reference it in a terminator. TargetMBB->setHasAddressTaken(); } if (MBBI != MBB.end()) DL = MBBI->getDebugLoc(); // If there is an ADD32ri or SUB32ri of ESP immediately before this // instruction, merge the two instructions. if (NumBytes || MFI->hasVarSizedObjects()) NumBytes += mergeSPUpdates(MBB, MBBI, true); // If dynamic alloca is used, then reset esp to point to the last callee-saved // slot before popping them off! Same applies for the case, when stack was // realigned. Don't do this if this was a funclet epilogue, since the funclets // will not do realignment or dynamic stack allocation. if ((TRI->needsStackRealignment(MF) || MFI->hasVarSizedObjects()) && !IsFunclet) { if (TRI->needsStackRealignment(MF)) MBBI = FirstCSPop; unsigned SEHFrameOffset = calculateSetFPREG(SEHStackAllocAmt); uint64_t LEAAmount = IsWin64Prologue ? SEHStackAllocAmt - SEHFrameOffset : -CSSize; // There are only two legal forms of epilogue: // - add SEHAllocationSize, %rsp // - lea SEHAllocationSize(%FramePtr), %rsp // // 'mov %FramePtr, %rsp' will not be recognized as an epilogue sequence. // However, we may use this sequence if we have a frame pointer because the // effects of the prologue can safely be undone. if (LEAAmount != 0) { unsigned Opc = getLEArOpcode(Uses64BitFramePtr); addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(Opc), StackPtr), FramePtr, false, LEAAmount); --MBBI; } else { unsigned Opc = (Uses64BitFramePtr ? X86::MOV64rr : X86::MOV32rr); BuildMI(MBB, MBBI, DL, TII.get(Opc), StackPtr) .addReg(FramePtr); --MBBI; } } else if (NumBytes) { // Adjust stack pointer back: ESP += numbytes. emitSPUpdate(MBB, MBBI, NumBytes, /*InEpilogue=*/true); --MBBI; } // Windows unwinder will not invoke function's exception handler if IP is // either in prologue or in epilogue. This behavior causes a problem when a // call immediately precedes an epilogue, because the return address points // into the epilogue. To cope with that, we insert an epilogue marker here, // then replace it with a 'nop' if it ends up immediately after a CALL in the // final emitted code. if (NeedsWinCFI) BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_Epilogue)); // Add the return addr area delta back since we are not tail calling. int Offset = -1 * X86FI->getTCReturnAddrDelta(); assert(Offset >= 0 && "TCDelta should never be positive"); if (Offset) { MBBI = MBB.getFirstTerminator(); // Check for possible merge with preceding ADD instruction. Offset += mergeSPUpdates(MBB, MBBI, true); emitSPUpdate(MBB, MBBI, Offset, /*InEpilogue=*/true); } } // NOTE: this only has a subset of the full frame index logic. In // particular, the FI < 0 and AfterFPPop logic is handled in // X86RegisterInfo::eliminateFrameIndex, but not here. Possibly // (probably?) it should be moved into here. int X86FrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, unsigned &FrameReg) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); // We can't calculate offset from frame pointer if the stack is realigned, // so enforce usage of stack/base pointer. The base pointer is used when we // have dynamic allocas in addition to dynamic realignment. if (TRI->hasBasePointer(MF)) FrameReg = TRI->getBaseRegister(); else if (TRI->needsStackRealignment(MF)) FrameReg = TRI->getStackRegister(); else FrameReg = TRI->getFrameRegister(MF); // Offset will hold the offset from the stack pointer at function entry to the // object. // We need to factor in additional offsets applied during the prologue to the // frame, base, and stack pointer depending on which is used. int Offset = MFI->getObjectOffset(FI) - getOffsetOfLocalArea(); const X86MachineFunctionInfo *X86FI = MF.getInfo(); unsigned CSSize = X86FI->getCalleeSavedFrameSize(); uint64_t StackSize = MFI->getStackSize(); bool HasFP = hasFP(MF); bool IsWin64Prologue = MF.getTarget().getMCAsmInfo()->usesWindowsCFI(); int64_t FPDelta = 0; if (IsWin64Prologue) { assert(!MFI->hasCalls() || (StackSize % 16) == 8); // Calculate required stack adjustment. uint64_t FrameSize = StackSize - SlotSize; // If required, include space for extra hidden slot for stashing base pointer. if (X86FI->getRestoreBasePointer()) FrameSize += SlotSize; uint64_t NumBytes = FrameSize - CSSize; uint64_t SEHFrameOffset = calculateSetFPREG(NumBytes); if (FI && FI == X86FI->getFAIndex()) return -SEHFrameOffset; // FPDelta is the offset from the "traditional" FP location of the old base // pointer followed by return address and the location required by the // restricted Win64 prologue. // Add FPDelta to all offsets below that go through the frame pointer. FPDelta = FrameSize - SEHFrameOffset; assert((!MFI->hasCalls() || (FPDelta % 16) == 0) && "FPDelta isn't aligned per the Win64 ABI!"); } if (TRI->hasBasePointer(MF)) { assert(HasFP && "VLAs and dynamic stack realign, but no FP?!"); if (FI < 0) { // Skip the saved EBP. return Offset + SlotSize + FPDelta; } else { assert((-(Offset + StackSize)) % MFI->getObjectAlignment(FI) == 0); return Offset + StackSize; } } else if (TRI->needsStackRealignment(MF)) { if (FI < 0) { // Skip the saved EBP. return Offset + SlotSize + FPDelta; } else { assert((-(Offset + StackSize)) % MFI->getObjectAlignment(FI) == 0); return Offset + StackSize; } // FIXME: Support tail calls } else { if (!HasFP) return Offset + StackSize; // Skip the saved EBP. Offset += SlotSize; // Skip the RETADDR move area int TailCallReturnAddrDelta = X86FI->getTCReturnAddrDelta(); if (TailCallReturnAddrDelta < 0) Offset -= TailCallReturnAddrDelta; } return Offset + FPDelta; } // Simplified from getFrameIndexReference keeping only StackPointer cases int X86FrameLowering::getFrameIndexReferenceFromSP(const MachineFunction &MF, int FI, unsigned &FrameReg) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); // Does not include any dynamic realign. const uint64_t StackSize = MFI->getStackSize(); { #ifndef NDEBUG // LLVM arranges the stack as follows: // ... // ARG2 // ARG1 // RETADDR // PUSH RBP <-- RBP points here // PUSH CSRs // ~~~~~~~ <-- possible stack realignment (non-win64) // ... // STACK OBJECTS // ... <-- RSP after prologue points here // ~~~~~~~ <-- possible stack realignment (win64) // // if (hasVarSizedObjects()): // ... <-- "base pointer" (ESI/RBX) points here // DYNAMIC ALLOCAS // ... <-- RSP points here // // Case 1: In the simple case of no stack realignment and no dynamic // allocas, both "fixed" stack objects (arguments and CSRs) are addressable // with fixed offsets from RSP. // // Case 2: In the case of stack realignment with no dynamic allocas, fixed // stack objects are addressed with RBP and regular stack objects with RSP. // // Case 3: In the case of dynamic allocas and stack realignment, RSP is used // to address stack arguments for outgoing calls and nothing else. The "base // pointer" points to local variables, and RBP points to fixed objects. // // In cases 2 and 3, we can only answer for non-fixed stack objects, and the // answer we give is relative to the SP after the prologue, and not the // SP in the middle of the function. assert((!MFI->isFixedObjectIndex(FI) || !TRI->needsStackRealignment(MF) || STI.isTargetWin64()) && "offset from fixed object to SP is not static"); // We don't handle tail calls, and shouldn't be seeing them either. int TailCallReturnAddrDelta = MF.getInfo()->getTCReturnAddrDelta(); assert(!(TailCallReturnAddrDelta < 0) && "we don't handle this case!"); #endif } // Fill in FrameReg output argument. FrameReg = TRI->getStackRegister(); // This is how the math works out: // // %rsp grows (i.e. gets lower) left to right. Each box below is // one word (eight bytes). Obj0 is the stack slot we're trying to // get to. // // ---------------------------------- // | BP | Obj0 | Obj1 | ... | ObjN | // ---------------------------------- // ^ ^ ^ ^ // A B C E // // A is the incoming stack pointer. // (B - A) is the local area offset (-8 for x86-64) [1] // (C - A) is the Offset returned by MFI->getObjectOffset for Obj0 [2] // // |(E - B)| is the StackSize (absolute value, positive). For a // stack that grown down, this works out to be (B - E). [3] // // E is also the value of %rsp after stack has been set up, and we // want (C - E) -- the value we can add to %rsp to get to Obj0. Now // (C - E) == (C - A) - (B - A) + (B - E) // { Using [1], [2] and [3] above } // == getObjectOffset - LocalAreaOffset + StackSize // // Get the Offset from the StackPointer int Offset = MFI->getObjectOffset(FI) - getOffsetOfLocalArea(); return Offset + StackSize; } bool X86FrameLowering::assignCalleeSavedSpillSlots( MachineFunction &MF, const TargetRegisterInfo *TRI, std::vector &CSI) const { MachineFrameInfo *MFI = MF.getFrameInfo(); X86MachineFunctionInfo *X86FI = MF.getInfo(); unsigned CalleeSavedFrameSize = 0; int SpillSlotOffset = getOffsetOfLocalArea() + X86FI->getTCReturnAddrDelta(); if (hasFP(MF)) { // emitPrologue always spills frame register the first thing. SpillSlotOffset -= SlotSize; MFI->CreateFixedSpillStackObject(SlotSize, SpillSlotOffset); // Since emitPrologue and emitEpilogue will handle spilling and restoring of // the frame register, we can delete it from CSI list and not have to worry // about avoiding it later. unsigned FPReg = TRI->getFrameRegister(MF); for (unsigned i = 0; i < CSI.size(); ++i) { if (TRI->regsOverlap(CSI[i].getReg(),FPReg)) { CSI.erase(CSI.begin() + i); break; } } } // Assign slots for GPRs. It increases frame size. for (unsigned i = CSI.size(); i != 0; --i) { unsigned Reg = CSI[i - 1].getReg(); if (!X86::GR64RegClass.contains(Reg) && !X86::GR32RegClass.contains(Reg)) continue; SpillSlotOffset -= SlotSize; CalleeSavedFrameSize += SlotSize; int SlotIndex = MFI->CreateFixedSpillStackObject(SlotSize, SpillSlotOffset); CSI[i - 1].setFrameIdx(SlotIndex); } X86FI->setCalleeSavedFrameSize(CalleeSavedFrameSize); // Assign slots for XMMs. for (unsigned i = CSI.size(); i != 0; --i) { unsigned Reg = CSI[i - 1].getReg(); if (X86::GR64RegClass.contains(Reg) || X86::GR32RegClass.contains(Reg)) continue; const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); // ensure alignment SpillSlotOffset -= std::abs(SpillSlotOffset) % RC->getAlignment(); // spill into slot SpillSlotOffset -= RC->getSize(); int SlotIndex = MFI->CreateFixedSpillStackObject(RC->getSize(), SpillSlotOffset); CSI[i - 1].setFrameIdx(SlotIndex); MFI->ensureMaxAlignment(RC->getAlignment()); } return true; } bool X86FrameLowering::spillCalleeSavedRegisters( MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, const std::vector &CSI, const TargetRegisterInfo *TRI) const { DebugLoc DL = MBB.findDebugLoc(MI); // Don't save CSRs in 32-bit EH funclets. The caller saves EBX, EBP, ESI, EDI // for us, and there are no XMM CSRs on Win32. if (MBB.isEHFuncletEntry() && STI.is32Bit() && STI.isOSWindows()) return true; // Push GPRs. It increases frame size. unsigned Opc = STI.is64Bit() ? X86::PUSH64r : X86::PUSH32r; for (unsigned i = CSI.size(); i != 0; --i) { unsigned Reg = CSI[i - 1].getReg(); if (!X86::GR64RegClass.contains(Reg) && !X86::GR32RegClass.contains(Reg)) continue; // Add the callee-saved register as live-in. It's killed at the spill. MBB.addLiveIn(Reg); BuildMI(MBB, MI, DL, TII.get(Opc)).addReg(Reg, RegState::Kill) .setMIFlag(MachineInstr::FrameSetup); } // Make XMM regs spilled. X86 does not have ability of push/pop XMM. // It can be done by spilling XMMs to stack frame. for (unsigned i = CSI.size(); i != 0; --i) { unsigned Reg = CSI[i-1].getReg(); if (X86::GR64RegClass.contains(Reg) || X86::GR32RegClass.contains(Reg)) continue; // Add the callee-saved register as live-in. It's killed at the spill. MBB.addLiveIn(Reg); const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); TII.storeRegToStackSlot(MBB, MI, Reg, true, CSI[i - 1].getFrameIdx(), RC, TRI); --MI; MI->setFlag(MachineInstr::FrameSetup); ++MI; } return true; } bool X86FrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, const std::vector &CSI, const TargetRegisterInfo *TRI) const { if (CSI.empty()) return false; if (isFuncletReturnInstr(MI) && STI.isOSWindows()) { // Don't restore CSRs in 32-bit EH funclets. Matches // spillCalleeSavedRegisters. if (STI.is32Bit()) return true; // Don't restore CSRs before an SEH catchret. SEH except blocks do not form // funclets. emitEpilogue transforms these to normal jumps. if (MI->getOpcode() == X86::CATCHRET) { const Function *Func = MBB.getParent()->getFunction(); bool IsSEH = isAsynchronousEHPersonality( classifyEHPersonality(Func->getPersonalityFn())); if (IsSEH) return true; } } DebugLoc DL = MBB.findDebugLoc(MI); // Reload XMMs from stack frame. for (unsigned i = 0, e = CSI.size(); i != e; ++i) { unsigned Reg = CSI[i].getReg(); if (X86::GR64RegClass.contains(Reg) || X86::GR32RegClass.contains(Reg)) continue; const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); TII.loadRegFromStackSlot(MBB, MI, Reg, CSI[i].getFrameIdx(), RC, TRI); } // POP GPRs. unsigned Opc = STI.is64Bit() ? X86::POP64r : X86::POP32r; for (unsigned i = 0, e = CSI.size(); i != e; ++i) { unsigned Reg = CSI[i].getReg(); if (!X86::GR64RegClass.contains(Reg) && !X86::GR32RegClass.contains(Reg)) continue; BuildMI(MBB, MI, DL, TII.get(Opc), Reg) .setMIFlag(MachineInstr::FrameDestroy); } return true; } void X86FrameLowering::determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS) const { TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); MachineFrameInfo *MFI = MF.getFrameInfo(); X86MachineFunctionInfo *X86FI = MF.getInfo(); int64_t TailCallReturnAddrDelta = X86FI->getTCReturnAddrDelta(); if (TailCallReturnAddrDelta < 0) { // create RETURNADDR area // arg // arg // RETADDR // { ... // RETADDR area // ... // } // [EBP] MFI->CreateFixedObject(-TailCallReturnAddrDelta, TailCallReturnAddrDelta - SlotSize, true); } // Spill the BasePtr if it's used. if (TRI->hasBasePointer(MF)) { SavedRegs.set(TRI->getBaseRegister()); // Allocate a spill slot for EBP if we have a base pointer and EH funclets. if (MF.getMMI().hasEHFunclets()) { int FI = MFI->CreateSpillStackObject(SlotSize, SlotSize); X86FI->setHasSEHFramePtrSave(true); X86FI->setSEHFramePtrSaveIndex(FI); } } } static bool HasNestArgument(const MachineFunction *MF) { const Function *F = MF->getFunction(); for (Function::const_arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; I++) { if (I->hasNestAttr()) return true; } return false; } /// GetScratchRegister - Get a temp register for performing work in the /// segmented stack and the Erlang/HiPE stack prologue. Depending on platform /// and the properties of the function either one or two registers will be /// needed. Set primary to true for the first register, false for the second. static unsigned GetScratchRegister(bool Is64Bit, bool IsLP64, const MachineFunction &MF, bool Primary) { CallingConv::ID CallingConvention = MF.getFunction()->getCallingConv(); // Erlang stuff. if (CallingConvention == CallingConv::HiPE) { if (Is64Bit) return Primary ? X86::R14 : X86::R13; else return Primary ? X86::EBX : X86::EDI; } if (Is64Bit) { if (IsLP64) return Primary ? X86::R11 : X86::R12; else return Primary ? X86::R11D : X86::R12D; } bool IsNested = HasNestArgument(&MF); if (CallingConvention == CallingConv::X86_FastCall || CallingConvention == CallingConv::Fast) { if (IsNested) report_fatal_error("Segmented stacks does not support fastcall with " "nested function."); return Primary ? X86::EAX : X86::ECX; } if (IsNested) return Primary ? X86::EDX : X86::EAX; return Primary ? X86::ECX : X86::EAX; } // The stack limit in the TCB is set to this many bytes above the actual stack // limit. static const uint64_t kSplitStackAvailable = 256; void X86FrameLowering::adjustForSegmentedStacks( MachineFunction &MF, MachineBasicBlock &PrologueMBB) const { MachineFrameInfo *MFI = MF.getFrameInfo(); uint64_t StackSize; unsigned TlsReg, TlsOffset; DebugLoc DL; // To support shrink-wrapping we would need to insert the new blocks // at the right place and update the branches to PrologueMBB. assert(&(*MF.begin()) == &PrologueMBB && "Shrink-wrapping not supported yet"); unsigned ScratchReg = GetScratchRegister(Is64Bit, IsLP64, MF, true); assert(!MF.getRegInfo().isLiveIn(ScratchReg) && "Scratch register is live-in"); if (MF.getFunction()->isVarArg()) report_fatal_error("Segmented stacks do not support vararg functions."); if (!STI.isTargetLinux() && !STI.isTargetDarwin() && !STI.isTargetWin32() && !STI.isTargetWin64() && !STI.isTargetFreeBSD() && !STI.isTargetDragonFly()) report_fatal_error("Segmented stacks not supported on this platform."); // Eventually StackSize will be calculated by a link-time pass; which will // also decide whether checking code needs to be injected into this particular // prologue. StackSize = MFI->getStackSize(); // Do not generate a prologue for functions with a stack of size zero if (StackSize == 0) return; MachineBasicBlock *allocMBB = MF.CreateMachineBasicBlock(); MachineBasicBlock *checkMBB = MF.CreateMachineBasicBlock(); X86MachineFunctionInfo *X86FI = MF.getInfo(); bool IsNested = false; // We need to know if the function has a nest argument only in 64 bit mode. if (Is64Bit) IsNested = HasNestArgument(&MF); // The MOV R10, RAX needs to be in a different block, since the RET we emit in // allocMBB needs to be last (terminating) instruction. for (const auto &LI : PrologueMBB.liveins()) { allocMBB->addLiveIn(LI); checkMBB->addLiveIn(LI); } if (IsNested) allocMBB->addLiveIn(IsLP64 ? X86::R10 : X86::R10D); MF.push_front(allocMBB); MF.push_front(checkMBB); // When the frame size is less than 256 we just compare the stack // boundary directly to the value of the stack pointer, per gcc. bool CompareStackPointer = StackSize < kSplitStackAvailable; // Read the limit off the current stacklet off the stack_guard location. if (Is64Bit) { if (STI.isTargetLinux()) { TlsReg = X86::FS; TlsOffset = IsLP64 ? 0x70 : 0x40; } else if (STI.isTargetDarwin()) { TlsReg = X86::GS; TlsOffset = 0x60 + 90*8; // See pthread_machdep.h. Steal TLS slot 90. } else if (STI.isTargetWin64()) { TlsReg = X86::GS; TlsOffset = 0x28; // pvArbitrary, reserved for application use } else if (STI.isTargetFreeBSD()) { TlsReg = X86::FS; TlsOffset = 0x18; } else if (STI.isTargetDragonFly()) { TlsReg = X86::FS; TlsOffset = 0x20; // use tls_tcb.tcb_segstack } else { report_fatal_error("Segmented stacks not supported on this platform."); } if (CompareStackPointer) ScratchReg = IsLP64 ? X86::RSP : X86::ESP; else BuildMI(checkMBB, DL, TII.get(IsLP64 ? X86::LEA64r : X86::LEA64_32r), ScratchReg).addReg(X86::RSP) .addImm(1).addReg(0).addImm(-StackSize).addReg(0); BuildMI(checkMBB, DL, TII.get(IsLP64 ? X86::CMP64rm : X86::CMP32rm)).addReg(ScratchReg) .addReg(0).addImm(1).addReg(0).addImm(TlsOffset).addReg(TlsReg); } else { if (STI.isTargetLinux()) { TlsReg = X86::GS; TlsOffset = 0x30; } else if (STI.isTargetDarwin()) { TlsReg = X86::GS; TlsOffset = 0x48 + 90*4; } else if (STI.isTargetWin32()) { TlsReg = X86::FS; TlsOffset = 0x14; // pvArbitrary, reserved for application use } else if (STI.isTargetDragonFly()) { TlsReg = X86::FS; TlsOffset = 0x10; // use tls_tcb.tcb_segstack } else if (STI.isTargetFreeBSD()) { report_fatal_error("Segmented stacks not supported on FreeBSD i386."); } else { report_fatal_error("Segmented stacks not supported on this platform."); } if (CompareStackPointer) ScratchReg = X86::ESP; else BuildMI(checkMBB, DL, TII.get(X86::LEA32r), ScratchReg).addReg(X86::ESP) .addImm(1).addReg(0).addImm(-StackSize).addReg(0); if (STI.isTargetLinux() || STI.isTargetWin32() || STI.isTargetWin64() || STI.isTargetDragonFly()) { BuildMI(checkMBB, DL, TII.get(X86::CMP32rm)).addReg(ScratchReg) .addReg(0).addImm(0).addReg(0).addImm(TlsOffset).addReg(TlsReg); } else if (STI.isTargetDarwin()) { // TlsOffset doesn't fit into a mod r/m byte so we need an extra register. unsigned ScratchReg2; bool SaveScratch2; if (CompareStackPointer) { // The primary scratch register is available for holding the TLS offset. ScratchReg2 = GetScratchRegister(Is64Bit, IsLP64, MF, true); SaveScratch2 = false; } else { // Need to use a second register to hold the TLS offset ScratchReg2 = GetScratchRegister(Is64Bit, IsLP64, MF, false); // Unfortunately, with fastcc the second scratch register may hold an // argument. SaveScratch2 = MF.getRegInfo().isLiveIn(ScratchReg2); } // If Scratch2 is live-in then it needs to be saved. assert((!MF.getRegInfo().isLiveIn(ScratchReg2) || SaveScratch2) && "Scratch register is live-in and not saved"); if (SaveScratch2) BuildMI(checkMBB, DL, TII.get(X86::PUSH32r)) .addReg(ScratchReg2, RegState::Kill); BuildMI(checkMBB, DL, TII.get(X86::MOV32ri), ScratchReg2) .addImm(TlsOffset); BuildMI(checkMBB, DL, TII.get(X86::CMP32rm)) .addReg(ScratchReg) .addReg(ScratchReg2).addImm(1).addReg(0) .addImm(0) .addReg(TlsReg); if (SaveScratch2) BuildMI(checkMBB, DL, TII.get(X86::POP32r), ScratchReg2); } } // This jump is taken if SP >= (Stacklet Limit + Stack Space required). // It jumps to normal execution of the function body. BuildMI(checkMBB, DL, TII.get(X86::JA_1)).addMBB(&PrologueMBB); // On 32 bit we first push the arguments size and then the frame size. On 64 // bit, we pass the stack frame size in r10 and the argument size in r11. if (Is64Bit) { // Functions with nested arguments use R10, so it needs to be saved across // the call to _morestack const unsigned RegAX = IsLP64 ? X86::RAX : X86::EAX; const unsigned Reg10 = IsLP64 ? X86::R10 : X86::R10D; const unsigned Reg11 = IsLP64 ? X86::R11 : X86::R11D; const unsigned MOVrr = IsLP64 ? X86::MOV64rr : X86::MOV32rr; const unsigned MOVri = IsLP64 ? X86::MOV64ri : X86::MOV32ri; if (IsNested) BuildMI(allocMBB, DL, TII.get(MOVrr), RegAX).addReg(Reg10); BuildMI(allocMBB, DL, TII.get(MOVri), Reg10) .addImm(StackSize); BuildMI(allocMBB, DL, TII.get(MOVri), Reg11) .addImm(X86FI->getArgumentStackSize()); } else { BuildMI(allocMBB, DL, TII.get(X86::PUSHi32)) .addImm(X86FI->getArgumentStackSize()); BuildMI(allocMBB, DL, TII.get(X86::PUSHi32)) .addImm(StackSize); } // __morestack is in libgcc if (Is64Bit && MF.getTarget().getCodeModel() == CodeModel::Large) { // Under the large code model, we cannot assume that __morestack lives // within 2^31 bytes of the call site, so we cannot use pc-relative // addressing. We cannot perform the call via a temporary register, // as the rax register may be used to store the static chain, and all // other suitable registers may be either callee-save or used for // parameter passing. We cannot use the stack at this point either // because __morestack manipulates the stack directly. // // To avoid these issues, perform an indirect call via a read-only memory // location containing the address. // // This solution is not perfect, as it assumes that the .rodata section // is laid out within 2^31 bytes of each function body, but this seems // to be sufficient for JIT. BuildMI(allocMBB, DL, TII.get(X86::CALL64m)) .addReg(X86::RIP) .addImm(0) .addReg(0) .addExternalSymbol("__morestack_addr") .addReg(0); MF.getMMI().setUsesMorestackAddr(true); } else { if (Is64Bit) BuildMI(allocMBB, DL, TII.get(X86::CALL64pcrel32)) .addExternalSymbol("__morestack"); else BuildMI(allocMBB, DL, TII.get(X86::CALLpcrel32)) .addExternalSymbol("__morestack"); } if (IsNested) BuildMI(allocMBB, DL, TII.get(X86::MORESTACK_RET_RESTORE_R10)); else BuildMI(allocMBB, DL, TII.get(X86::MORESTACK_RET)); allocMBB->addSuccessor(&PrologueMBB); checkMBB->addSuccessor(allocMBB); checkMBB->addSuccessor(&PrologueMBB); #ifdef XDEBUG MF.verify(); #endif } /// Erlang programs may need a special prologue to handle the stack size they /// might need at runtime. That is because Erlang/OTP does not implement a C /// stack but uses a custom implementation of hybrid stack/heap architecture. /// (for more information see Eric Stenman's Ph.D. thesis: /// http://publications.uu.se/uu/fulltext/nbn_se_uu_diva-2688.pdf) /// /// CheckStack: /// temp0 = sp - MaxStack /// if( temp0 < SP_LIMIT(P) ) goto IncStack else goto OldStart /// OldStart: /// ... /// IncStack: /// call inc_stack # doubles the stack space /// temp0 = sp - MaxStack /// if( temp0 < SP_LIMIT(P) ) goto IncStack else goto OldStart void X86FrameLowering::adjustForHiPEPrologue( MachineFunction &MF, MachineBasicBlock &PrologueMBB) const { MachineFrameInfo *MFI = MF.getFrameInfo(); DebugLoc DL; // To support shrink-wrapping we would need to insert the new blocks // at the right place and update the branches to PrologueMBB. assert(&(*MF.begin()) == &PrologueMBB && "Shrink-wrapping not supported yet"); // HiPE-specific values const unsigned HipeLeafWords = 24; const unsigned CCRegisteredArgs = Is64Bit ? 6 : 5; const unsigned Guaranteed = HipeLeafWords * SlotSize; unsigned CallerStkArity = MF.getFunction()->arg_size() > CCRegisteredArgs ? MF.getFunction()->arg_size() - CCRegisteredArgs : 0; unsigned MaxStack = MFI->getStackSize() + CallerStkArity*SlotSize + SlotSize; assert(STI.isTargetLinux() && "HiPE prologue is only supported on Linux operating systems."); // Compute the largest caller's frame that is needed to fit the callees' // frames. This 'MaxStack' is computed from: // // a) the fixed frame size, which is the space needed for all spilled temps, // b) outgoing on-stack parameter areas, and // c) the minimum stack space this function needs to make available for the // functions it calls (a tunable ABI property). if (MFI->hasCalls()) { unsigned MoreStackForCalls = 0; for (MachineFunction::iterator MBBI = MF.begin(), MBBE = MF.end(); MBBI != MBBE; ++MBBI) for (MachineBasicBlock::iterator MI = MBBI->begin(), ME = MBBI->end(); MI != ME; ++MI) { if (!MI->isCall()) continue; // Get callee operand. const MachineOperand &MO = MI->getOperand(0); // Only take account of global function calls (no closures etc.). if (!MO.isGlobal()) continue; const Function *F = dyn_cast(MO.getGlobal()); if (!F) continue; // Do not update 'MaxStack' for primitive and built-in functions // (encoded with names either starting with "erlang."/"bif_" or not // having a ".", such as a simple .., or an // "_", such as the BIF "suspend_0") as they are executed on another // stack. if (F->getName().find("erlang.") != StringRef::npos || F->getName().find("bif_") != StringRef::npos || F->getName().find_first_of("._") == StringRef::npos) continue; unsigned CalleeStkArity = F->arg_size() > CCRegisteredArgs ? F->arg_size()-CCRegisteredArgs : 0; if (HipeLeafWords - 1 > CalleeStkArity) MoreStackForCalls = std::max(MoreStackForCalls, (HipeLeafWords - 1 - CalleeStkArity) * SlotSize); } MaxStack += MoreStackForCalls; } // If the stack frame needed is larger than the guaranteed then runtime checks // and calls to "inc_stack_0" BIF should be inserted in the assembly prologue. if (MaxStack > Guaranteed) { MachineBasicBlock *stackCheckMBB = MF.CreateMachineBasicBlock(); MachineBasicBlock *incStackMBB = MF.CreateMachineBasicBlock(); for (const auto &LI : PrologueMBB.liveins()) { stackCheckMBB->addLiveIn(LI); incStackMBB->addLiveIn(LI); } MF.push_front(incStackMBB); MF.push_front(stackCheckMBB); unsigned ScratchReg, SPReg, PReg, SPLimitOffset; unsigned LEAop, CMPop, CALLop; if (Is64Bit) { SPReg = X86::RSP; PReg = X86::RBP; LEAop = X86::LEA64r; CMPop = X86::CMP64rm; CALLop = X86::CALL64pcrel32; SPLimitOffset = 0x90; } else { SPReg = X86::ESP; PReg = X86::EBP; LEAop = X86::LEA32r; CMPop = X86::CMP32rm; CALLop = X86::CALLpcrel32; SPLimitOffset = 0x4c; } ScratchReg = GetScratchRegister(Is64Bit, IsLP64, MF, true); assert(!MF.getRegInfo().isLiveIn(ScratchReg) && "HiPE prologue scratch register is live-in"); // Create new MBB for StackCheck: addRegOffset(BuildMI(stackCheckMBB, DL, TII.get(LEAop), ScratchReg), SPReg, false, -MaxStack); // SPLimitOffset is in a fixed heap location (pointed by BP). addRegOffset(BuildMI(stackCheckMBB, DL, TII.get(CMPop)) .addReg(ScratchReg), PReg, false, SPLimitOffset); BuildMI(stackCheckMBB, DL, TII.get(X86::JAE_1)).addMBB(&PrologueMBB); // Create new MBB for IncStack: BuildMI(incStackMBB, DL, TII.get(CALLop)). addExternalSymbol("inc_stack_0"); addRegOffset(BuildMI(incStackMBB, DL, TII.get(LEAop), ScratchReg), SPReg, false, -MaxStack); addRegOffset(BuildMI(incStackMBB, DL, TII.get(CMPop)) .addReg(ScratchReg), PReg, false, SPLimitOffset); BuildMI(incStackMBB, DL, TII.get(X86::JLE_1)).addMBB(incStackMBB); stackCheckMBB->addSuccessor(&PrologueMBB, {99, 100}); stackCheckMBB->addSuccessor(incStackMBB, {1, 100}); incStackMBB->addSuccessor(&PrologueMBB, {99, 100}); incStackMBB->addSuccessor(incStackMBB, {1, 100}); } #ifdef XDEBUG MF.verify(); #endif } bool X86FrameLowering::adjustStackWithPops(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, DebugLoc DL, int Offset) const { if (Offset <= 0) return false; if (Offset % SlotSize) return false; int NumPops = Offset / SlotSize; // This is only worth it if we have at most 2 pops. if (NumPops != 1 && NumPops != 2) return false; // Handle only the trivial case where the adjustment directly follows // a call. This is the most common one, anyway. if (MBBI == MBB.begin()) return false; MachineBasicBlock::iterator Prev = std::prev(MBBI); if (!Prev->isCall() || !Prev->getOperand(1).isRegMask()) return false; unsigned Regs[2]; unsigned FoundRegs = 0; auto RegMask = Prev->getOperand(1); auto &RegClass = Is64Bit ? X86::GR64_NOREX_NOSPRegClass : X86::GR32_NOREX_NOSPRegClass; // Try to find up to NumPops free registers. for (auto Candidate : RegClass) { // Poor man's liveness: // Since we're immediately after a call, any register that is clobbered // by the call and not defined by it can be considered dead. if (!RegMask.clobbersPhysReg(Candidate)) continue; bool IsDef = false; for (const MachineOperand &MO : Prev->implicit_operands()) { if (MO.isReg() && MO.isDef() && MO.getReg() == Candidate) { IsDef = true; break; } } if (IsDef) continue; Regs[FoundRegs++] = Candidate; if (FoundRegs == (unsigned)NumPops) break; } if (FoundRegs == 0) return false; // If we found only one free register, but need two, reuse the same one twice. while (FoundRegs < (unsigned)NumPops) Regs[FoundRegs++] = Regs[0]; for (int i = 0; i < NumPops; ++i) BuildMI(MBB, MBBI, DL, TII.get(STI.is64Bit() ? X86::POP64r : X86::POP32r), Regs[i]); return true; } void X86FrameLowering:: eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const { bool reserveCallFrame = hasReservedCallFrame(MF); unsigned Opcode = I->getOpcode(); bool isDestroy = Opcode == TII.getCallFrameDestroyOpcode(); DebugLoc DL = I->getDebugLoc(); uint64_t Amount = !reserveCallFrame ? I->getOperand(0).getImm() : 0; uint64_t InternalAmt = (isDestroy || Amount) ? I->getOperand(1).getImm() : 0; I = MBB.erase(I); if (!reserveCallFrame) { // If the stack pointer can be changed after prologue, turn the // adjcallstackup instruction into a 'sub ESP, ' and the // adjcallstackdown instruction into 'add ESP, ' // We need to keep the stack aligned properly. To do this, we round the // amount of space needed for the outgoing arguments up to the next // alignment boundary. unsigned StackAlign = getStackAlignment(); Amount = RoundUpToAlignment(Amount, StackAlign); MachineModuleInfo &MMI = MF.getMMI(); const Function *Fn = MF.getFunction(); bool WindowsCFI = MF.getTarget().getMCAsmInfo()->usesWindowsCFI(); bool DwarfCFI = !WindowsCFI && (MMI.hasDebugInfo() || Fn->needsUnwindTableEntry()); // If we have any exception handlers in this function, and we adjust // the SP before calls, we may need to indicate this to the unwinder // using GNU_ARGS_SIZE. Note that this may be necessary even when // Amount == 0, because the preceding function may have set a non-0 // GNU_ARGS_SIZE. // TODO: We don't need to reset this between subsequent functions, // if it didn't change. bool HasDwarfEHHandlers = !WindowsCFI && !MF.getMMI().getLandingPads().empty(); if (HasDwarfEHHandlers && !isDestroy && MF.getInfo()->getHasPushSequences()) BuildCFI(MBB, I, DL, MCCFIInstruction::createGnuArgsSize(nullptr, Amount)); if (Amount == 0) return; // Factor out the amount that gets handled inside the sequence // (Pushes of argument for frame setup, callee pops for frame destroy) Amount -= InternalAmt; // TODO: This is needed only if we require precise CFA. // If this is a callee-pop calling convention, emit a CFA adjust for // the amount the callee popped. if (isDestroy && InternalAmt && DwarfCFI && !hasFP(MF)) BuildCFI(MBB, I, DL, MCCFIInstruction::createAdjustCfaOffset(nullptr, -InternalAmt)); if (Amount) { // Add Amount to SP to destroy a frame, and subtract to setup. int Offset = isDestroy ? Amount : -Amount; if (!(Fn->optForMinSize() && adjustStackWithPops(MBB, I, DL, Offset))) BuildStackAdjustment(MBB, I, DL, Offset, /*InEpilogue=*/false); } if (DwarfCFI && !hasFP(MF)) { // If we don't have FP, but need to generate unwind information, // we need to set the correct CFA offset after the stack adjustment. // How much we adjust the CFA offset depends on whether we're emitting // CFI only for EH purposes or for debugging. EH only requires the CFA // offset to be correct at each call site, while for debugging we want // it to be more precise. int CFAOffset = Amount; // TODO: When not using precise CFA, we also need to adjust for the // InternalAmt here. if (CFAOffset) { CFAOffset = isDestroy ? -CFAOffset : CFAOffset; BuildCFI(MBB, I, DL, MCCFIInstruction::createAdjustCfaOffset(nullptr, CFAOffset)); } } return; } if (isDestroy && InternalAmt) { // If we are performing frame pointer elimination and if the callee pops // something off the stack pointer, add it back. We do this until we have // more advanced stack pointer tracking ability. // We are not tracking the stack pointer adjustment by the callee, so make // sure we restore the stack pointer immediately after the call, there may // be spill code inserted between the CALL and ADJCALLSTACKUP instructions. MachineBasicBlock::iterator B = MBB.begin(); while (I != B && !std::prev(I)->isCall()) --I; BuildStackAdjustment(MBB, I, DL, -InternalAmt, /*InEpilogue=*/false); } } bool X86FrameLowering::canUseAsEpilogue(const MachineBasicBlock &MBB) const { assert(MBB.getParent() && "Block is not attached to a function!"); // Win64 has strict requirements in terms of epilogue and we are // not taking a chance at messing with them. // I.e., unless this block is already an exit block, we can't use // it as an epilogue. if (STI.isTargetWin64() && !MBB.succ_empty() && !MBB.isReturnBlock()) return false; if (canUseLEAForSPInEpilogue(*MBB.getParent())) return true; // If we cannot use LEA to adjust SP, we may need to use ADD, which // clobbers the EFLAGS. Check that we do not need to preserve it, // otherwise, conservatively assume this is not // safe to insert the epilogue here. return !flagsNeedToBePreservedBeforeTheTerminators(MBB); } bool X86FrameLowering::enableShrinkWrapping(const MachineFunction &MF) const { // If we may need to emit frameless compact unwind information, give // up as this is currently broken: PR25614. #if 1 return false; #else return (MF.getFunction()->hasFnAttribute(Attribute::NoUnwind) || hasFP(MF)) && // The lowering of segmented stack and HiPE only support entry blocks // as prologue blocks: PR26107. // This limitation may be lifted if we fix: // - adjustForSegmentedStacks // - adjustForHiPEPrologue MF.getFunction()->getCallingConv() != CallingConv::HiPE && !MF.shouldSplitStack(); #endif } MachineBasicBlock::iterator X86FrameLowering::restoreWin32EHStackPointers( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, DebugLoc DL, bool RestoreSP) const { assert(STI.isTargetWindowsMSVC() && "funclets only supported in MSVC env"); assert(STI.isTargetWin32() && "EBP/ESI restoration only required on win32"); assert(STI.is32Bit() && !Uses64BitFramePtr && "restoring EBP/ESI on non-32-bit target"); MachineFunction &MF = *MBB.getParent(); unsigned FramePtr = TRI->getFrameRegister(MF); unsigned BasePtr = TRI->getBaseRegister(); WinEHFuncInfo &FuncInfo = *MF.getWinEHFuncInfo(); X86MachineFunctionInfo *X86FI = MF.getInfo(); MachineFrameInfo *MFI = MF.getFrameInfo(); // FIXME: Don't set FrameSetup flag in catchret case. int FI = FuncInfo.EHRegNodeFrameIndex; int EHRegSize = MFI->getObjectSize(FI); if (RestoreSP) { // MOV32rm -EHRegSize(%ebp), %esp addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32rm), X86::ESP), X86::EBP, true, -EHRegSize) .setMIFlag(MachineInstr::FrameSetup); } unsigned UsedReg; int EHRegOffset = getFrameIndexReference(MF, FI, UsedReg); int EndOffset = -EHRegOffset - EHRegSize; FuncInfo.EHRegNodeEndOffset = EndOffset; if (UsedReg == FramePtr) { // ADD $offset, %ebp unsigned ADDri = getADDriOpcode(false, EndOffset); BuildMI(MBB, MBBI, DL, TII.get(ADDri), FramePtr) .addReg(FramePtr) .addImm(EndOffset) .setMIFlag(MachineInstr::FrameSetup) ->getOperand(3) .setIsDead(); assert(EndOffset >= 0 && "end of registration object above normal EBP position!"); } else if (UsedReg == BasePtr) { // LEA offset(%ebp), %esi addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::LEA32r), BasePtr), FramePtr, false, EndOffset) .setMIFlag(MachineInstr::FrameSetup); // MOV32rm SavedEBPOffset(%esi), %ebp assert(X86FI->getHasSEHFramePtrSave()); int Offset = getFrameIndexReference(MF, X86FI->getSEHFramePtrSaveIndex(), UsedReg); assert(UsedReg == BasePtr); addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32rm), FramePtr), UsedReg, true, Offset) .setMIFlag(MachineInstr::FrameSetup); } else { llvm_unreachable("32-bit frames with WinEH must use FramePtr or BasePtr"); } return MBBI; } unsigned X86FrameLowering::getWinEHParentFrameOffset(const MachineFunction &MF) const { // RDX, the parent frame pointer, is homed into 16(%rsp) in the prologue. unsigned Offset = 16; // RBP is immediately pushed. Offset += SlotSize; // All callee-saved registers are then pushed. Offset += MF.getInfo()->getCalleeSavedFrameSize(); // Every funclet allocates enough stack space for the largest outgoing call. Offset += getWinEHFuncletFrameSize(MF); return Offset; } void X86FrameLowering::processFunctionBeforeFrameFinalized( MachineFunction &MF, RegScavenger *RS) const { // If this function isn't doing Win64-style C++ EH, we don't need to do // anything. const Function *Fn = MF.getFunction(); if (!STI.is64Bit() || !MF.getMMI().hasEHFunclets() || classifyEHPersonality(Fn->getPersonalityFn()) != EHPersonality::MSVC_CXX) return; // Win64 C++ EH needs to allocate the UnwindHelp object at some fixed offset // relative to RSP after the prologue. Find the offset of the last fixed // object, so that we can allocate a slot immediately following it. If there // were no fixed objects, use offset -SlotSize, which is immediately after the // return address. Fixed objects have negative frame indices. MachineFrameInfo *MFI = MF.getFrameInfo(); int64_t MinFixedObjOffset = -SlotSize; for (int I = MFI->getObjectIndexBegin(); I < 0; ++I) MinFixedObjOffset = std::min(MinFixedObjOffset, MFI->getObjectOffset(I)); int64_t UnwindHelpOffset = MinFixedObjOffset - SlotSize; int UnwindHelpFI = MFI->CreateFixedObject(SlotSize, UnwindHelpOffset, /*Immutable=*/false); MF.getWinEHFuncInfo()->UnwindHelpFrameIdx = UnwindHelpFI; // Store -2 into UnwindHelp on function entry. We have to scan forwards past // other frame setup instructions. MachineBasicBlock &MBB = MF.front(); auto MBBI = MBB.begin(); while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup)) ++MBBI; DebugLoc DL = MBB.findDebugLoc(MBBI); addFrameReference(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV64mi32)), UnwindHelpFI) .addImm(-2); } Index: projects/clang380-import/contrib/llvm/lib/Target/X86/X86InstrAVX512.td =================================================================== --- projects/clang380-import/contrib/llvm/lib/Target/X86/X86InstrAVX512.td (revision 295858) +++ projects/clang380-import/contrib/llvm/lib/Target/X86/X86InstrAVX512.td (revision 295859) @@ -1,7487 +1,7487 @@ //===-- X86InstrAVX512.td - AVX512 Instruction Set ---------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file describes the X86 AVX512 instruction set, defining the // instructions, and properties of the instructions which are needed for code // generation, machine code emission, and analysis. // //===----------------------------------------------------------------------===// // Group template arguments that can be derived from the vector type (EltNum x // EltVT). These are things like the register class for the writemask, etc. // The idea is to pass one of these as the template argument rather than the // individual arguments. // The template is also used for scalar types, in this case numelts is 1. class X86VectorVTInfo { RegisterClass RC = rc; ValueType EltVT = eltvt; int NumElts = numelts; // Corresponding mask register class. RegisterClass KRC = !cast("VK" # NumElts); // Corresponding write-mask register class. RegisterClass KRCWM = !cast("VK" # NumElts # "WM"); // The GPR register class that can hold the write mask. Use GR8 for fewer // than 8 elements. Use shift-right and equal to work around the lack of // !lt in tablegen. RegisterClass MRC = !cast("GR" # !if (!eq (!srl(NumElts, 3), 0), 8, NumElts)); // Suffix used in the instruction mnemonic. string Suffix = suffix; // VTName is a string name for vector VT. For vector types it will be // v # NumElts # EltVT, so for vector of 8 elements of i32 it will be v8i32 // It is a little bit complex for scalar types, where NumElts = 1. // In this case we build v4f32 or v2f64 string VTName = "v" # !if (!eq (NumElts, 1), !if (!eq (EltVT.Size, 32), 4, !if (!eq (EltVT.Size, 64), 2, NumElts)), NumElts) # EltVT; // The vector VT. ValueType VT = !cast(VTName); string EltTypeName = !cast(EltVT); // Size of the element type in bits, e.g. 32 for v16i32. string EltSizeName = !subst("i", "", !subst("f", "", EltTypeName)); int EltSize = EltVT.Size; // "i" for integer types and "f" for floating-point types string TypeVariantName = !subst(EltSizeName, "", EltTypeName); // Size of RC in bits, e.g. 512 for VR512. int Size = VT.Size; // The corresponding memory operand, e.g. i512mem for VR512. X86MemOperand MemOp = !cast(TypeVariantName # Size # "mem"); X86MemOperand ScalarMemOp = !cast(EltVT # "mem"); // Load patterns // Note: For 128/256-bit integer VT we choose loadv2i64/loadv4i64 // due to load promotion during legalization PatFrag LdFrag = !cast("load" # !if (!eq (TypeVariantName, "i"), !if (!eq (Size, 128), "v2i64", !if (!eq (Size, 256), "v4i64", VTName)), VTName)); PatFrag AlignedLdFrag = !cast("alignedload" # !if (!eq (TypeVariantName, "i"), !if (!eq (Size, 128), "v2i64", !if (!eq (Size, 256), "v4i64", !if (!eq (Size, 512), !if (!eq (EltSize, 64), "v8i64", "v16i32"), VTName))), VTName)); PatFrag ScalarLdFrag = !cast("load" # EltVT); // The corresponding float type, e.g. v16f32 for v16i32 // Note: For EltSize < 32, FloatVT is illegal and TableGen // fails to compile, so we choose FloatVT = VT ValueType FloatVT = !cast( !if (!eq (!srl(EltSize,5),0), VTName, !if (!eq(TypeVariantName, "i"), "v" # NumElts # "f" # EltSize, VTName))); // The string to specify embedded broadcast in assembly. string BroadcastStr = "{1to" # NumElts # "}"; // 8-bit compressed displacement tuple/subvector format. This is only // defined for NumElts <= 8. CD8VForm CD8TupleForm = !if (!eq (!srl(NumElts, 4), 0), !cast("CD8VT" # NumElts), ?); SubRegIndex SubRegIdx = !if (!eq (Size, 128), sub_xmm, !if (!eq (Size, 256), sub_ymm, ?)); Domain ExeDomain = !if (!eq (EltTypeName, "f32"), SSEPackedSingle, !if (!eq (EltTypeName, "f64"), SSEPackedDouble, SSEPackedInt)); RegisterClass FRC = !if (!eq (EltTypeName, "f32"), FR32X, FR64X); // A vector type of the same width with element type i32. This is used to // create the canonical constant zero node ImmAllZerosV. ValueType i32VT = !cast("v" # !srl(Size, 5) # "i32"); dag ImmAllZerosV = (VT (bitconvert (i32VT immAllZerosV))); string ZSuffix = !if (!eq (Size, 128), "Z128", !if (!eq (Size, 256), "Z256", "Z")); } def v64i8_info : X86VectorVTInfo<64, i8, VR512, "b">; def v32i16_info : X86VectorVTInfo<32, i16, VR512, "w">; def v16i32_info : X86VectorVTInfo<16, i32, VR512, "d">; def v8i64_info : X86VectorVTInfo<8, i64, VR512, "q">; def v16f32_info : X86VectorVTInfo<16, f32, VR512, "ps">; def v8f64_info : X86VectorVTInfo<8, f64, VR512, "pd">; // "x" in v32i8x_info means RC = VR256X def v32i8x_info : X86VectorVTInfo<32, i8, VR256X, "b">; def v16i16x_info : X86VectorVTInfo<16, i16, VR256X, "w">; def v8i32x_info : X86VectorVTInfo<8, i32, VR256X, "d">; def v4i64x_info : X86VectorVTInfo<4, i64, VR256X, "q">; def v8f32x_info : X86VectorVTInfo<8, f32, VR256X, "ps">; def v4f64x_info : X86VectorVTInfo<4, f64, VR256X, "pd">; def v16i8x_info : X86VectorVTInfo<16, i8, VR128X, "b">; def v8i16x_info : X86VectorVTInfo<8, i16, VR128X, "w">; def v4i32x_info : X86VectorVTInfo<4, i32, VR128X, "d">; def v2i64x_info : X86VectorVTInfo<2, i64, VR128X, "q">; def v4f32x_info : X86VectorVTInfo<4, f32, VR128X, "ps">; def v2f64x_info : X86VectorVTInfo<2, f64, VR128X, "pd">; // We map scalar types to the smallest (128-bit) vector type // with the appropriate element type. This allows to use the same masking logic. def i32x_info : X86VectorVTInfo<1, i32, GR32, "si">; def i64x_info : X86VectorVTInfo<1, i64, GR64, "sq">; def f32x_info : X86VectorVTInfo<1, f32, VR128X, "ss">; def f64x_info : X86VectorVTInfo<1, f64, VR128X, "sd">; class AVX512VLVectorVTInfo { X86VectorVTInfo info512 = i512; X86VectorVTInfo info256 = i256; X86VectorVTInfo info128 = i128; } def avx512vl_i8_info : AVX512VLVectorVTInfo; def avx512vl_i16_info : AVX512VLVectorVTInfo; def avx512vl_i32_info : AVX512VLVectorVTInfo; def avx512vl_i64_info : AVX512VLVectorVTInfo; def avx512vl_f32_info : AVX512VLVectorVTInfo; def avx512vl_f64_info : AVX512VLVectorVTInfo; // This multiclass generates the masking variants from the non-masking // variant. It only provides the assembly pieces for the masking variants. // It assumes custom ISel patterns for masking which can be provided as // template arguments. multiclass AVX512_maskable_custom O, Format F, dag Outs, dag Ins, dag MaskingIns, dag ZeroMaskingIns, string OpcodeStr, string AttSrcAsm, string IntelSrcAsm, list Pattern, list MaskingPattern, list ZeroMaskingPattern, string MaskingConstraint = "", InstrItinClass itin = NoItinerary, bit IsCommutable = 0> { let isCommutable = IsCommutable in def NAME: AVX512; // Prefer over VMOV*rrk Pat<> let AddedComplexity = 20 in def NAME#k: AVX512, EVEX_K { // In case of the 3src subclass this is overridden with a let. string Constraints = MaskingConstraint; } let AddedComplexity = 30 in // Prefer over VMOV*rrkz Pat<> def NAME#kz: AVX512, EVEX_KZ; } // Common base class of AVX512_maskable and AVX512_maskable_3src. multiclass AVX512_maskable_common O, Format F, X86VectorVTInfo _, dag Outs, dag Ins, dag MaskingIns, dag ZeroMaskingIns, string OpcodeStr, string AttSrcAsm, string IntelSrcAsm, dag RHS, dag MaskingRHS, SDNode Select = vselect, string MaskingConstraint = "", InstrItinClass itin = NoItinerary, bit IsCommutable = 0> : AVX512_maskable_custom; // This multiclass generates the unconditional/non-masking, the masking and // the zero-masking variant of the vector instruction. In the masking case, the // perserved vector elements come from a new dummy input operand tied to $dst. multiclass AVX512_maskable O, Format F, X86VectorVTInfo _, dag Outs, dag Ins, string OpcodeStr, string AttSrcAsm, string IntelSrcAsm, dag RHS, InstrItinClass itin = NoItinerary, bit IsCommutable = 0> : AVX512_maskable_common; // This multiclass generates the unconditional/non-masking, the masking and // the zero-masking variant of the scalar instruction. multiclass AVX512_maskable_scalar O, Format F, X86VectorVTInfo _, dag Outs, dag Ins, string OpcodeStr, string AttSrcAsm, string IntelSrcAsm, dag RHS, InstrItinClass itin = NoItinerary, bit IsCommutable = 0> : AVX512_maskable_common; // Similar to AVX512_maskable but in this case one of the source operands // ($src1) is already tied to $dst so we just use that for the preserved // vector elements. NOTE that the NonTiedIns (the ins dag) should exclude // $src1. multiclass AVX512_maskable_3src O, Format F, X86VectorVTInfo _, dag Outs, dag NonTiedIns, string OpcodeStr, string AttSrcAsm, string IntelSrcAsm, dag RHS> : AVX512_maskable_common; // Similar to AVX512_maskable_3rc but in this case the input VT for the tied // operand differs from the output VT. This requires a bitconvert on // the preserved vector going into the vselect. multiclass AVX512_maskable_3src_cast O, Format F, X86VectorVTInfo OutVT, X86VectorVTInfo InVT, dag Outs, dag NonTiedIns, string OpcodeStr, string AttSrcAsm, string IntelSrcAsm, dag RHS> : AVX512_maskable_common; multiclass AVX512_maskable_3src_scalar O, Format F, X86VectorVTInfo _, dag Outs, dag NonTiedIns, string OpcodeStr, string AttSrcAsm, string IntelSrcAsm, dag RHS> : AVX512_maskable_common; multiclass AVX512_maskable_in_asm O, Format F, X86VectorVTInfo _, dag Outs, dag Ins, string OpcodeStr, string AttSrcAsm, string IntelSrcAsm, list Pattern> : AVX512_maskable_custom; // Instruction with mask that puts result in mask register, // like "compare" and "vptest" multiclass AVX512_maskable_custom_cmp O, Format F, dag Outs, dag Ins, dag MaskingIns, string OpcodeStr, string AttSrcAsm, string IntelSrcAsm, list Pattern, list MaskingPattern> { def NAME: AVX512; def NAME#k: AVX512, EVEX_K; } multiclass AVX512_maskable_common_cmp O, Format F, X86VectorVTInfo _, dag Outs, dag Ins, dag MaskingIns, string OpcodeStr, string AttSrcAsm, string IntelSrcAsm, dag RHS, dag MaskingRHS> : AVX512_maskable_custom_cmp; multiclass AVX512_maskable_cmp O, Format F, X86VectorVTInfo _, dag Outs, dag Ins, string OpcodeStr, string AttSrcAsm, string IntelSrcAsm, dag RHS> : AVX512_maskable_common_cmp; multiclass AVX512_maskable_cmp_alt O, Format F, X86VectorVTInfo _, dag Outs, dag Ins, string OpcodeStr, string AttSrcAsm, string IntelSrcAsm> : AVX512_maskable_custom_cmp; // Bitcasts between 512-bit vector types. Return the original type since // no instruction is needed for the conversion let Predicates = [HasAVX512] in { def : Pat<(v8f64 (bitconvert (v8i64 VR512:$src))), (v8f64 VR512:$src)>; def : Pat<(v8f64 (bitconvert (v16i32 VR512:$src))), (v8f64 VR512:$src)>; def : Pat<(v8f64 (bitconvert (v32i16 VR512:$src))), (v8f64 VR512:$src)>; def : Pat<(v8f64 (bitconvert (v64i8 VR512:$src))), (v8f64 VR512:$src)>; def : Pat<(v8f64 (bitconvert (v16f32 VR512:$src))), (v8f64 VR512:$src)>; def : Pat<(v16f32 (bitconvert (v8i64 VR512:$src))), (v16f32 VR512:$src)>; def : Pat<(v16f32 (bitconvert (v16i32 VR512:$src))), (v16f32 VR512:$src)>; def : Pat<(v16f32 (bitconvert (v32i16 VR512:$src))), (v16f32 VR512:$src)>; def : Pat<(v16f32 (bitconvert (v64i8 VR512:$src))), (v16f32 VR512:$src)>; def : Pat<(v16f32 (bitconvert (v8f64 VR512:$src))), (v16f32 VR512:$src)>; def : Pat<(v8i64 (bitconvert (v16i32 VR512:$src))), (v8i64 VR512:$src)>; def : Pat<(v8i64 (bitconvert (v32i16 VR512:$src))), (v8i64 VR512:$src)>; def : Pat<(v8i64 (bitconvert (v64i8 VR512:$src))), (v8i64 VR512:$src)>; def : Pat<(v8i64 (bitconvert (v8f64 VR512:$src))), (v8i64 VR512:$src)>; def : Pat<(v8i64 (bitconvert (v16f32 VR512:$src))), (v8i64 VR512:$src)>; def : Pat<(v16i32 (bitconvert (v8i64 VR512:$src))), (v16i32 VR512:$src)>; def : Pat<(v16i32 (bitconvert (v16f32 VR512:$src))), (v16i32 VR512:$src)>; def : Pat<(v16i32 (bitconvert (v32i16 VR512:$src))), (v16i32 VR512:$src)>; def : Pat<(v16i32 (bitconvert (v64i8 VR512:$src))), (v16i32 VR512:$src)>; def : Pat<(v16i32 (bitconvert (v8f64 VR512:$src))), (v16i32 VR512:$src)>; def : Pat<(v32i16 (bitconvert (v8i64 VR512:$src))), (v32i16 VR512:$src)>; def : Pat<(v32i16 (bitconvert (v16i32 VR512:$src))), (v32i16 VR512:$src)>; def : Pat<(v32i16 (bitconvert (v64i8 VR512:$src))), (v32i16 VR512:$src)>; def : Pat<(v32i16 (bitconvert (v8f64 VR512:$src))), (v32i16 VR512:$src)>; def : Pat<(v32i16 (bitconvert (v16f32 VR512:$src))), (v32i16 VR512:$src)>; def : Pat<(v32i16 (bitconvert (v16f32 VR512:$src))), (v32i16 VR512:$src)>; def : Pat<(v64i8 (bitconvert (v8i64 VR512:$src))), (v64i8 VR512:$src)>; def : Pat<(v64i8 (bitconvert (v16i32 VR512:$src))), (v64i8 VR512:$src)>; def : Pat<(v64i8 (bitconvert (v32i16 VR512:$src))), (v64i8 VR512:$src)>; def : Pat<(v64i8 (bitconvert (v8f64 VR512:$src))), (v64i8 VR512:$src)>; def : Pat<(v64i8 (bitconvert (v16f32 VR512:$src))), (v64i8 VR512:$src)>; def : Pat<(v2i64 (bitconvert (v4i32 VR128X:$src))), (v2i64 VR128X:$src)>; def : Pat<(v2i64 (bitconvert (v8i16 VR128X:$src))), (v2i64 VR128X:$src)>; def : Pat<(v2i64 (bitconvert (v16i8 VR128X:$src))), (v2i64 VR128X:$src)>; def : Pat<(v2i64 (bitconvert (v2f64 VR128X:$src))), (v2i64 VR128X:$src)>; def : Pat<(v2i64 (bitconvert (v4f32 VR128X:$src))), (v2i64 VR128X:$src)>; def : Pat<(v4i32 (bitconvert (v2i64 VR128X:$src))), (v4i32 VR128X:$src)>; def : Pat<(v4i32 (bitconvert (v8i16 VR128X:$src))), (v4i32 VR128X:$src)>; def : Pat<(v4i32 (bitconvert (v16i8 VR128X:$src))), (v4i32 VR128X:$src)>; def : Pat<(v4i32 (bitconvert (v2f64 VR128X:$src))), (v4i32 VR128X:$src)>; def : Pat<(v4i32 (bitconvert (v4f32 VR128X:$src))), (v4i32 VR128X:$src)>; def : Pat<(v8i16 (bitconvert (v2i64 VR128X:$src))), (v8i16 VR128X:$src)>; def : Pat<(v8i16 (bitconvert (v4i32 VR128X:$src))), (v8i16 VR128X:$src)>; def : Pat<(v8i16 (bitconvert (v16i8 VR128X:$src))), (v8i16 VR128X:$src)>; def : Pat<(v8i16 (bitconvert (v2f64 VR128X:$src))), (v8i16 VR128X:$src)>; def : Pat<(v8i16 (bitconvert (v4f32 VR128X:$src))), (v8i16 VR128X:$src)>; def : Pat<(v16i8 (bitconvert (v2i64 VR128X:$src))), (v16i8 VR128X:$src)>; def : Pat<(v16i8 (bitconvert (v4i32 VR128X:$src))), (v16i8 VR128X:$src)>; def : Pat<(v16i8 (bitconvert (v8i16 VR128X:$src))), (v16i8 VR128X:$src)>; def : Pat<(v16i8 (bitconvert (v2f64 VR128X:$src))), (v16i8 VR128X:$src)>; def : Pat<(v16i8 (bitconvert (v4f32 VR128X:$src))), (v16i8 VR128X:$src)>; def : Pat<(v4f32 (bitconvert (v2i64 VR128X:$src))), (v4f32 VR128X:$src)>; def : Pat<(v4f32 (bitconvert (v4i32 VR128X:$src))), (v4f32 VR128X:$src)>; def : Pat<(v4f32 (bitconvert (v8i16 VR128X:$src))), (v4f32 VR128X:$src)>; def : Pat<(v4f32 (bitconvert (v16i8 VR128X:$src))), (v4f32 VR128X:$src)>; def : Pat<(v4f32 (bitconvert (v2f64 VR128X:$src))), (v4f32 VR128X:$src)>; def : Pat<(v2f64 (bitconvert (v2i64 VR128X:$src))), (v2f64 VR128X:$src)>; def : Pat<(v2f64 (bitconvert (v4i32 VR128X:$src))), (v2f64 VR128X:$src)>; def : Pat<(v2f64 (bitconvert (v8i16 VR128X:$src))), (v2f64 VR128X:$src)>; def : Pat<(v2f64 (bitconvert (v16i8 VR128X:$src))), (v2f64 VR128X:$src)>; def : Pat<(v2f64 (bitconvert (v4f32 VR128X:$src))), (v2f64 VR128X:$src)>; // Bitcasts between 256-bit vector types. Return the original type since // no instruction is needed for the conversion def : Pat<(v4f64 (bitconvert (v8f32 VR256X:$src))), (v4f64 VR256X:$src)>; def : Pat<(v4f64 (bitconvert (v8i32 VR256X:$src))), (v4f64 VR256X:$src)>; def : Pat<(v4f64 (bitconvert (v4i64 VR256X:$src))), (v4f64 VR256X:$src)>; def : Pat<(v4f64 (bitconvert (v16i16 VR256X:$src))), (v4f64 VR256X:$src)>; def : Pat<(v4f64 (bitconvert (v32i8 VR256X:$src))), (v4f64 VR256X:$src)>; def : Pat<(v8f32 (bitconvert (v8i32 VR256X:$src))), (v8f32 VR256X:$src)>; def : Pat<(v8f32 (bitconvert (v4i64 VR256X:$src))), (v8f32 VR256X:$src)>; def : Pat<(v8f32 (bitconvert (v4f64 VR256X:$src))), (v8f32 VR256X:$src)>; def : Pat<(v8f32 (bitconvert (v32i8 VR256X:$src))), (v8f32 VR256X:$src)>; def : Pat<(v8f32 (bitconvert (v16i16 VR256X:$src))), (v8f32 VR256X:$src)>; def : Pat<(v4i64 (bitconvert (v8f32 VR256X:$src))), (v4i64 VR256X:$src)>; def : Pat<(v4i64 (bitconvert (v8i32 VR256X:$src))), (v4i64 VR256X:$src)>; def : Pat<(v4i64 (bitconvert (v4f64 VR256X:$src))), (v4i64 VR256X:$src)>; def : Pat<(v4i64 (bitconvert (v32i8 VR256X:$src))), (v4i64 VR256X:$src)>; def : Pat<(v4i64 (bitconvert (v16i16 VR256X:$src))), (v4i64 VR256X:$src)>; def : Pat<(v32i8 (bitconvert (v4f64 VR256X:$src))), (v32i8 VR256X:$src)>; def : Pat<(v32i8 (bitconvert (v4i64 VR256X:$src))), (v32i8 VR256X:$src)>; def : Pat<(v32i8 (bitconvert (v8f32 VR256X:$src))), (v32i8 VR256X:$src)>; def : Pat<(v32i8 (bitconvert (v8i32 VR256X:$src))), (v32i8 VR256X:$src)>; def : Pat<(v32i8 (bitconvert (v16i16 VR256X:$src))), (v32i8 VR256X:$src)>; def : Pat<(v8i32 (bitconvert (v32i8 VR256X:$src))), (v8i32 VR256X:$src)>; def : Pat<(v8i32 (bitconvert (v16i16 VR256X:$src))), (v8i32 VR256X:$src)>; def : Pat<(v8i32 (bitconvert (v8f32 VR256X:$src))), (v8i32 VR256X:$src)>; def : Pat<(v8i32 (bitconvert (v4i64 VR256X:$src))), (v8i32 VR256X:$src)>; def : Pat<(v8i32 (bitconvert (v4f64 VR256X:$src))), (v8i32 VR256X:$src)>; def : Pat<(v16i16 (bitconvert (v8f32 VR256X:$src))), (v16i16 VR256X:$src)>; def : Pat<(v16i16 (bitconvert (v8i32 VR256X:$src))), (v16i16 VR256X:$src)>; def : Pat<(v16i16 (bitconvert (v4i64 VR256X:$src))), (v16i16 VR256X:$src)>; def : Pat<(v16i16 (bitconvert (v4f64 VR256X:$src))), (v16i16 VR256X:$src)>; def : Pat<(v16i16 (bitconvert (v32i8 VR256X:$src))), (v16i16 VR256X:$src)>; } // // AVX-512: VPXOR instruction writes zero to its upper part, it's safe build zeros. // let isReMaterializable = 1, isAsCheapAsAMove = 1, canFoldAsLoad = 1, isPseudo = 1, Predicates = [HasAVX512] in { def AVX512_512_SET0 : I<0, Pseudo, (outs VR512:$dst), (ins), "", [(set VR512:$dst, (v16f32 immAllZerosV))]>; } let Predicates = [HasAVX512] in { def : Pat<(v8i64 immAllZerosV), (AVX512_512_SET0)>; def : Pat<(v16i32 immAllZerosV), (AVX512_512_SET0)>; def : Pat<(v8f64 immAllZerosV), (AVX512_512_SET0)>; } //===----------------------------------------------------------------------===// // AVX-512 - VECTOR INSERT // multiclass vinsert_for_size { let hasSideEffects = 0, ExeDomain = To.ExeDomain in { defm rr : AVX512_maskable, AVX512AIi8Base, EVEX_4V; let mayLoad = 1 in defm rm : AVX512_maskable, AVX512AIi8Base, EVEX_4V, EVEX_CD8; } } multiclass vinsert_for_size_lowering p> { let Predicates = p in { def : Pat<(vinsert_insert:$ins (To.VT To.RC:$src1), (From.VT From.RC:$src2), (iPTR imm)), (To.VT (!cast(InstrStr#"rr") To.RC:$src1, From.RC:$src2, (INSERT_get_vinsert_imm To.RC:$ins)))>; def : Pat<(vinsert_insert:$ins (To.VT To.RC:$src1), (From.VT (bitconvert (From.LdFrag addr:$src2))), (iPTR imm)), (To.VT (!cast(InstrStr#"rm") To.RC:$src1, addr:$src2, (INSERT_get_vinsert_imm To.RC:$ins)))>; } } multiclass vinsert_for_type { let Predicates = [HasVLX] in defm NAME # "32x4Z256" : vinsert_for_size, X86VectorVTInfo< 8, EltVT32, VR256X>, vinsert128_insert>, EVEX_V256; defm NAME # "32x4Z" : vinsert_for_size, X86VectorVTInfo<16, EltVT32, VR512>, vinsert128_insert>, EVEX_V512; defm NAME # "64x4Z" : vinsert_for_size, X86VectorVTInfo< 8, EltVT64, VR512>, vinsert256_insert>, VEX_W, EVEX_V512; let Predicates = [HasVLX, HasDQI] in defm NAME # "64x2Z256" : vinsert_for_size, X86VectorVTInfo< 4, EltVT64, VR256X>, vinsert128_insert>, VEX_W, EVEX_V256; let Predicates = [HasDQI] in { defm NAME # "64x2Z" : vinsert_for_size, X86VectorVTInfo< 8, EltVT64, VR512>, vinsert128_insert>, VEX_W, EVEX_V512; defm NAME # "32x8Z" : vinsert_for_size, X86VectorVTInfo<16, EltVT32, VR512>, vinsert256_insert>, EVEX_V512; } } defm VINSERTF : vinsert_for_type; defm VINSERTI : vinsert_for_type; // Codegen pattern with the alternative types, // Only add this if 64x2 and its friends are not supported natively via AVX512DQ. defm : vinsert_for_size_lowering<"VINSERTF32x4Z256", v2f64x_info, v4f64x_info, vinsert128_insert, INSERT_get_vinsert128_imm, [HasVLX, NoDQI]>; defm : vinsert_for_size_lowering<"VINSERTI32x4Z256", v2i64x_info, v4i64x_info, vinsert128_insert, INSERT_get_vinsert128_imm, [HasVLX, NoDQI]>; defm : vinsert_for_size_lowering<"VINSERTF32x4Z", v2f64x_info, v8f64_info, vinsert128_insert, INSERT_get_vinsert128_imm, [HasAVX512, NoDQI]>; defm : vinsert_for_size_lowering<"VINSERTI32x4Z", v2i64x_info, v8i64_info, vinsert128_insert, INSERT_get_vinsert128_imm, [HasAVX512, NoDQI]>; defm : vinsert_for_size_lowering<"VINSERTF64x4Z", v8f32x_info, v16f32_info, vinsert256_insert, INSERT_get_vinsert256_imm, [HasAVX512, NoDQI]>; defm : vinsert_for_size_lowering<"VINSERTI64x4Z", v8i32x_info, v16i32_info, vinsert256_insert, INSERT_get_vinsert256_imm, [HasAVX512, NoDQI]>; // Codegen pattern with the alternative types insert VEC128 into VEC256 defm : vinsert_for_size_lowering<"VINSERTI32x4Z256", v8i16x_info, v16i16x_info, vinsert128_insert, INSERT_get_vinsert128_imm, [HasVLX]>; defm : vinsert_for_size_lowering<"VINSERTI32x4Z256", v16i8x_info, v32i8x_info, vinsert128_insert, INSERT_get_vinsert128_imm, [HasVLX]>; // Codegen pattern with the alternative types insert VEC128 into VEC512 defm : vinsert_for_size_lowering<"VINSERTI32x4Z", v8i16x_info, v32i16_info, vinsert128_insert, INSERT_get_vinsert128_imm, [HasAVX512]>; defm : vinsert_for_size_lowering<"VINSERTI32x4Z", v16i8x_info, v64i8_info, vinsert128_insert, INSERT_get_vinsert128_imm, [HasAVX512]>; // Codegen pattern with the alternative types insert VEC256 into VEC512 defm : vinsert_for_size_lowering<"VINSERTI64x4Z", v16i16x_info, v32i16_info, vinsert256_insert, INSERT_get_vinsert256_imm, [HasAVX512]>; defm : vinsert_for_size_lowering<"VINSERTI64x4Z", v32i8x_info, v64i8_info, vinsert256_insert, INSERT_get_vinsert256_imm, [HasAVX512]>; // vinsertps - insert f32 to XMM def VINSERTPSzrr : AVX512AIi8<0x21, MRMSrcReg, (outs VR128X:$dst), (ins VR128X:$src1, VR128X:$src2, u8imm:$src3), "vinsertps\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}", [(set VR128X:$dst, (X86insertps VR128X:$src1, VR128X:$src2, imm:$src3))]>, EVEX_4V; def VINSERTPSzrm: AVX512AIi8<0x21, MRMSrcMem, (outs VR128X:$dst), (ins VR128X:$src1, f32mem:$src2, u8imm:$src3), "vinsertps\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}", [(set VR128X:$dst, (X86insertps VR128X:$src1, (v4f32 (scalar_to_vector (loadf32 addr:$src2))), imm:$src3))]>, EVEX_4V, EVEX_CD8<32, CD8VT1>; //===----------------------------------------------------------------------===// // AVX-512 VECTOR EXTRACT //--- multiclass vextract_for_size_first_position_lowering { // A subvector extract from the first vector position is // a subregister copy that needs no instruction. def NAME # To.NumElts: Pat<(To.VT (extract_subvector (From.VT From.RC:$src),(iPTR 0))), (To.VT (EXTRACT_SUBREG (From.VT From.RC:$src), To.SubRegIdx))>; } multiclass vextract_for_size : vextract_for_size_first_position_lowering { let hasSideEffects = 0, ExeDomain = To.ExeDomain in { // use AVX512_maskable_in_asm (AVX512_maskable can't be used due to // vextract_extract), we interesting only in patterns without mask, // intrinsics pattern match generated bellow. defm rr : AVX512_maskable_in_asm, AVX512AIi8Base, EVEX; let mayStore = 1 in { def rm : AVX512AIi8, EVEX; def rmk : AVX512AIi8, EVEX_K, EVEX; }//mayStore = 1 } // Intrinsic call with masking. def : Pat<(!cast("int_x86_avx512_mask_vextract" # To.EltTypeName # "x" # To.NumElts # "_" # From.Size) From.RC:$src1, (iPTR imm:$idx), To.RC:$src0, To.MRC:$mask), (!cast(NAME # To.EltSize # "x" # To.NumElts # From.ZSuffix # "rrk") To.RC:$src0, (COPY_TO_REGCLASS To.MRC:$mask, To.KRCWM), From.RC:$src1, imm:$idx)>; // Intrinsic call with zero-masking. def : Pat<(!cast("int_x86_avx512_mask_vextract" # To.EltTypeName # "x" # To.NumElts # "_" # From.Size) From.RC:$src1, (iPTR imm:$idx), To.ImmAllZerosV, To.MRC:$mask), (!cast(NAME # To.EltSize # "x" # To.NumElts # From.ZSuffix # "rrkz") (COPY_TO_REGCLASS To.MRC:$mask, To.KRCWM), From.RC:$src1, imm:$idx)>; // Intrinsic call without masking. def : Pat<(!cast("int_x86_avx512_mask_vextract" # To.EltTypeName # "x" # To.NumElts # "_" # From.Size) From.RC:$src1, (iPTR imm:$idx), To.ImmAllZerosV, (i8 -1)), (!cast(NAME # To.EltSize # "x" # To.NumElts # From.ZSuffix # "rr") From.RC:$src1, imm:$idx)>; } // Codegen pattern for the alternative types multiclass vextract_for_size_lowering p> : vextract_for_size_first_position_lowering { let Predicates = p in def : Pat<(vextract_extract:$ext (From.VT From.RC:$src1), (iPTR imm)), (To.VT (!cast(InstrStr#"rr") From.RC:$src1, (EXTRACT_get_vextract_imm To.RC:$ext)))>; } multiclass vextract_for_type { defm NAME # "32x4Z" : vextract_for_size, X86VectorVTInfo< 4, EltVT32, VR128X>, vextract128_extract>, EVEX_V512, EVEX_CD8<32, CD8VT4>; defm NAME # "64x4Z" : vextract_for_size, X86VectorVTInfo< 4, EltVT64, VR256X>, vextract256_extract>, VEX_W, EVEX_V512, EVEX_CD8<64, CD8VT4>; let Predicates = [HasVLX] in defm NAME # "32x4Z256" : vextract_for_size, X86VectorVTInfo< 4, EltVT32, VR128X>, vextract128_extract>, EVEX_V256, EVEX_CD8<32, CD8VT4>; let Predicates = [HasVLX, HasDQI] in defm NAME # "64x2Z256" : vextract_for_size, X86VectorVTInfo< 2, EltVT64, VR128X>, vextract128_extract>, VEX_W, EVEX_V256, EVEX_CD8<64, CD8VT2>; let Predicates = [HasDQI] in { defm NAME # "64x2Z" : vextract_for_size, X86VectorVTInfo< 2, EltVT64, VR128X>, vextract128_extract>, VEX_W, EVEX_V512, EVEX_CD8<64, CD8VT2>; defm NAME # "32x8Z" : vextract_for_size, X86VectorVTInfo< 8, EltVT32, VR256X>, vextract256_extract>, EVEX_V512, EVEX_CD8<32, CD8VT8>; } } defm VEXTRACTF : vextract_for_type; defm VEXTRACTI : vextract_for_type; // extract_subvector codegen patterns with the alternative types. // Only add this if 64x2 and its friends are not supported natively via AVX512DQ. defm : vextract_for_size_lowering<"VEXTRACTF32x4Z", v8f64_info, v2f64x_info, vextract128_extract, EXTRACT_get_vextract128_imm, [HasAVX512, NoDQI]>; defm : vextract_for_size_lowering<"VEXTRACTI32x4Z", v8i64_info, v2i64x_info, vextract128_extract, EXTRACT_get_vextract128_imm, [HasAVX512, NoDQI]>; defm : vextract_for_size_lowering<"VEXTRACTF64x4Z", v16f32_info, v8f32x_info, vextract256_extract, EXTRACT_get_vextract256_imm, [HasAVX512, NoDQI]>; defm : vextract_for_size_lowering<"VEXTRACTI64x4Z", v16i32_info, v8i32x_info, vextract256_extract, EXTRACT_get_vextract256_imm, [HasAVX512, NoDQI]>; defm : vextract_for_size_lowering<"VEXTRACTF32x4Z256", v4f64x_info, v2f64x_info, vextract128_extract, EXTRACT_get_vextract128_imm, [HasVLX, NoDQI]>; defm : vextract_for_size_lowering<"VEXTRACTI32x4Z256", v4i64x_info, v2i64x_info, vextract128_extract, EXTRACT_get_vextract128_imm, [HasVLX, NoDQI]>; // Codegen pattern with the alternative types extract VEC128 from VEC512 defm : vextract_for_size_lowering<"VEXTRACTI32x4Z", v32i16_info, v8i16x_info, vextract128_extract, EXTRACT_get_vextract128_imm, [HasAVX512]>; defm : vextract_for_size_lowering<"VEXTRACTI32x4Z", v64i8_info, v16i8x_info, vextract128_extract, EXTRACT_get_vextract128_imm, [HasAVX512]>; // Codegen pattern with the alternative types extract VEC256 from VEC512 defm : vextract_for_size_lowering<"VEXTRACTI64x4Z", v32i16_info, v16i16x_info, vextract256_extract, EXTRACT_get_vextract256_imm, [HasAVX512]>; defm : vextract_for_size_lowering<"VEXTRACTI64x4Z", v64i8_info, v32i8x_info, vextract256_extract, EXTRACT_get_vextract256_imm, [HasAVX512]>; // A 128-bit subvector insert to the first 512-bit vector position // is a subregister copy that needs no instruction. def : Pat<(insert_subvector undef, (v2i64 VR128X:$src), (iPTR 0)), (INSERT_SUBREG (v8i64 (IMPLICIT_DEF)), (INSERT_SUBREG (v4i64 (IMPLICIT_DEF)), VR128X:$src, sub_xmm), sub_ymm)>; def : Pat<(insert_subvector undef, (v2f64 VR128X:$src), (iPTR 0)), (INSERT_SUBREG (v8f64 (IMPLICIT_DEF)), (INSERT_SUBREG (v4f64 (IMPLICIT_DEF)), VR128X:$src, sub_xmm), sub_ymm)>; def : Pat<(insert_subvector undef, (v4i32 VR128X:$src), (iPTR 0)), (INSERT_SUBREG (v16i32 (IMPLICIT_DEF)), (INSERT_SUBREG (v8i32 (IMPLICIT_DEF)), VR128X:$src, sub_xmm), sub_ymm)>; def : Pat<(insert_subvector undef, (v4f32 VR128X:$src), (iPTR 0)), (INSERT_SUBREG (v16f32 (IMPLICIT_DEF)), (INSERT_SUBREG (v8f32 (IMPLICIT_DEF)), VR128X:$src, sub_xmm), sub_ymm)>; def : Pat<(insert_subvector undef, (v4i64 VR256X:$src), (iPTR 0)), (INSERT_SUBREG (v8i64 (IMPLICIT_DEF)), VR256X:$src, sub_ymm)>; def : Pat<(insert_subvector undef, (v4f64 VR256X:$src), (iPTR 0)), (INSERT_SUBREG (v8f64 (IMPLICIT_DEF)), VR256X:$src, sub_ymm)>; def : Pat<(insert_subvector undef, (v8i32 VR256X:$src), (iPTR 0)), (INSERT_SUBREG (v16i32 (IMPLICIT_DEF)), VR256X:$src, sub_ymm)>; def : Pat<(insert_subvector undef, (v8f32 VR256X:$src), (iPTR 0)), (INSERT_SUBREG (v16f32 (IMPLICIT_DEF)), VR256X:$src, sub_ymm)>; def : Pat<(insert_subvector undef, (v16i16 VR256X:$src), (iPTR 0)), (INSERT_SUBREG (v32i16 (IMPLICIT_DEF)), VR256X:$src, sub_ymm)>; def : Pat<(insert_subvector undef, (v32i8 VR256X:$src), (iPTR 0)), (INSERT_SUBREG (v64i8 (IMPLICIT_DEF)), VR256X:$src, sub_ymm)>; // vextractps - extract 32 bits from XMM def VEXTRACTPSzrr : AVX512AIi8<0x17, MRMDestReg, (outs GR32:$dst), (ins VR128X:$src1, u8imm:$src2), "vextractps\t{$src2, $src1, $dst|$dst, $src1, $src2}", [(set GR32:$dst, (extractelt (bc_v4i32 (v4f32 VR128X:$src1)), imm:$src2))]>, EVEX; def VEXTRACTPSzmr : AVX512AIi8<0x17, MRMDestMem, (outs), (ins f32mem:$dst, VR128X:$src1, u8imm:$src2), "vextractps\t{$src2, $src1, $dst|$dst, $src1, $src2}", [(store (extractelt (bc_v4i32 (v4f32 VR128X:$src1)), imm:$src2), addr:$dst)]>, EVEX, EVEX_CD8<32, CD8VT1>; //===---------------------------------------------------------------------===// // AVX-512 BROADCAST //--- multiclass avx512_broadcast_rm opc, string OpcodeStr, X86VectorVTInfo DestInfo, X86VectorVTInfo SrcInfo> { defm r : AVX512_maskable, T8PD, EVEX; let mayLoad = 1 in defm m : AVX512_maskable, T8PD, EVEX, EVEX_CD8; } multiclass avx512_fp_broadcast_vl opc, string OpcodeStr, AVX512VLVectorVTInfo _> { defm Z : avx512_broadcast_rm, EVEX_V512; let Predicates = [HasVLX] in { defm Z256 : avx512_broadcast_rm, EVEX_V256; } } let ExeDomain = SSEPackedSingle in { defm VBROADCASTSS : avx512_fp_broadcast_vl<0x18, "vbroadcastss", avx512vl_f32_info>; let Predicates = [HasVLX] in { defm VBROADCASTSSZ128 : avx512_broadcast_rm<0x18, "vbroadcastss", v4f32x_info, v4f32x_info>, EVEX_V128; } } let ExeDomain = SSEPackedDouble in { defm VBROADCASTSD : avx512_fp_broadcast_vl<0x19, "vbroadcastsd", avx512vl_f64_info>, VEX_W; } // avx512_broadcast_pat introduces patterns for broadcast with a scalar argument. // Later, we can canonize broadcast instructions before ISel phase and // eliminate additional patterns on ISel. // SrcRC_v and SrcRC_s are RegisterClasses for vector and scalar // representations of source multiclass avx512_broadcast_pat { def : Pat<(_.VT (OpNode (_.EltVT SrcRC_s:$src))), (!cast(InstName##"r") (COPY_TO_REGCLASS SrcRC_s:$src, SrcRC_v))>; let AddedComplexity = 30 in { def : Pat<(_.VT (vselect _.KRCWM:$mask, (OpNode (_.EltVT SrcRC_s:$src)), _.RC:$src0)), (!cast(InstName##"rk") _.RC:$src0, _.KRCWM:$mask, (COPY_TO_REGCLASS SrcRC_s:$src, SrcRC_v))>; def : Pat<(_.VT(vselect _.KRCWM:$mask, (OpNode (_.EltVT SrcRC_s:$src)), _.ImmAllZerosV)), (!cast(InstName##"rkz") _.KRCWM:$mask, (COPY_TO_REGCLASS SrcRC_s:$src, SrcRC_v))>; } } defm : avx512_broadcast_pat<"VBROADCASTSSZ", X86VBroadcast, v16f32_info, VR128X, FR32X>; defm : avx512_broadcast_pat<"VBROADCASTSDZ", X86VBroadcast, v8f64_info, VR128X, FR64X>; let Predicates = [HasVLX] in { defm : avx512_broadcast_pat<"VBROADCASTSSZ256", X86VBroadcast, v8f32x_info, VR128X, FR32X>; defm : avx512_broadcast_pat<"VBROADCASTSSZ128", X86VBroadcast, v4f32x_info, VR128X, FR32X>; defm : avx512_broadcast_pat<"VBROADCASTSDZ256", X86VBroadcast, v4f64x_info, VR128X, FR64X>; } def : Pat<(v16f32 (X86VBroadcast (loadf32 addr:$src))), (VBROADCASTSSZm addr:$src)>; def : Pat<(v8f64 (X86VBroadcast (loadf64 addr:$src))), (VBROADCASTSDZm addr:$src)>; def : Pat<(int_x86_avx512_vbroadcast_ss_512 addr:$src), (VBROADCASTSSZm addr:$src)>; def : Pat<(int_x86_avx512_vbroadcast_sd_512 addr:$src), (VBROADCASTSDZm addr:$src)>; multiclass avx512_int_broadcast_reg opc, X86VectorVTInfo _, RegisterClass SrcRC> { defm r : AVX512_maskable_in_asm, T8PD, EVEX; } multiclass avx512_int_broadcast_reg_vl opc, AVX512VLVectorVTInfo _, RegisterClass SrcRC, Predicate prd> { let Predicates = [prd] in defm Z : avx512_int_broadcast_reg, EVEX_V512; let Predicates = [prd, HasVLX] in { defm Z256 : avx512_int_broadcast_reg, EVEX_V256; defm Z128 : avx512_int_broadcast_reg, EVEX_V128; } } defm VPBROADCASTBr : avx512_int_broadcast_reg_vl<0x7A, avx512vl_i8_info, GR32, HasBWI>; defm VPBROADCASTWr : avx512_int_broadcast_reg_vl<0x7B, avx512vl_i16_info, GR32, HasBWI>; defm VPBROADCASTDr : avx512_int_broadcast_reg_vl<0x7C, avx512vl_i32_info, GR32, HasAVX512>; defm VPBROADCASTQr : avx512_int_broadcast_reg_vl<0x7C, avx512vl_i64_info, GR64, HasAVX512>, VEX_W; def : Pat <(v16i32 (X86vzext VK16WM:$mask)), (VPBROADCASTDrZrkz VK16WM:$mask, (i32 (MOV32ri 0x1)))>; def : Pat <(v8i64 (X86vzext VK8WM:$mask)), (VPBROADCASTQrZrkz VK8WM:$mask, (i64 (MOV64ri 0x1)))>; def : Pat<(v16i32 (X86VBroadcast (i32 GR32:$src))), (VPBROADCASTDrZr GR32:$src)>; def : Pat<(v8i64 (X86VBroadcast (i64 GR64:$src))), (VPBROADCASTQrZr GR64:$src)>; def : Pat<(v16i32 (int_x86_avx512_pbroadcastd_i32_512 (i32 GR32:$src))), (VPBROADCASTDrZr GR32:$src)>; def : Pat<(v8i64 (int_x86_avx512_pbroadcastq_i64_512 (i64 GR64:$src))), (VPBROADCASTQrZr GR64:$src)>; def : Pat<(v16i32 (int_x86_avx512_mask_pbroadcast_d_gpr_512 (i32 GR32:$src), (v16i32 immAllZerosV), (i16 GR16:$mask))), (VPBROADCASTDrZrkz (COPY_TO_REGCLASS GR16:$mask, VK16WM), GR32:$src)>; def : Pat<(v8i64 (int_x86_avx512_mask_pbroadcast_q_gpr_512 (i64 GR64:$src), (bc_v8i64 (v16i32 immAllZerosV)), (i8 GR8:$mask))), (VPBROADCASTQrZrkz (COPY_TO_REGCLASS GR8:$mask, VK8WM), GR64:$src)>; // Provide aliases for broadcast from the same register class that // automatically does the extract. multiclass avx512_int_broadcast_rm_lowering { def : Pat<(DestInfo.VT (X86VBroadcast (SrcInfo.VT SrcInfo.RC:$src))), (!cast(NAME#DestInfo.ZSuffix#"r") (EXTRACT_SUBREG (SrcInfo.VT SrcInfo.RC:$src), sub_xmm))>; } multiclass avx512_int_broadcast_rm_vl opc, string OpcodeStr, AVX512VLVectorVTInfo _, Predicate prd> { let Predicates = [prd] in { defm Z : avx512_broadcast_rm, avx512_int_broadcast_rm_lowering<_.info512, _.info256>, EVEX_V512; // Defined separately to avoid redefinition. defm Z_Alt : avx512_int_broadcast_rm_lowering<_.info512, _.info512>; } let Predicates = [prd, HasVLX] in { defm Z256 : avx512_broadcast_rm, avx512_int_broadcast_rm_lowering<_.info256, _.info256>, EVEX_V256; defm Z128 : avx512_broadcast_rm, EVEX_V128; } } defm VPBROADCASTB : avx512_int_broadcast_rm_vl<0x78, "vpbroadcastb", avx512vl_i8_info, HasBWI>; defm VPBROADCASTW : avx512_int_broadcast_rm_vl<0x79, "vpbroadcastw", avx512vl_i16_info, HasBWI>; defm VPBROADCASTD : avx512_int_broadcast_rm_vl<0x58, "vpbroadcastd", avx512vl_i32_info, HasAVX512>; defm VPBROADCASTQ : avx512_int_broadcast_rm_vl<0x59, "vpbroadcastq", avx512vl_i64_info, HasAVX512>, VEX_W; multiclass avx512_subvec_broadcast_rm opc, string OpcodeStr, X86VectorVTInfo _Dst, X86VectorVTInfo _Src> { let mayLoad = 1 in defm rm : AVX512_maskable, AVX5128IBase, EVEX; } defm VBROADCASTI32X4 : avx512_subvec_broadcast_rm<0x5a, "vbroadcasti32x4", v16i32_info, v4i32x_info>, EVEX_V512, EVEX_CD8<32, CD8VT4>; defm VBROADCASTF32X4 : avx512_subvec_broadcast_rm<0x1a, "vbroadcastf32x4", v16f32_info, v4f32x_info>, EVEX_V512, EVEX_CD8<32, CD8VT4>; defm VBROADCASTI64X4 : avx512_subvec_broadcast_rm<0x5b, "vbroadcasti64x4", v8i64_info, v4i64x_info>, VEX_W, EVEX_V512, EVEX_CD8<64, CD8VT4>; defm VBROADCASTF64X4 : avx512_subvec_broadcast_rm<0x1b, "vbroadcastf64x4", v8f64_info, v4f64x_info>, VEX_W, EVEX_V512, EVEX_CD8<64, CD8VT4>; let Predicates = [HasVLX] in { defm VBROADCASTI32X4Z256 : avx512_subvec_broadcast_rm<0x5a, "vbroadcasti32x4", v8i32x_info, v4i32x_info>, EVEX_V256, EVEX_CD8<32, CD8VT4>; defm VBROADCASTF32X4Z256 : avx512_subvec_broadcast_rm<0x1a, "vbroadcastf32x4", v8f32x_info, v4f32x_info>, EVEX_V256, EVEX_CD8<32, CD8VT4>; } let Predicates = [HasVLX, HasDQI] in { defm VBROADCASTI64X2Z128 : avx512_subvec_broadcast_rm<0x5a, "vbroadcasti64x2", v4i64x_info, v2i64x_info>, VEX_W, EVEX_V256, EVEX_CD8<64, CD8VT2>; defm VBROADCASTF64X2Z128 : avx512_subvec_broadcast_rm<0x1a, "vbroadcastf64x2", v4f64x_info, v2f64x_info>, VEX_W, EVEX_V256, EVEX_CD8<64, CD8VT2>; } let Predicates = [HasDQI] in { defm VBROADCASTI64X2 : avx512_subvec_broadcast_rm<0x5a, "vbroadcasti64x2", v8i64_info, v2i64x_info>, VEX_W, EVEX_V512, EVEX_CD8<64, CD8VT2>; defm VBROADCASTI32X8 : avx512_subvec_broadcast_rm<0x5b, "vbroadcasti32x8", v16i32_info, v8i32x_info>, EVEX_V512, EVEX_CD8<32, CD8VT8>; defm VBROADCASTF64X2 : avx512_subvec_broadcast_rm<0x1a, "vbroadcastf64x2", v8f64_info, v2f64x_info>, VEX_W, EVEX_V512, EVEX_CD8<64, CD8VT2>; defm VBROADCASTF32X8 : avx512_subvec_broadcast_rm<0x1b, "vbroadcastf32x8", v16f32_info, v8f32x_info>, EVEX_V512, EVEX_CD8<32, CD8VT8>; } multiclass avx512_broadcast_32x2 opc, string OpcodeStr, X86VectorVTInfo _Dst, X86VectorVTInfo _Src, SDNode OpNode = X86SubVBroadcast> { defm r : AVX512_maskable, T8PD, EVEX; let mayLoad = 1 in defm m : AVX512_maskable, T8PD, EVEX, EVEX_CD8<_Src.EltSize, CD8VT2>; } multiclass avx512_common_broadcast_32x2 opc, string OpcodeStr, AVX512VLVectorVTInfo _> { let Predicates = [HasDQI] in defm Z : avx512_broadcast_32x2, EVEX_V512; let Predicates = [HasDQI, HasVLX] in defm Z256 : avx512_broadcast_32x2, EVEX_V256; } multiclass avx512_common_broadcast_i32x2 opc, string OpcodeStr, AVX512VLVectorVTInfo _> : avx512_common_broadcast_32x2 { let Predicates = [HasDQI, HasVLX] in defm Z128 : avx512_broadcast_32x2, EVEX_V128; } defm VPBROADCASTI32X2 : avx512_common_broadcast_i32x2<0x59, "vbroadcasti32x2", avx512vl_i32_info>; defm VPBROADCASTF32X2 : avx512_common_broadcast_32x2<0x19, "vbroadcastf32x2", avx512vl_f32_info>; def : Pat<(v16f32 (X86VBroadcast (v16f32 VR512:$src))), (VBROADCASTSSZr (EXTRACT_SUBREG (v16f32 VR512:$src), sub_xmm))>; def : Pat<(v16f32 (X86VBroadcast (v8f32 VR256X:$src))), (VBROADCASTSSZr (EXTRACT_SUBREG (v8f32 VR256X:$src), sub_xmm))>; def : Pat<(v8f64 (X86VBroadcast (v8f64 VR512:$src))), (VBROADCASTSDZr (EXTRACT_SUBREG (v8f64 VR512:$src), sub_xmm))>; def : Pat<(v8f64 (X86VBroadcast (v4f64 VR256X:$src))), (VBROADCASTSDZr (EXTRACT_SUBREG (v4f64 VR256X:$src), sub_xmm))>; // Provide fallback in case the load node that is used in the patterns above // is used by additional users, which prevents the pattern selection. def : Pat<(v16f32 (X86VBroadcast FR32X:$src)), (VBROADCASTSSZr (COPY_TO_REGCLASS FR32X:$src, VR128X))>; def : Pat<(v8f64 (X86VBroadcast FR64X:$src)), (VBROADCASTSDZr (COPY_TO_REGCLASS FR64X:$src, VR128X))>; //===----------------------------------------------------------------------===// // AVX-512 BROADCAST MASK TO VECTOR REGISTER //--- multiclass avx512_mask_broadcastm opc, string OpcodeStr, X86VectorVTInfo _, RegisterClass KRC> { def rr : AVX512XS8I, EVEX; } multiclass avx512_mask_broadcast opc, string OpcodeStr, AVX512VLVectorVTInfo VTInfo, RegisterClass KRC> { let Predicates = [HasCDI] in defm Z : avx512_mask_broadcastm, EVEX_V512; let Predicates = [HasCDI, HasVLX] in { defm Z256 : avx512_mask_broadcastm, EVEX_V256; defm Z128 : avx512_mask_broadcastm, EVEX_V128; } } defm VPBROADCASTMW2D : avx512_mask_broadcast<0x3A, "vpbroadcastmw2d", avx512vl_i32_info, VK16>; defm VPBROADCASTMB2Q : avx512_mask_broadcast<0x2A, "vpbroadcastmb2q", avx512vl_i64_info, VK8>, VEX_W; //===----------------------------------------------------------------------===// // -- VPERMI2 - 3 source operands form -- multiclass avx512_perm_i opc, string OpcodeStr, X86VectorVTInfo _, X86VectorVTInfo IdxVT> { let Constraints = "$src1 = $dst" in { defm rr: AVX512_maskable_3src_cast, EVEX_4V, AVX5128IBase; let mayLoad = 1 in defm rm: AVX512_maskable_3src_cast, EVEX_4V, AVX5128IBase; } } multiclass avx512_perm_i_mb opc, string OpcodeStr, X86VectorVTInfo _, X86VectorVTInfo IdxVT> { let mayLoad = 1, Constraints = "$src1 = $dst" in defm rmb: AVX512_maskable_3src_cast, AVX5128IBase, EVEX_4V, EVEX_B; } multiclass avx512_perm_i_sizes opc, string OpcodeStr, AVX512VLVectorVTInfo VTInfo, AVX512VLVectorVTInfo ShuffleMask> { defm NAME: avx512_perm_i, avx512_perm_i_mb, EVEX_V512; let Predicates = [HasVLX] in { defm NAME#128: avx512_perm_i, avx512_perm_i_mb, EVEX_V128; defm NAME#256: avx512_perm_i, avx512_perm_i_mb, EVEX_V256; } } multiclass avx512_perm_i_sizes_w opc, string OpcodeStr, AVX512VLVectorVTInfo VTInfo, AVX512VLVectorVTInfo Idx> { let Predicates = [HasBWI] in defm NAME: avx512_perm_i, EVEX_V512; let Predicates = [HasBWI, HasVLX] in { defm NAME#128: avx512_perm_i, EVEX_V128; defm NAME#256: avx512_perm_i, EVEX_V256; } } defm VPERMI2D : avx512_perm_i_sizes<0x76, "vpermi2d", avx512vl_i32_info, avx512vl_i32_info>, EVEX_CD8<32, CD8VF>; defm VPERMI2Q : avx512_perm_i_sizes<0x76, "vpermi2q", avx512vl_i64_info, avx512vl_i64_info>, VEX_W, EVEX_CD8<64, CD8VF>; defm VPERMI2W : avx512_perm_i_sizes_w<0x75, "vpermi2w", avx512vl_i16_info, avx512vl_i16_info>, VEX_W, EVEX_CD8<16, CD8VF>; defm VPERMI2PS : avx512_perm_i_sizes<0x77, "vpermi2ps", avx512vl_f32_info, avx512vl_i32_info>, EVEX_CD8<32, CD8VF>; defm VPERMI2PD : avx512_perm_i_sizes<0x77, "vpermi2pd", avx512vl_f64_info, avx512vl_i64_info>, VEX_W, EVEX_CD8<64, CD8VF>; // VPERMT2 multiclass avx512_perm_t opc, string OpcodeStr, X86VectorVTInfo _, X86VectorVTInfo IdxVT> { let Constraints = "$src1 = $dst" in { defm rr: AVX512_maskable_3src, EVEX_4V, AVX5128IBase; let mayLoad = 1 in defm rm: AVX512_maskable_3src, EVEX_4V, AVX5128IBase; } } multiclass avx512_perm_t_mb opc, string OpcodeStr, X86VectorVTInfo _, X86VectorVTInfo IdxVT> { let mayLoad = 1, Constraints = "$src1 = $dst" in defm rmb: AVX512_maskable_3src, AVX5128IBase, EVEX_4V, EVEX_B; } multiclass avx512_perm_t_sizes opc, string OpcodeStr, AVX512VLVectorVTInfo VTInfo, AVX512VLVectorVTInfo ShuffleMask> { defm NAME: avx512_perm_t, avx512_perm_t_mb, EVEX_V512; let Predicates = [HasVLX] in { defm NAME#128: avx512_perm_t, avx512_perm_t_mb, EVEX_V128; defm NAME#256: avx512_perm_t, avx512_perm_t_mb, EVEX_V256; } } multiclass avx512_perm_t_sizes_w opc, string OpcodeStr, AVX512VLVectorVTInfo VTInfo, AVX512VLVectorVTInfo Idx> { let Predicates = [HasBWI] in defm NAME: avx512_perm_t, EVEX_V512; let Predicates = [HasBWI, HasVLX] in { defm NAME#128: avx512_perm_t, EVEX_V128; defm NAME#256: avx512_perm_t, EVEX_V256; } } defm VPERMT2D : avx512_perm_t_sizes<0x7E, "vpermt2d", avx512vl_i32_info, avx512vl_i32_info>, EVEX_CD8<32, CD8VF>; defm VPERMT2Q : avx512_perm_t_sizes<0x7E, "vpermt2q", avx512vl_i64_info, avx512vl_i64_info>, VEX_W, EVEX_CD8<64, CD8VF>; defm VPERMT2W : avx512_perm_t_sizes_w<0x7D, "vpermt2w", avx512vl_i16_info, avx512vl_i16_info>, VEX_W, EVEX_CD8<16, CD8VF>; defm VPERMT2PS : avx512_perm_t_sizes<0x7F, "vpermt2ps", avx512vl_f32_info, avx512vl_i32_info>, EVEX_CD8<32, CD8VF>; defm VPERMT2PD : avx512_perm_t_sizes<0x7F, "vpermt2pd", avx512vl_f64_info, avx512vl_i64_info>, VEX_W, EVEX_CD8<64, CD8VF>; //===----------------------------------------------------------------------===// // AVX-512 - BLEND using mask // multiclass avx512_blendmask opc, string OpcodeStr, X86VectorVTInfo _> { let ExeDomain = _.ExeDomain in { def rr : AVX5128I, EVEX_4V; def rrk : AVX5128I, EVEX_4V, EVEX_K; def rrkz : AVX5128I, EVEX_4V, EVEX_KZ; let mayLoad = 1 in { def rm : AVX5128I, EVEX_4V, EVEX_CD8<_.EltSize, CD8VF>; def rmk : AVX5128I, EVEX_4V, EVEX_K, EVEX_CD8<_.EltSize, CD8VF>; def rmkz : AVX5128I, EVEX_4V, EVEX_KZ, EVEX_CD8<_.EltSize, CD8VF>; } } } multiclass avx512_blendmask_rmb opc, string OpcodeStr, X86VectorVTInfo _> { def rmbk : AVX5128I, EVEX_4V, EVEX_K, EVEX_B, EVEX_CD8<_.EltSize, CD8VF>; def rmb : AVX5128I, EVEX_4V, EVEX_B, EVEX_CD8<_.EltSize, CD8VF>; } multiclass blendmask_dq opc, string OpcodeStr, AVX512VLVectorVTInfo VTInfo> { defm Z : avx512_blendmask , avx512_blendmask_rmb , EVEX_V512; let Predicates = [HasVLX] in { defm Z256 : avx512_blendmask, avx512_blendmask_rmb , EVEX_V256; defm Z128 : avx512_blendmask, avx512_blendmask_rmb , EVEX_V128; } } multiclass blendmask_bw opc, string OpcodeStr, AVX512VLVectorVTInfo VTInfo> { let Predicates = [HasBWI] in defm Z : avx512_blendmask , EVEX_V512; let Predicates = [HasBWI, HasVLX] in { defm Z256 : avx512_blendmask , EVEX_V256; defm Z128 : avx512_blendmask , EVEX_V128; } } defm VBLENDMPS : blendmask_dq <0x65, "vblendmps", avx512vl_f32_info>; defm VBLENDMPD : blendmask_dq <0x65, "vblendmpd", avx512vl_f64_info>, VEX_W; defm VPBLENDMD : blendmask_dq <0x64, "vpblendmd", avx512vl_i32_info>; defm VPBLENDMQ : blendmask_dq <0x64, "vpblendmq", avx512vl_i64_info>, VEX_W; defm VPBLENDMB : blendmask_bw <0x66, "vpblendmb", avx512vl_i8_info>; defm VPBLENDMW : blendmask_bw <0x66, "vpblendmw", avx512vl_i16_info>, VEX_W; let Predicates = [HasAVX512] in { def : Pat<(v8f32 (vselect (v8i1 VK8WM:$mask), (v8f32 VR256X:$src1), (v8f32 VR256X:$src2))), (EXTRACT_SUBREG (v16f32 (VBLENDMPSZrrk (COPY_TO_REGCLASS VK8WM:$mask, VK16WM), (v16f32 (SUBREG_TO_REG (i32 0), VR256X:$src2, sub_ymm)), (v16f32 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)))), sub_ymm)>; def : Pat<(v8i32 (vselect (v8i1 VK8WM:$mask), (v8i32 VR256X:$src1), (v8i32 VR256X:$src2))), (EXTRACT_SUBREG (v16i32 (VPBLENDMDZrrk (COPY_TO_REGCLASS VK8WM:$mask, VK16WM), (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src2, sub_ymm)), (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)))), sub_ymm)>; } //===----------------------------------------------------------------------===// // Compare Instructions //===----------------------------------------------------------------------===// // avx512_cmp_scalar - AVX512 CMPSS and CMPSD multiclass avx512_cmp_scalar{ defm rr_Int : AVX512_maskable_cmp<0xC2, MRMSrcReg, _, (outs _.KRC:$dst), (ins _.RC:$src1, _.RC:$src2, AVXCC:$cc), "vcmp${cc}"#_.Suffix, "$src2, $src1", "$src1, $src2", (OpNode (_.VT _.RC:$src1), (_.VT _.RC:$src2), imm:$cc)>, EVEX_4V; let mayLoad = 1 in defm rm_Int : AVX512_maskable_cmp<0xC2, MRMSrcMem, _, (outs _.KRC:$dst), (ins _.RC:$src1, _.MemOp:$src2, AVXCC:$cc), "vcmp${cc}"#_.Suffix, "$src2, $src1", "$src1, $src2", (OpNode (_.VT _.RC:$src1), (_.VT (scalar_to_vector (_.ScalarLdFrag addr:$src2))), imm:$cc)>, EVEX_4V, EVEX_CD8<_.EltSize, CD8VT1>; defm rrb_Int : AVX512_maskable_cmp<0xC2, MRMSrcReg, _, (outs _.KRC:$dst), (ins _.RC:$src1, _.RC:$src2, AVXCC:$cc), "vcmp${cc}"#_.Suffix, "{sae}, $src2, $src1", "$src1, $src2, {sae}", (OpNodeRnd (_.VT _.RC:$src1), (_.VT _.RC:$src2), imm:$cc, (i32 FROUND_NO_EXC))>, EVEX_4V, EVEX_B; // Accept explicit immediate argument form instead of comparison code. let isAsmParserOnly = 1, hasSideEffects = 0 in { defm rri_alt : AVX512_maskable_cmp_alt<0xC2, MRMSrcReg, _, (outs VK1:$dst), (ins _.RC:$src1, _.RC:$src2, u8imm:$cc), "vcmp"#_.Suffix, "$cc, $src2, $src1", "$src1, $src2, $cc">, EVEX_4V; defm rmi_alt : AVX512_maskable_cmp_alt<0xC2, MRMSrcMem, _, (outs _.KRC:$dst), (ins _.RC:$src1, _.MemOp:$src2, u8imm:$cc), "vcmp"#_.Suffix, "$cc, $src2, $src1", "$src1, $src2, $cc">, EVEX_4V, EVEX_CD8<_.EltSize, CD8VT1>; defm rrb_alt : AVX512_maskable_cmp_alt<0xC2, MRMSrcReg, _, (outs _.KRC:$dst), (ins _.RC:$src1, _.RC:$src2, u8imm:$cc), "vcmp"#_.Suffix, "$cc, {sae}, $src2, $src1","$src1, $src2, {sae}, $cc">, EVEX_4V, EVEX_B; }// let isAsmParserOnly = 1, hasSideEffects = 0 let isCodeGenOnly = 1 in { def rr : AVX512Ii8<0xC2, MRMSrcReg, (outs _.KRC:$dst), (ins _.FRC:$src1, _.FRC:$src2, AVXCC:$cc), !strconcat("vcmp${cc}", _.Suffix, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"), [(set _.KRC:$dst, (OpNode _.FRC:$src1, _.FRC:$src2, imm:$cc))], IIC_SSE_ALU_F32S_RR>, EVEX_4V; let mayLoad = 1 in def rm : AVX512Ii8<0xC2, MRMSrcMem, (outs _.KRC:$dst), (ins _.FRC:$src1, _.ScalarMemOp:$src2, AVXCC:$cc), !strconcat("vcmp${cc}", _.Suffix, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"), [(set _.KRC:$dst, (OpNode _.FRC:$src1, (_.ScalarLdFrag addr:$src2), imm:$cc))], IIC_SSE_ALU_F32P_RM>, EVEX_4V, EVEX_CD8<_.EltSize, CD8VT1>; } } let Predicates = [HasAVX512] in { defm VCMPSSZ : avx512_cmp_scalar, AVX512XSIi8Base; defm VCMPSDZ : avx512_cmp_scalar, AVX512XDIi8Base, VEX_W; } multiclass avx512_icmp_packed opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { def rr : AVX512BI, EVEX_4V; let mayLoad = 1 in def rm : AVX512BI, EVEX_4V; def rrk : AVX512BI, EVEX_4V, EVEX_K; let mayLoad = 1 in def rmk : AVX512BI, EVEX_4V, EVEX_K; } multiclass avx512_icmp_packed_rmb opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> : avx512_icmp_packed { let mayLoad = 1 in { def rmb : AVX512BI, EVEX_4V, EVEX_B; def rmbk : AVX512BI, EVEX_4V, EVEX_K, EVEX_B; } } multiclass avx512_icmp_packed_vl opc, string OpcodeStr, SDNode OpNode, AVX512VLVectorVTInfo VTInfo, Predicate prd> { let Predicates = [prd] in defm Z : avx512_icmp_packed, EVEX_V512; let Predicates = [prd, HasVLX] in { defm Z256 : avx512_icmp_packed, EVEX_V256; defm Z128 : avx512_icmp_packed, EVEX_V128; } } multiclass avx512_icmp_packed_rmb_vl opc, string OpcodeStr, SDNode OpNode, AVX512VLVectorVTInfo VTInfo, Predicate prd> { let Predicates = [prd] in defm Z : avx512_icmp_packed_rmb, EVEX_V512; let Predicates = [prd, HasVLX] in { defm Z256 : avx512_icmp_packed_rmb, EVEX_V256; defm Z128 : avx512_icmp_packed_rmb, EVEX_V128; } } defm VPCMPEQB : avx512_icmp_packed_vl<0x74, "vpcmpeqb", X86pcmpeqm, avx512vl_i8_info, HasBWI>, EVEX_CD8<8, CD8VF>; defm VPCMPEQW : avx512_icmp_packed_vl<0x75, "vpcmpeqw", X86pcmpeqm, avx512vl_i16_info, HasBWI>, EVEX_CD8<16, CD8VF>; defm VPCMPEQD : avx512_icmp_packed_rmb_vl<0x76, "vpcmpeqd", X86pcmpeqm, avx512vl_i32_info, HasAVX512>, EVEX_CD8<32, CD8VF>; defm VPCMPEQQ : avx512_icmp_packed_rmb_vl<0x29, "vpcmpeqq", X86pcmpeqm, avx512vl_i64_info, HasAVX512>, T8PD, VEX_W, EVEX_CD8<64, CD8VF>; defm VPCMPGTB : avx512_icmp_packed_vl<0x64, "vpcmpgtb", X86pcmpgtm, avx512vl_i8_info, HasBWI>, EVEX_CD8<8, CD8VF>; defm VPCMPGTW : avx512_icmp_packed_vl<0x65, "vpcmpgtw", X86pcmpgtm, avx512vl_i16_info, HasBWI>, EVEX_CD8<16, CD8VF>; defm VPCMPGTD : avx512_icmp_packed_rmb_vl<0x66, "vpcmpgtd", X86pcmpgtm, avx512vl_i32_info, HasAVX512>, EVEX_CD8<32, CD8VF>; defm VPCMPGTQ : avx512_icmp_packed_rmb_vl<0x37, "vpcmpgtq", X86pcmpgtm, avx512vl_i64_info, HasAVX512>, T8PD, VEX_W, EVEX_CD8<64, CD8VF>; def : Pat<(v8i1 (X86pcmpgtm (v8i32 VR256X:$src1), (v8i32 VR256X:$src2))), (COPY_TO_REGCLASS (VPCMPGTDZrr (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)), (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src2, sub_ymm))), VK8)>; def : Pat<(v8i1 (X86pcmpeqm (v8i32 VR256X:$src1), (v8i32 VR256X:$src2))), (COPY_TO_REGCLASS (VPCMPEQDZrr (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)), (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src2, sub_ymm))), VK8)>; multiclass avx512_icmp_cc opc, string Suffix, SDNode OpNode, X86VectorVTInfo _> { def rri : AVX512AIi8, EVEX_4V; let mayLoad = 1 in def rmi : AVX512AIi8, EVEX_4V; def rrik : AVX512AIi8, EVEX_4V, EVEX_K; let mayLoad = 1 in def rmik : AVX512AIi8, EVEX_4V, EVEX_K; // Accept explicit immediate argument form instead of comparison code. let isAsmParserOnly = 1, hasSideEffects = 0 in { def rri_alt : AVX512AIi8, EVEX_4V; let mayLoad = 1 in def rmi_alt : AVX512AIi8, EVEX_4V; def rrik_alt : AVX512AIi8, EVEX_4V, EVEX_K; let mayLoad = 1 in def rmik_alt : AVX512AIi8, EVEX_4V, EVEX_K; } } multiclass avx512_icmp_cc_rmb opc, string Suffix, SDNode OpNode, X86VectorVTInfo _> : avx512_icmp_cc { def rmib : AVX512AIi8, EVEX_4V, EVEX_B; def rmibk : AVX512AIi8, EVEX_4V, EVEX_K, EVEX_B; // Accept explicit immediate argument form instead of comparison code. let isAsmParserOnly = 1, hasSideEffects = 0, mayLoad = 1 in { def rmib_alt : AVX512AIi8, EVEX_4V, EVEX_B; def rmibk_alt : AVX512AIi8, EVEX_4V, EVEX_K, EVEX_B; } } multiclass avx512_icmp_cc_vl opc, string Suffix, SDNode OpNode, AVX512VLVectorVTInfo VTInfo, Predicate prd> { let Predicates = [prd] in defm Z : avx512_icmp_cc, EVEX_V512; let Predicates = [prd, HasVLX] in { defm Z256 : avx512_icmp_cc, EVEX_V256; defm Z128 : avx512_icmp_cc, EVEX_V128; } } multiclass avx512_icmp_cc_rmb_vl opc, string Suffix, SDNode OpNode, AVX512VLVectorVTInfo VTInfo, Predicate prd> { let Predicates = [prd] in defm Z : avx512_icmp_cc_rmb, EVEX_V512; let Predicates = [prd, HasVLX] in { defm Z256 : avx512_icmp_cc_rmb, EVEX_V256; defm Z128 : avx512_icmp_cc_rmb, EVEX_V128; } } defm VPCMPB : avx512_icmp_cc_vl<0x3F, "b", X86cmpm, avx512vl_i8_info, HasBWI>, EVEX_CD8<8, CD8VF>; defm VPCMPUB : avx512_icmp_cc_vl<0x3E, "ub", X86cmpmu, avx512vl_i8_info, HasBWI>, EVEX_CD8<8, CD8VF>; defm VPCMPW : avx512_icmp_cc_vl<0x3F, "w", X86cmpm, avx512vl_i16_info, HasBWI>, VEX_W, EVEX_CD8<16, CD8VF>; defm VPCMPUW : avx512_icmp_cc_vl<0x3E, "uw", X86cmpmu, avx512vl_i16_info, HasBWI>, VEX_W, EVEX_CD8<16, CD8VF>; defm VPCMPD : avx512_icmp_cc_rmb_vl<0x1F, "d", X86cmpm, avx512vl_i32_info, HasAVX512>, EVEX_CD8<32, CD8VF>; defm VPCMPUD : avx512_icmp_cc_rmb_vl<0x1E, "ud", X86cmpmu, avx512vl_i32_info, HasAVX512>, EVEX_CD8<32, CD8VF>; defm VPCMPQ : avx512_icmp_cc_rmb_vl<0x1F, "q", X86cmpm, avx512vl_i64_info, HasAVX512>, VEX_W, EVEX_CD8<64, CD8VF>; defm VPCMPUQ : avx512_icmp_cc_rmb_vl<0x1E, "uq", X86cmpmu, avx512vl_i64_info, HasAVX512>, VEX_W, EVEX_CD8<64, CD8VF>; multiclass avx512_vcmp_common { defm rri : AVX512_maskable_cmp<0xC2, MRMSrcReg, _, (outs _.KRC:$dst), (ins _.RC:$src1, _.RC:$src2,AVXCC:$cc), "vcmp${cc}"#_.Suffix, "$src2, $src1", "$src1, $src2", (X86cmpm (_.VT _.RC:$src1), (_.VT _.RC:$src2), imm:$cc)>; let mayLoad = 1 in { defm rmi : AVX512_maskable_cmp<0xC2, MRMSrcMem, _, (outs _.KRC:$dst),(ins _.RC:$src1, _.MemOp:$src2, AVXCC:$cc), "vcmp${cc}"#_.Suffix, "$src2, $src1", "$src1, $src2", (X86cmpm (_.VT _.RC:$src1), (_.VT (bitconvert (_.LdFrag addr:$src2))), imm:$cc)>; defm rmbi : AVX512_maskable_cmp<0xC2, MRMSrcMem, _, (outs _.KRC:$dst), (ins _.RC:$src1, _.ScalarMemOp:$src2, AVXCC:$cc), "vcmp${cc}"#_.Suffix, "${src2}"##_.BroadcastStr##", $src1", "$src1, ${src2}"##_.BroadcastStr, (X86cmpm (_.VT _.RC:$src1), (_.VT (X86VBroadcast(_.ScalarLdFrag addr:$src2))), imm:$cc)>,EVEX_B; } // Accept explicit immediate argument form instead of comparison code. let isAsmParserOnly = 1, hasSideEffects = 0 in { defm rri_alt : AVX512_maskable_cmp_alt<0xC2, MRMSrcReg, _, (outs _.KRC:$dst), (ins _.RC:$src1, _.RC:$src2, u8imm:$cc), "vcmp"#_.Suffix, "$cc, $src2, $src1", "$src1, $src2, $cc">; let mayLoad = 1 in { defm rmi_alt : AVX512_maskable_cmp_alt<0xC2, MRMSrcMem, _, (outs _.KRC:$dst), (ins _.RC:$src1, _.MemOp:$src2, u8imm:$cc), "vcmp"#_.Suffix, "$cc, $src2, $src1", "$src1, $src2, $cc">; defm rmbi_alt : AVX512_maskable_cmp_alt<0xC2, MRMSrcMem, _, (outs _.KRC:$dst), (ins _.RC:$src1, _.ScalarMemOp:$src2, u8imm:$cc), "vcmp"#_.Suffix, "$cc, ${src2}"##_.BroadcastStr##", $src1", "$src1, ${src2}"##_.BroadcastStr##", $cc">,EVEX_B; } } } multiclass avx512_vcmp_sae { // comparison code form (VCMP[EQ/LT/LE/...] defm rrib : AVX512_maskable_cmp<0xC2, MRMSrcReg, _, (outs _.KRC:$dst),(ins _.RC:$src1, _.RC:$src2, AVXCC:$cc), "vcmp${cc}"#_.Suffix, "{sae}, $src2, $src1", "$src1, $src2, {sae}", (X86cmpmRnd (_.VT _.RC:$src1), (_.VT _.RC:$src2), imm:$cc, (i32 FROUND_NO_EXC))>, EVEX_B; let isAsmParserOnly = 1, hasSideEffects = 0 in { defm rrib_alt : AVX512_maskable_cmp_alt<0xC2, MRMSrcReg, _, (outs _.KRC:$dst), (ins _.RC:$src1, _.RC:$src2, u8imm:$cc), "vcmp"#_.Suffix, "$cc, {sae}, $src2, $src1", "$src1, $src2, {sae}, $cc">, EVEX_B; } } multiclass avx512_vcmp { let Predicates = [HasAVX512] in { defm Z : avx512_vcmp_common<_.info512>, avx512_vcmp_sae<_.info512>, EVEX_V512; } let Predicates = [HasAVX512,HasVLX] in { defm Z128 : avx512_vcmp_common<_.info128>, EVEX_V128; defm Z256 : avx512_vcmp_common<_.info256>, EVEX_V256; } } defm VCMPPD : avx512_vcmp, AVX512PDIi8Base, EVEX_4V, EVEX_CD8<64, CD8VF>, VEX_W; defm VCMPPS : avx512_vcmp, AVX512PSIi8Base, EVEX_4V, EVEX_CD8<32, CD8VF>; def : Pat<(v8i1 (X86cmpm (v8f32 VR256X:$src1), (v8f32 VR256X:$src2), imm:$cc)), (COPY_TO_REGCLASS (VCMPPSZrri (v16f32 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)), (v16f32 (SUBREG_TO_REG (i32 0), VR256X:$src2, sub_ymm)), imm:$cc), VK8)>; def : Pat<(v8i1 (X86cmpm (v8i32 VR256X:$src1), (v8i32 VR256X:$src2), imm:$cc)), (COPY_TO_REGCLASS (VPCMPDZrri (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)), (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src2, sub_ymm)), imm:$cc), VK8)>; def : Pat<(v8i1 (X86cmpmu (v8i32 VR256X:$src1), (v8i32 VR256X:$src2), imm:$cc)), (COPY_TO_REGCLASS (VPCMPUDZrri (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)), (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src2, sub_ymm)), imm:$cc), VK8)>; // ---------------------------------------------------------------- // FPClass //handle fpclass instruction mask = op(reg_scalar,imm) // op(mem_scalar,imm) multiclass avx512_scalar_fpclass opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _, Predicate prd> { let Predicates = [prd] in { def rr : AVX512; def rrk : AVX512, EVEX_K; let mayLoad = 1, AddedComplexity = 20 in { def rm : AVX512; def rmk : AVX512, EVEX_K; } } } //handle fpclass instruction mask = fpclass(reg_vec, reg_vec, imm) // fpclass(reg_vec, mem_vec, imm) // fpclass(reg_vec, broadcast(eltVt), imm) multiclass avx512_vector_fpclass opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _, string mem, string broadcast>{ def rr : AVX512; def rrk : AVX512, EVEX_K; let mayLoad = 1 in { def rm : AVX512; def rmk : AVX512, EVEX_K; def rmb : AVX512,EVEX_B; def rmbk : AVX512, EVEX_B, EVEX_K; } } multiclass avx512_vector_fpclass_all opc, SDNode OpNode, Predicate prd, string broadcast>{ let Predicates = [prd] in { defm Z : avx512_vector_fpclass, EVEX_V512; } let Predicates = [prd, HasVLX] in { defm Z128 : avx512_vector_fpclass, EVEX_V128; defm Z256 : avx512_vector_fpclass, EVEX_V256; } } multiclass avx512_fp_fpclass_all opcVec, bits<8> opcScalar, SDNode VecOpNode, SDNode ScalarOpNode, Predicate prd>{ defm PS : avx512_vector_fpclass_all, EVEX_CD8<32, CD8VF>; defm PD : avx512_vector_fpclass_all,EVEX_CD8<64, CD8VF> , VEX_W; defm SS : avx512_scalar_fpclass, EVEX_CD8<32, CD8VT1>; defm SD : avx512_scalar_fpclass, EVEX_CD8<64, CD8VT1>, VEX_W; } defm VFPCLASS : avx512_fp_fpclass_all<"vfpclass", 0x66, 0x67, X86Vfpclass, X86Vfpclasss, HasDQI>, AVX512AIi8Base,EVEX; //----------------------------------------------------------------- // Mask register copy, including // - copy between mask registers // - load/store mask registers // - copy from GPR to mask register and vice versa // multiclass avx512_mask_mov opc_kk, bits<8> opc_km, bits<8> opc_mk, string OpcodeStr, RegisterClass KRC, ValueType vvt, X86MemOperand x86memop> { let hasSideEffects = 0 in { def kk : I; let mayLoad = 1 in def km : I; let mayStore = 1 in def mk : I; } } multiclass avx512_mask_mov_gpr opc_kr, bits<8> opc_rk, string OpcodeStr, RegisterClass KRC, RegisterClass GRC> { let hasSideEffects = 0 in { def kr : I; def rk : I; } } let Predicates = [HasDQI] in defm KMOVB : avx512_mask_mov<0x90, 0x90, 0x91, "kmovb", VK8, v8i1, i8mem>, avx512_mask_mov_gpr<0x92, 0x93, "kmovb", VK8, GR32>, VEX, PD; let Predicates = [HasAVX512] in defm KMOVW : avx512_mask_mov<0x90, 0x90, 0x91, "kmovw", VK16, v16i1, i16mem>, avx512_mask_mov_gpr<0x92, 0x93, "kmovw", VK16, GR32>, VEX, PS; let Predicates = [HasBWI] in { defm KMOVD : avx512_mask_mov<0x90, 0x90, 0x91, "kmovd", VK32, v32i1,i32mem>, VEX, PD, VEX_W; defm KMOVD : avx512_mask_mov_gpr<0x92, 0x93, "kmovd", VK32, GR32>, VEX, XD; } let Predicates = [HasBWI] in { defm KMOVQ : avx512_mask_mov<0x90, 0x90, 0x91, "kmovq", VK64, v64i1, i64mem>, VEX, PS, VEX_W; defm KMOVQ : avx512_mask_mov_gpr<0x92, 0x93, "kmovq", VK64, GR64>, VEX, XD, VEX_W; } // GR from/to mask register let Predicates = [HasDQI] in { def : Pat<(v8i1 (bitconvert (i8 GR8:$src))), (KMOVBkr (SUBREG_TO_REG (i32 0), GR8:$src, sub_8bit))>; def : Pat<(i8 (bitconvert (v8i1 VK8:$src))), (EXTRACT_SUBREG (KMOVBrk VK8:$src), sub_8bit)>; } let Predicates = [HasAVX512] in { def : Pat<(v16i1 (bitconvert (i16 GR16:$src))), (KMOVWkr (SUBREG_TO_REG (i32 0), GR16:$src, sub_16bit))>; def : Pat<(i16 (bitconvert (v16i1 VK16:$src))), (EXTRACT_SUBREG (KMOVWrk VK16:$src), sub_16bit)>; } let Predicates = [HasBWI] in { def : Pat<(v32i1 (bitconvert (i32 GR32:$src))), (KMOVDkr GR32:$src)>; def : Pat<(i32 (bitconvert (v32i1 VK32:$src))), (KMOVDrk VK32:$src)>; } let Predicates = [HasBWI] in { def : Pat<(v64i1 (bitconvert (i64 GR64:$src))), (KMOVQkr GR64:$src)>; def : Pat<(i64 (bitconvert (v64i1 VK64:$src))), (KMOVQrk VK64:$src)>; } // Load/store kreg let Predicates = [HasDQI] in { def : Pat<(store (i8 (bitconvert (v8i1 VK8:$src))), addr:$dst), (KMOVBmk addr:$dst, VK8:$src)>; def : Pat<(v8i1 (bitconvert (i8 (load addr:$src)))), (KMOVBkm addr:$src)>; def : Pat<(store VK4:$src, addr:$dst), (KMOVBmk addr:$dst, (COPY_TO_REGCLASS VK4:$src, VK8))>; def : Pat<(store VK2:$src, addr:$dst), (KMOVBmk addr:$dst, (COPY_TO_REGCLASS VK2:$src, VK8))>; } let Predicates = [HasAVX512, NoDQI] in { def : Pat<(store (i8 (bitconvert (v8i1 VK8:$src))), addr:$dst), (KMOVWmk addr:$dst, (COPY_TO_REGCLASS VK8:$src, VK16))>; def : Pat<(v8i1 (bitconvert (i8 (load addr:$src)))), (COPY_TO_REGCLASS (KMOVWkm addr:$src), VK8)>; } let Predicates = [HasAVX512] in { def : Pat<(store (i16 (bitconvert (v16i1 VK16:$src))), addr:$dst), (KMOVWmk addr:$dst, VK16:$src)>; def : Pat<(i1 (load addr:$src)), (COPY_TO_REGCLASS (AND16ri (i16 (SUBREG_TO_REG (i32 0), (MOV8rm addr:$src), sub_8bit)), (i16 1)), VK1)>; def : Pat<(v16i1 (bitconvert (i16 (load addr:$src)))), (KMOVWkm addr:$src)>; } let Predicates = [HasBWI] in { def : Pat<(store (i32 (bitconvert (v32i1 VK32:$src))), addr:$dst), (KMOVDmk addr:$dst, VK32:$src)>; def : Pat<(v32i1 (bitconvert (i32 (load addr:$src)))), (KMOVDkm addr:$src)>; } let Predicates = [HasBWI] in { def : Pat<(store (i64 (bitconvert (v64i1 VK64:$src))), addr:$dst), (KMOVQmk addr:$dst, VK64:$src)>; def : Pat<(v64i1 (bitconvert (i64 (load addr:$src)))), (KMOVQkm addr:$src)>; } let Predicates = [HasAVX512] in { def : Pat<(i1 (trunc (i64 GR64:$src))), (COPY_TO_REGCLASS (KMOVWkr (AND32ri (EXTRACT_SUBREG $src, sub_32bit), (i32 1))), VK1)>; def : Pat<(i1 (trunc (i32 GR32:$src))), (COPY_TO_REGCLASS (KMOVWkr (AND32ri $src, (i32 1))), VK1)>; def : Pat<(i1 (trunc (i8 GR8:$src))), (COPY_TO_REGCLASS (KMOVWkr (AND32ri (SUBREG_TO_REG (i32 0), GR8:$src, sub_8bit), (i32 1))), VK1)>; def : Pat<(i1 (trunc (i16 GR16:$src))), (COPY_TO_REGCLASS (KMOVWkr (AND32ri (SUBREG_TO_REG (i32 0), $src, sub_16bit), (i32 1))), VK1)>; def : Pat<(i32 (zext VK1:$src)), (AND32ri (KMOVWrk (COPY_TO_REGCLASS VK1:$src, VK16)), (i32 1))>; def : Pat<(i32 (anyext VK1:$src)), (KMOVWrk (COPY_TO_REGCLASS VK1:$src, VK16))>; def : Pat<(i8 (zext VK1:$src)), (EXTRACT_SUBREG (AND32ri (KMOVWrk (COPY_TO_REGCLASS VK1:$src, VK16)), (i32 1)), sub_8bit)>; def : Pat<(i8 (anyext VK1:$src)), (EXTRACT_SUBREG (KMOVWrk (COPY_TO_REGCLASS VK1:$src, VK16)), sub_8bit)>; def : Pat<(i64 (zext VK1:$src)), (AND64ri8 (SUBREG_TO_REG (i64 0), (KMOVWrk (COPY_TO_REGCLASS VK1:$src, VK16)), sub_32bit), (i64 1))>; def : Pat<(i16 (zext VK1:$src)), (EXTRACT_SUBREG (AND32ri (KMOVWrk (COPY_TO_REGCLASS VK1:$src, VK16)), (i32 1)), sub_16bit)>; } def : Pat<(v16i1 (scalar_to_vector VK1:$src)), (COPY_TO_REGCLASS VK1:$src, VK16)>; def : Pat<(v8i1 (scalar_to_vector VK1:$src)), (COPY_TO_REGCLASS VK1:$src, VK8)>; def : Pat<(v4i1 (scalar_to_vector VK1:$src)), (COPY_TO_REGCLASS VK1:$src, VK4)>; def : Pat<(v2i1 (scalar_to_vector VK1:$src)), (COPY_TO_REGCLASS VK1:$src, VK2)>; def : Pat<(v32i1 (scalar_to_vector VK1:$src)), (COPY_TO_REGCLASS VK1:$src, VK32)>; def : Pat<(v64i1 (scalar_to_vector VK1:$src)), (COPY_TO_REGCLASS VK1:$src, VK64)>; // With AVX-512 only, 8-bit mask is promoted to 16-bit mask. let Predicates = [HasAVX512, NoDQI] in { // GR from/to 8-bit mask without native support def : Pat<(v8i1 (bitconvert (i8 GR8:$src))), (COPY_TO_REGCLASS (KMOVWkr (MOVZX32rr8 GR8 :$src)), VK8)>; def : Pat<(i8 (bitconvert (v8i1 VK8:$src))), (EXTRACT_SUBREG (KMOVWrk (COPY_TO_REGCLASS VK8:$src, VK16)), sub_8bit)>; } let Predicates = [HasAVX512] in { def : Pat<(i1 (X86Vextract VK16:$src, (iPTR 0))), (COPY_TO_REGCLASS VK16:$src, VK1)>; def : Pat<(i1 (X86Vextract VK8:$src, (iPTR 0))), (COPY_TO_REGCLASS VK8:$src, VK1)>; } let Predicates = [HasBWI] in { def : Pat<(i1 (X86Vextract VK32:$src, (iPTR 0))), (COPY_TO_REGCLASS VK32:$src, VK1)>; def : Pat<(i1 (X86Vextract VK64:$src, (iPTR 0))), (COPY_TO_REGCLASS VK64:$src, VK1)>; } // Mask unary operation // - KNOT multiclass avx512_mask_unop opc, string OpcodeStr, RegisterClass KRC, SDPatternOperator OpNode, Predicate prd> { let Predicates = [prd] in def rr : I; } multiclass avx512_mask_unop_all opc, string OpcodeStr, SDPatternOperator OpNode> { defm B : avx512_mask_unop, VEX, PD; defm W : avx512_mask_unop, VEX, PS; defm D : avx512_mask_unop, VEX, PD, VEX_W; defm Q : avx512_mask_unop, VEX, PS, VEX_W; } defm KNOT : avx512_mask_unop_all<0x44, "knot", not>; multiclass avx512_mask_unop_int { let Predicates = [HasAVX512] in def : Pat<(!cast("int_x86_avx512_"##IntName##"_w") (i16 GR16:$src)), (COPY_TO_REGCLASS (!cast(InstName##"Wrr") (v16i1 (COPY_TO_REGCLASS GR16:$src, VK16))), GR16)>; } defm : avx512_mask_unop_int<"knot", "KNOT">; let Predicates = [HasDQI] in def : Pat<(xor VK8:$src1, (v8i1 immAllOnesV)), (KNOTBrr VK8:$src1)>; let Predicates = [HasAVX512] in def : Pat<(xor VK16:$src1, (v16i1 immAllOnesV)), (KNOTWrr VK16:$src1)>; let Predicates = [HasBWI] in def : Pat<(xor VK32:$src1, (v32i1 immAllOnesV)), (KNOTDrr VK32:$src1)>; let Predicates = [HasBWI] in def : Pat<(xor VK64:$src1, (v64i1 immAllOnesV)), (KNOTQrr VK64:$src1)>; // KNL does not support KMOVB, 8-bit mask is promoted to 16-bit let Predicates = [HasAVX512, NoDQI] in { def : Pat<(xor VK8:$src1, (v8i1 immAllOnesV)), (COPY_TO_REGCLASS (KNOTWrr (COPY_TO_REGCLASS VK8:$src1, VK16)), VK8)>; def : Pat<(not VK8:$src), (COPY_TO_REGCLASS (KNOTWrr (COPY_TO_REGCLASS VK8:$src, VK16)), VK8)>; } def : Pat<(xor VK4:$src1, (v4i1 immAllOnesV)), (COPY_TO_REGCLASS (KNOTWrr (COPY_TO_REGCLASS VK4:$src1, VK16)), VK4)>; def : Pat<(xor VK2:$src1, (v2i1 immAllOnesV)), (COPY_TO_REGCLASS (KNOTWrr (COPY_TO_REGCLASS VK2:$src1, VK16)), VK2)>; // Mask binary operation // - KAND, KANDN, KOR, KXNOR, KXOR multiclass avx512_mask_binop opc, string OpcodeStr, RegisterClass KRC, SDPatternOperator OpNode, Predicate prd, bit IsCommutable> { let Predicates = [prd], isCommutable = IsCommutable in def rr : I; } multiclass avx512_mask_binop_all opc, string OpcodeStr, SDPatternOperator OpNode, bit IsCommutable, Predicate prdW = HasAVX512> { defm B : avx512_mask_binop, VEX_4V, VEX_L, PD; defm W : avx512_mask_binop, VEX_4V, VEX_L, PS; defm D : avx512_mask_binop, VEX_4V, VEX_L, VEX_W, PD; defm Q : avx512_mask_binop, VEX_4V, VEX_L, VEX_W, PS; } def andn : PatFrag<(ops node:$i0, node:$i1), (and (not node:$i0), node:$i1)>; def xnor : PatFrag<(ops node:$i0, node:$i1), (not (xor node:$i0, node:$i1))>; defm KAND : avx512_mask_binop_all<0x41, "kand", and, 1>; defm KOR : avx512_mask_binop_all<0x45, "kor", or, 1>; defm KXNOR : avx512_mask_binop_all<0x46, "kxnor", xnor, 1>; defm KXOR : avx512_mask_binop_all<0x47, "kxor", xor, 1>; defm KANDN : avx512_mask_binop_all<0x42, "kandn", andn, 0>; defm KADD : avx512_mask_binop_all<0x4A, "kadd", add, 1, HasDQI>; multiclass avx512_mask_binop_int { let Predicates = [HasAVX512] in def : Pat<(!cast("int_x86_avx512_"##IntName##"_w") (i16 GR16:$src1), (i16 GR16:$src2)), (COPY_TO_REGCLASS (!cast(InstName##"Wrr") (v16i1 (COPY_TO_REGCLASS GR16:$src1, VK16)), (v16i1 (COPY_TO_REGCLASS GR16:$src2, VK16))), GR16)>; } defm : avx512_mask_binop_int<"kand", "KAND">; defm : avx512_mask_binop_int<"kandn", "KANDN">; defm : avx512_mask_binop_int<"kor", "KOR">; defm : avx512_mask_binop_int<"kxnor", "KXNOR">; defm : avx512_mask_binop_int<"kxor", "KXOR">; multiclass avx512_binop_pat { // With AVX512F, 8-bit mask is promoted to 16-bit mask, // for the DQI set, this type is legal and KxxxB instruction is used let Predicates = [NoDQI] in def : Pat<(OpNode VK8:$src1, VK8:$src2), (COPY_TO_REGCLASS (Inst (COPY_TO_REGCLASS VK8:$src1, VK16), (COPY_TO_REGCLASS VK8:$src2, VK16)), VK8)>; // All types smaller than 8 bits require conversion anyway def : Pat<(OpNode VK1:$src1, VK1:$src2), (COPY_TO_REGCLASS (Inst (COPY_TO_REGCLASS VK1:$src1, VK16), (COPY_TO_REGCLASS VK1:$src2, VK16)), VK1)>; def : Pat<(OpNode VK2:$src1, VK2:$src2), (COPY_TO_REGCLASS (Inst (COPY_TO_REGCLASS VK2:$src1, VK16), (COPY_TO_REGCLASS VK2:$src2, VK16)), VK1)>; def : Pat<(OpNode VK4:$src1, VK4:$src2), (COPY_TO_REGCLASS (Inst (COPY_TO_REGCLASS VK4:$src1, VK16), (COPY_TO_REGCLASS VK4:$src2, VK16)), VK1)>; } defm : avx512_binop_pat; defm : avx512_binop_pat; defm : avx512_binop_pat; defm : avx512_binop_pat; defm : avx512_binop_pat; def : Pat<(xor (xor VK16:$src1, VK16:$src2), (v16i1 immAllOnesV)), (KXNORWrr VK16:$src1, VK16:$src2)>; def : Pat<(xor (xor VK8:$src1, VK8:$src2), (v8i1 immAllOnesV)), (KXNORBrr VK8:$src1, VK8:$src2)>, Requires<[HasDQI]>; def : Pat<(xor (xor VK32:$src1, VK32:$src2), (v32i1 immAllOnesV)), (KXNORDrr VK32:$src1, VK32:$src2)>, Requires<[HasBWI]>; def : Pat<(xor (xor VK64:$src1, VK64:$src2), (v64i1 immAllOnesV)), (KXNORQrr VK64:$src1, VK64:$src2)>, Requires<[HasBWI]>; let Predicates = [NoDQI] in def : Pat<(xor (xor VK8:$src1, VK8:$src2), (v8i1 immAllOnesV)), (COPY_TO_REGCLASS (KXNORWrr (COPY_TO_REGCLASS VK8:$src1, VK16), (COPY_TO_REGCLASS VK8:$src2, VK16)), VK8)>; def : Pat<(xor (xor VK4:$src1, VK4:$src2), (v4i1 immAllOnesV)), (COPY_TO_REGCLASS (KXNORWrr (COPY_TO_REGCLASS VK4:$src1, VK16), (COPY_TO_REGCLASS VK4:$src2, VK16)), VK4)>; def : Pat<(xor (xor VK2:$src1, VK2:$src2), (v2i1 immAllOnesV)), (COPY_TO_REGCLASS (KXNORWrr (COPY_TO_REGCLASS VK2:$src1, VK16), (COPY_TO_REGCLASS VK2:$src2, VK16)), VK2)>; def : Pat<(xor (xor VK1:$src1, VK1:$src2), (i1 1)), (COPY_TO_REGCLASS (KXNORWrr (COPY_TO_REGCLASS VK1:$src1, VK16), (COPY_TO_REGCLASS VK1:$src2, VK16)), VK1)>; // Mask unpacking multiclass avx512_mask_unpck { let Predicates = [prd] in { let hasSideEffects = 0 in def rr : I<0x4b, MRMSrcReg, (outs KRC:$dst), (ins KRC:$src1, KRC:$src2), "kunpck"#Suffix#"\t{$src2, $src1, $dst|$dst, $src1, $src2}", []>, VEX_4V, VEX_L; def : Pat<(VT (concat_vectors KRCSrc:$src1, KRCSrc:$src2)), (!cast(NAME##rr) (COPY_TO_REGCLASS KRCSrc:$src2, KRC), (COPY_TO_REGCLASS KRCSrc:$src1, KRC))>; } } defm KUNPCKBW : avx512_mask_unpck<"bw", VK16, v16i1, VK8, HasAVX512>, PD; defm KUNPCKWD : avx512_mask_unpck<"wd", VK32, v32i1, VK16, HasBWI>, PS; defm KUNPCKDQ : avx512_mask_unpck<"dq", VK64, v64i1, VK32, HasBWI>, PS, VEX_W; // Mask bit testing multiclass avx512_mask_testop opc, string OpcodeStr, RegisterClass KRC, SDNode OpNode, Predicate prd> { let Predicates = [prd], Defs = [EFLAGS] in def rr : I; } multiclass avx512_mask_testop_w opc, string OpcodeStr, SDNode OpNode, Predicate prdW = HasAVX512> { defm B : avx512_mask_testop, VEX, PD; defm W : avx512_mask_testop, VEX, PS; defm Q : avx512_mask_testop, VEX, PS, VEX_W; defm D : avx512_mask_testop, VEX, PD, VEX_W; } defm KORTEST : avx512_mask_testop_w<0x98, "kortest", X86kortest>; defm KTEST : avx512_mask_testop_w<0x99, "ktest", X86ktest, HasDQI>; // Mask shift multiclass avx512_mask_shiftop opc, string OpcodeStr, RegisterClass KRC, SDNode OpNode> { let Predicates = [HasAVX512] in def ri : Ii8; } multiclass avx512_mask_shiftop_w opc1, bits<8> opc2, string OpcodeStr, SDNode OpNode> { defm W : avx512_mask_shiftop, VEX, TAPD, VEX_W; let Predicates = [HasDQI] in defm B : avx512_mask_shiftop, VEX, TAPD; let Predicates = [HasBWI] in { defm Q : avx512_mask_shiftop, VEX, TAPD, VEX_W; let Predicates = [HasDQI] in defm D : avx512_mask_shiftop, VEX, TAPD; } } defm KSHIFTL : avx512_mask_shiftop_w<0x32, 0x33, "kshiftl", X86vshli>; defm KSHIFTR : avx512_mask_shiftop_w<0x30, 0x31, "kshiftr", X86vsrli>; // Mask setting all 0s or 1s multiclass avx512_mask_setop { let Predicates = [HasAVX512] in let isReMaterializable = 1, isAsCheapAsAMove = 1, isPseudo = 1 in def #NAME# : I<0, Pseudo, (outs KRC:$dst), (ins), "", [(set KRC:$dst, (VT Val))]>; } multiclass avx512_mask_setop_w { defm B : avx512_mask_setop; defm W : avx512_mask_setop; defm D : avx512_mask_setop; defm Q : avx512_mask_setop; } defm KSET0 : avx512_mask_setop_w; defm KSET1 : avx512_mask_setop_w; // With AVX-512 only, 8-bit mask is promoted to 16-bit mask. let Predicates = [HasAVX512] in { def : Pat<(v8i1 immAllZerosV), (COPY_TO_REGCLASS (KSET0W), VK8)>; def : Pat<(v8i1 immAllOnesV), (COPY_TO_REGCLASS (KSET1W), VK8)>; def : Pat<(v4i1 immAllOnesV), (COPY_TO_REGCLASS (KSET1W), VK4)>; def : Pat<(v2i1 immAllOnesV), (COPY_TO_REGCLASS (KSET1W), VK2)>; def : Pat<(i1 0), (COPY_TO_REGCLASS (KSET0W), VK1)>; def : Pat<(i1 1), (COPY_TO_REGCLASS (KSHIFTRWri (KSET1W), (i8 15)), VK1)>; def : Pat<(i1 -1), (COPY_TO_REGCLASS (KSHIFTRWri (KSET1W), (i8 15)), VK1)>; } def : Pat<(v8i1 (extract_subvector (v16i1 VK16:$src), (iPTR 0))), (v8i1 (COPY_TO_REGCLASS VK16:$src, VK8))>; def : Pat<(v16i1 (insert_subvector undef, (v8i1 VK8:$src), (iPTR 0))), (v16i1 (COPY_TO_REGCLASS VK8:$src, VK16))>; def : Pat<(v8i1 (extract_subvector (v16i1 VK16:$src), (iPTR 8))), (v8i1 (COPY_TO_REGCLASS (KSHIFTRWri VK16:$src, (i8 8)), VK8))>; def : Pat<(v16i1 (extract_subvector (v32i1 VK32:$src), (iPTR 0))), (v16i1 (COPY_TO_REGCLASS VK32:$src, VK16))>; def : Pat<(v16i1 (extract_subvector (v32i1 VK32:$src), (iPTR 16))), (v16i1 (COPY_TO_REGCLASS (KSHIFTRDri VK32:$src, (i8 16)), VK16))>; def : Pat<(v32i1 (extract_subvector (v64i1 VK64:$src), (iPTR 0))), (v32i1 (COPY_TO_REGCLASS VK64:$src, VK32))>; def : Pat<(v32i1 (extract_subvector (v64i1 VK64:$src), (iPTR 32))), (v32i1 (COPY_TO_REGCLASS (KSHIFTRQri VK64:$src, (i8 32)), VK32))>; def : Pat<(v4i1 (extract_subvector (v8i1 VK8:$src), (iPTR 0))), (v4i1 (COPY_TO_REGCLASS VK8:$src, VK4))>; def : Pat<(v2i1 (extract_subvector (v8i1 VK8:$src), (iPTR 0))), (v2i1 (COPY_TO_REGCLASS VK8:$src, VK2))>; def : Pat<(v4i1 (insert_subvector undef, (v2i1 VK2:$src), (iPTR 0))), (v4i1 (COPY_TO_REGCLASS VK2:$src, VK4))>; def : Pat<(v8i1 (insert_subvector undef, (v4i1 VK4:$src), (iPTR 0))), (v8i1 (COPY_TO_REGCLASS VK4:$src, VK8))>; def : Pat<(v8i1 (insert_subvector undef, (v2i1 VK2:$src), (iPTR 0))), (v8i1 (COPY_TO_REGCLASS VK2:$src, VK8))>; def : Pat<(v32i1 (insert_subvector undef, VK2:$src, (iPTR 0))), (v32i1 (COPY_TO_REGCLASS VK2:$src, VK32))>; def : Pat<(v32i1 (insert_subvector undef, VK4:$src, (iPTR 0))), (v32i1 (COPY_TO_REGCLASS VK4:$src, VK32))>; def : Pat<(v32i1 (insert_subvector undef, VK8:$src, (iPTR 0))), (v32i1 (COPY_TO_REGCLASS VK8:$src, VK32))>; def : Pat<(v32i1 (insert_subvector undef, VK16:$src, (iPTR 0))), (v32i1 (COPY_TO_REGCLASS VK16:$src, VK32))>; def : Pat<(v64i1 (insert_subvector undef, VK2:$src, (iPTR 0))), (v64i1 (COPY_TO_REGCLASS VK2:$src, VK64))>; def : Pat<(v64i1 (insert_subvector undef, VK4:$src, (iPTR 0))), (v64i1 (COPY_TO_REGCLASS VK4:$src, VK64))>; def : Pat<(v64i1 (insert_subvector undef, VK8:$src, (iPTR 0))), (v64i1 (COPY_TO_REGCLASS VK8:$src, VK64))>; def : Pat<(v64i1 (insert_subvector undef, VK16:$src, (iPTR 0))), (v64i1 (COPY_TO_REGCLASS VK16:$src, VK64))>; def : Pat<(v64i1 (insert_subvector undef, VK32:$src, (iPTR 0))), (v64i1 (COPY_TO_REGCLASS VK32:$src, VK64))>; def : Pat<(v8i1 (X86vshli VK8:$src, (i8 imm:$imm))), (v8i1 (COPY_TO_REGCLASS (KSHIFTLWri (COPY_TO_REGCLASS VK8:$src, VK16), (I8Imm $imm)), VK8))>, Requires<[HasAVX512, NoDQI]>; def : Pat<(v8i1 (X86vsrli VK8:$src, (i8 imm:$imm))), (v8i1 (COPY_TO_REGCLASS (KSHIFTRWri (COPY_TO_REGCLASS VK8:$src, VK16), (I8Imm $imm)), VK8))>, Requires<[HasAVX512, NoDQI]>; def : Pat<(v4i1 (X86vshli VK4:$src, (i8 imm:$imm))), (v4i1 (COPY_TO_REGCLASS (KSHIFTLWri (COPY_TO_REGCLASS VK4:$src, VK16), (I8Imm $imm)), VK4))>, Requires<[HasAVX512]>; def : Pat<(v4i1 (X86vsrli VK4:$src, (i8 imm:$imm))), (v4i1 (COPY_TO_REGCLASS (KSHIFTRWri (COPY_TO_REGCLASS VK4:$src, VK16), (I8Imm $imm)), VK4))>, Requires<[HasAVX512]>; //===----------------------------------------------------------------------===// // AVX-512 - Aligned and unaligned load and store // multiclass avx512_load opc, string OpcodeStr, X86VectorVTInfo _, PatFrag ld_frag, PatFrag mload, bit IsReMaterializable = 1> { let hasSideEffects = 0 in { def rr : AVX512PI, EVEX; def rrkz : AVX512PI, EVEX, EVEX_KZ; let canFoldAsLoad = 1, isReMaterializable = IsReMaterializable, SchedRW = [WriteLoad] in def rm : AVX512PI, EVEX; let Constraints = "$src0 = $dst" in { def rrk : AVX512PI, EVEX, EVEX_K; let mayLoad = 1, SchedRW = [WriteLoad] in def rmk : AVX512PI, EVEX, EVEX_K; } let mayLoad = 1, SchedRW = [WriteLoad] in def rmkz : AVX512PI, EVEX, EVEX_KZ; } def : Pat<(_.VT (mload addr:$ptr, _.KRCWM:$mask, undef)), (!cast(NAME#_.ZSuffix##rmkz) _.KRCWM:$mask, addr:$ptr)>; def : Pat<(_.VT (mload addr:$ptr, _.KRCWM:$mask, _.ImmAllZerosV)), (!cast(NAME#_.ZSuffix##rmkz) _.KRCWM:$mask, addr:$ptr)>; def : Pat<(_.VT (mload addr:$ptr, _.KRCWM:$mask, (_.VT _.RC:$src0))), (!cast(NAME#_.ZSuffix##rmk) _.RC:$src0, _.KRCWM:$mask, addr:$ptr)>; } multiclass avx512_alignedload_vl opc, string OpcodeStr, AVX512VLVectorVTInfo _, Predicate prd, bit IsReMaterializable = 1> { let Predicates = [prd] in defm Z : avx512_load, EVEX_V512; let Predicates = [prd, HasVLX] in { defm Z256 : avx512_load, EVEX_V256; defm Z128 : avx512_load, EVEX_V128; } } multiclass avx512_load_vl opc, string OpcodeStr, AVX512VLVectorVTInfo _, Predicate prd, bit IsReMaterializable = 1> { let Predicates = [prd] in defm Z : avx512_load, EVEX_V512; let Predicates = [prd, HasVLX] in { defm Z256 : avx512_load, EVEX_V256; defm Z128 : avx512_load, EVEX_V128; } } multiclass avx512_store opc, string OpcodeStr, X86VectorVTInfo _, PatFrag st_frag, PatFrag mstore> { def rr_REV : AVX512PI, EVEX; def rrk_REV : AVX512PI, EVEX, EVEX_K; def rrkz_REV : AVX512PI, EVEX, EVEX_KZ; let mayStore = 1 in { def mr : AVX512PI, EVEX; def mrk : AVX512PI, EVEX, EVEX_K; } def: Pat<(mstore addr:$ptr, _.KRCWM:$mask, (_.VT _.RC:$src)), (!cast(NAME#_.ZSuffix##mrk) addr:$ptr, _.KRCWM:$mask, _.RC:$src)>; } multiclass avx512_store_vl< bits<8> opc, string OpcodeStr, AVX512VLVectorVTInfo _, Predicate prd> { let Predicates = [prd] in defm Z : avx512_store, EVEX_V512; let Predicates = [prd, HasVLX] in { defm Z256 : avx512_store, EVEX_V256; defm Z128 : avx512_store, EVEX_V128; } } multiclass avx512_alignedstore_vl opc, string OpcodeStr, AVX512VLVectorVTInfo _, Predicate prd> { let Predicates = [prd] in defm Z : avx512_store, EVEX_V512; let Predicates = [prd, HasVLX] in { defm Z256 : avx512_store, EVEX_V256; defm Z128 : avx512_store, EVEX_V128; } } defm VMOVAPS : avx512_alignedload_vl<0x28, "vmovaps", avx512vl_f32_info, HasAVX512>, avx512_alignedstore_vl<0x29, "vmovaps", avx512vl_f32_info, HasAVX512>, PS, EVEX_CD8<32, CD8VF>; defm VMOVAPD : avx512_alignedload_vl<0x28, "vmovapd", avx512vl_f64_info, HasAVX512>, avx512_alignedstore_vl<0x29, "vmovapd", avx512vl_f64_info, HasAVX512>, PD, VEX_W, EVEX_CD8<64, CD8VF>; defm VMOVUPS : avx512_load_vl<0x10, "vmovups", avx512vl_f32_info, HasAVX512>, avx512_store_vl<0x11, "vmovups", avx512vl_f32_info, HasAVX512>, PS, EVEX_CD8<32, CD8VF>; defm VMOVUPD : avx512_load_vl<0x10, "vmovupd", avx512vl_f64_info, HasAVX512, 0>, avx512_store_vl<0x11, "vmovupd", avx512vl_f64_info, HasAVX512>, PD, VEX_W, EVEX_CD8<64, CD8VF>; def: Pat<(int_x86_avx512_mask_storeu_ps_512 addr:$ptr, (v16f32 VR512:$src), GR16:$mask), (VMOVUPSZmrk addr:$ptr, (v16i1 (COPY_TO_REGCLASS GR16:$mask, VK16WM)), VR512:$src)>; def: Pat<(int_x86_avx512_mask_storeu_pd_512 addr:$ptr, (v8f64 VR512:$src), GR8:$mask), (VMOVUPDZmrk addr:$ptr, (v8i1 (COPY_TO_REGCLASS GR8:$mask, VK8WM)), VR512:$src)>; def: Pat<(int_x86_avx512_mask_store_ps_512 addr:$ptr, (v16f32 VR512:$src), GR16:$mask), (VMOVAPSZmrk addr:$ptr, (v16i1 (COPY_TO_REGCLASS GR16:$mask, VK16WM)), VR512:$src)>; def: Pat<(int_x86_avx512_mask_store_pd_512 addr:$ptr, (v8f64 VR512:$src), GR8:$mask), (VMOVAPDZmrk addr:$ptr, (v8i1 (COPY_TO_REGCLASS GR8:$mask, VK8WM)), VR512:$src)>; defm VMOVDQA32 : avx512_alignedload_vl<0x6F, "vmovdqa32", avx512vl_i32_info, HasAVX512>, avx512_alignedstore_vl<0x7F, "vmovdqa32", avx512vl_i32_info, HasAVX512>, PD, EVEX_CD8<32, CD8VF>; defm VMOVDQA64 : avx512_alignedload_vl<0x6F, "vmovdqa64", avx512vl_i64_info, HasAVX512>, avx512_alignedstore_vl<0x7F, "vmovdqa64", avx512vl_i64_info, HasAVX512>, PD, VEX_W, EVEX_CD8<64, CD8VF>; defm VMOVDQU8 : avx512_load_vl<0x6F, "vmovdqu8", avx512vl_i8_info, HasBWI>, avx512_store_vl<0x7F, "vmovdqu8", avx512vl_i8_info, HasBWI>, XD, EVEX_CD8<8, CD8VF>; defm VMOVDQU16 : avx512_load_vl<0x6F, "vmovdqu16", avx512vl_i16_info, HasBWI>, avx512_store_vl<0x7F, "vmovdqu16", avx512vl_i16_info, HasBWI>, XD, VEX_W, EVEX_CD8<16, CD8VF>; defm VMOVDQU32 : avx512_load_vl<0x6F, "vmovdqu32", avx512vl_i32_info, HasAVX512>, avx512_store_vl<0x7F, "vmovdqu32", avx512vl_i32_info, HasAVX512>, XS, EVEX_CD8<32, CD8VF>; defm VMOVDQU64 : avx512_load_vl<0x6F, "vmovdqu64", avx512vl_i64_info, HasAVX512>, avx512_store_vl<0x7F, "vmovdqu64", avx512vl_i64_info, HasAVX512>, XS, VEX_W, EVEX_CD8<64, CD8VF>; def: Pat<(v16i32 (int_x86_avx512_mask_loadu_d_512 addr:$ptr, (v16i32 immAllZerosV), GR16:$mask)), (VMOVDQU32Zrmkz (v16i1 (COPY_TO_REGCLASS GR16:$mask, VK16WM)), addr:$ptr)>; def: Pat<(v8i64 (int_x86_avx512_mask_loadu_q_512 addr:$ptr, (bc_v8i64 (v16i32 immAllZerosV)), GR8:$mask)), (VMOVDQU64Zrmkz (v8i1 (COPY_TO_REGCLASS GR8:$mask, VK8WM)), addr:$ptr)>; def: Pat<(int_x86_avx512_mask_storeu_d_512 addr:$ptr, (v16i32 VR512:$src), GR16:$mask), (VMOVDQU32Zmrk addr:$ptr, (v16i1 (COPY_TO_REGCLASS GR16:$mask, VK16WM)), VR512:$src)>; def: Pat<(int_x86_avx512_mask_storeu_q_512 addr:$ptr, (v8i64 VR512:$src), GR8:$mask), (VMOVDQU64Zmrk addr:$ptr, (v8i1 (COPY_TO_REGCLASS GR8:$mask, VK8WM)), VR512:$src)>; let AddedComplexity = 20 in { def : Pat<(v8i64 (vselect VK8WM:$mask, (v8i64 VR512:$src), (bc_v8i64 (v16i32 immAllZerosV)))), (VMOVDQU64Zrrkz VK8WM:$mask, VR512:$src)>; def : Pat<(v8i64 (vselect VK8WM:$mask, (bc_v8i64 (v16i32 immAllZerosV)), (v8i64 VR512:$src))), (VMOVDQU64Zrrkz (COPY_TO_REGCLASS (KNOTWrr (COPY_TO_REGCLASS VK8:$mask, VK16)), VK8), VR512:$src)>; def : Pat<(v16i32 (vselect VK16WM:$mask, (v16i32 VR512:$src), (v16i32 immAllZerosV))), (VMOVDQU32Zrrkz VK16WM:$mask, VR512:$src)>; def : Pat<(v16i32 (vselect VK16WM:$mask, (v16i32 immAllZerosV), (v16i32 VR512:$src))), (VMOVDQU32Zrrkz (KNOTWrr VK16WM:$mask), VR512:$src)>; } // Move Int Doubleword to Packed Double Int // def VMOVDI2PDIZrr : AVX512BI<0x6E, MRMSrcReg, (outs VR128X:$dst), (ins GR32:$src), "vmovd\t{$src, $dst|$dst, $src}", [(set VR128X:$dst, (v4i32 (scalar_to_vector GR32:$src)))], IIC_SSE_MOVDQ>, EVEX; def VMOVDI2PDIZrm : AVX512BI<0x6E, MRMSrcMem, (outs VR128X:$dst), (ins i32mem:$src), "vmovd\t{$src, $dst|$dst, $src}", [(set VR128X:$dst, (v4i32 (scalar_to_vector (loadi32 addr:$src))))], IIC_SSE_MOVDQ>, EVEX, EVEX_CD8<32, CD8VT1>; def VMOV64toPQIZrr : AVX512BI<0x6E, MRMSrcReg, (outs VR128X:$dst), (ins GR64:$src), "vmovq\t{$src, $dst|$dst, $src}", [(set VR128X:$dst, (v2i64 (scalar_to_vector GR64:$src)))], IIC_SSE_MOVDQ>, EVEX, VEX_W; let isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0, mayLoad = 1 in def VMOV64toPQIZrm : AVX512BI<0x6E, MRMSrcMem, (outs VR128X:$dst), (ins i64mem:$src), "vmovq\t{$src, $dst|$dst, $src}", []>, EVEX, VEX_W, EVEX_CD8<64, CD8VT1>; let isCodeGenOnly = 1 in { def VMOV64toSDZrr : AVX512BI<0x6E, MRMSrcReg, (outs FR64X:$dst), (ins GR64:$src), "vmovq\t{$src, $dst|$dst, $src}", [(set FR64X:$dst, (bitconvert GR64:$src))], IIC_SSE_MOVDQ>, EVEX, VEX_W, Sched<[WriteMove]>; def VMOVSDto64Zrr : AVX512BI<0x7E, MRMDestReg, (outs GR64:$dst), (ins FR64X:$src), "vmovq\t{$src, $dst|$dst, $src}", [(set GR64:$dst, (bitconvert FR64X:$src))], IIC_SSE_MOVDQ>, EVEX, VEX_W, Sched<[WriteMove]>; def VMOVSDto64Zmr : AVX512BI<0x7E, MRMDestMem, (outs), (ins i64mem:$dst, FR64X:$src), "vmovq\t{$src, $dst|$dst, $src}", [(store (i64 (bitconvert FR64X:$src)), addr:$dst)], IIC_SSE_MOVDQ>, EVEX, VEX_W, Sched<[WriteStore]>, EVEX_CD8<64, CD8VT1>; } // Move Int Doubleword to Single Scalar // let isCodeGenOnly = 1 in { def VMOVDI2SSZrr : AVX512BI<0x6E, MRMSrcReg, (outs FR32X:$dst), (ins GR32:$src), "vmovd\t{$src, $dst|$dst, $src}", [(set FR32X:$dst, (bitconvert GR32:$src))], IIC_SSE_MOVDQ>, EVEX; def VMOVDI2SSZrm : AVX512BI<0x6E, MRMSrcMem, (outs FR32X:$dst), (ins i32mem:$src), "vmovd\t{$src, $dst|$dst, $src}", [(set FR32X:$dst, (bitconvert (loadi32 addr:$src)))], IIC_SSE_MOVDQ>, EVEX, EVEX_CD8<32, CD8VT1>; } // Move doubleword from xmm register to r/m32 // def VMOVPDI2DIZrr : AVX512BI<0x7E, MRMDestReg, (outs GR32:$dst), (ins VR128X:$src), "vmovd\t{$src, $dst|$dst, $src}", [(set GR32:$dst, (extractelt (v4i32 VR128X:$src), (iPTR 0)))], IIC_SSE_MOVD_ToGP>, EVEX; def VMOVPDI2DIZmr : AVX512BI<0x7E, MRMDestMem, (outs), (ins i32mem:$dst, VR128X:$src), "vmovd\t{$src, $dst|$dst, $src}", [(store (i32 (extractelt (v4i32 VR128X:$src), (iPTR 0))), addr:$dst)], IIC_SSE_MOVDQ>, EVEX, EVEX_CD8<32, CD8VT1>; // Move quadword from xmm1 register to r/m64 // def VMOVPQIto64Zrr : I<0x7E, MRMDestReg, (outs GR64:$dst), (ins VR128X:$src), "vmovq\t{$src, $dst|$dst, $src}", [(set GR64:$dst, (extractelt (v2i64 VR128X:$src), (iPTR 0)))], IIC_SSE_MOVD_ToGP>, PD, EVEX, VEX_W, Requires<[HasAVX512, In64BitMode]>; let isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0, mayStore = 1 in def VMOVPQIto64Zmr : I<0x7E, MRMDestMem, (outs), (ins i64mem:$dst, VR128X:$src), "vmovq\t{$src, $dst|$dst, $src}", [], IIC_SSE_MOVD_ToGP>, PD, EVEX, VEX_W, Requires<[HasAVX512, In64BitMode]>; def VMOVPQI2QIZmr : I<0xD6, MRMDestMem, (outs), (ins i64mem:$dst, VR128X:$src), "vmovq\t{$src, $dst|$dst, $src}", [(store (extractelt (v2i64 VR128X:$src), (iPTR 0)), addr:$dst)], IIC_SSE_MOVDQ>, EVEX, PD, VEX_W, EVEX_CD8<64, CD8VT1>, Sched<[WriteStore]>, Requires<[HasAVX512, In64BitMode]>; let hasSideEffects = 0 in def VMOVPQI2QIZrr : AVX512BI<0xD6, MRMDestReg, (outs VR128X:$dst), (ins VR128X:$src), "vmovq.s\t{$src, $dst|$dst, $src}",[]>, EVEX, VEX_W; // Move Scalar Single to Double Int // let isCodeGenOnly = 1 in { def VMOVSS2DIZrr : AVX512BI<0x7E, MRMDestReg, (outs GR32:$dst), (ins FR32X:$src), "vmovd\t{$src, $dst|$dst, $src}", [(set GR32:$dst, (bitconvert FR32X:$src))], IIC_SSE_MOVD_ToGP>, EVEX; def VMOVSS2DIZmr : AVX512BI<0x7E, MRMDestMem, (outs), (ins i32mem:$dst, FR32X:$src), "vmovd\t{$src, $dst|$dst, $src}", [(store (i32 (bitconvert FR32X:$src)), addr:$dst)], IIC_SSE_MOVDQ>, EVEX, EVEX_CD8<32, CD8VT1>; } // Move Quadword Int to Packed Quadword Int // def VMOVQI2PQIZrm : AVX512XSI<0x7E, MRMSrcMem, (outs VR128X:$dst), (ins i64mem:$src), "vmovq\t{$src, $dst|$dst, $src}", [(set VR128X:$dst, (v2i64 (scalar_to_vector (loadi64 addr:$src))))]>, EVEX, VEX_W, EVEX_CD8<8, CD8VT8>; //===----------------------------------------------------------------------===// // AVX-512 MOVSS, MOVSD //===----------------------------------------------------------------------===// multiclass avx512_move_scalar { defm rr_Int : AVX512_maskable_scalar<0x10, MRMSrcReg, _, (outs _.RC:$dst), (ins _.RC:$src1, _.RC:$src2), asm, "$src2, $src1","$src1, $src2", (_.VT (OpNode (_.VT _.RC:$src1), (_.VT _.RC:$src2))), IIC_SSE_MOV_S_RR>, EVEX_4V; let Constraints = "$src1 = $dst" , mayLoad = 1 in defm rm_Int : AVX512_maskable_3src_scalar<0x10, MRMSrcMem, _, (outs _.RC:$dst), (ins _.ScalarMemOp:$src), asm,"$src","$src", (_.VT (OpNode (_.VT _.RC:$src1), (_.VT (scalar_to_vector (_.ScalarLdFrag addr:$src)))))>, EVEX; let isCodeGenOnly = 1 in { def rr : AVX512PI<0x10, MRMSrcReg, (outs _.RC:$dst), (ins _.RC:$src1, _.FRC:$src2), !strconcat(asm, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"), [(set _.RC:$dst, (_.VT (OpNode _.RC:$src1, (scalar_to_vector _.FRC:$src2))))], _.ExeDomain,IIC_SSE_MOV_S_RR>, EVEX_4V; let mayLoad = 1 in def rm : AVX512PI<0x10, MRMSrcMem, (outs _.FRC:$dst), (ins _.ScalarMemOp:$src), !strconcat(asm, "\t{$src, $dst|$dst, $src}"), [(set _.FRC:$dst, (_.ScalarLdFrag addr:$src))], _.ExeDomain, IIC_SSE_MOV_S_RM>, EVEX; } let mayStore = 1 in { def mr: AVX512PI<0x11, MRMDestMem, (outs), (ins _.ScalarMemOp:$dst, _.FRC:$src), !strconcat(asm, "\t{$src, $dst|$dst, $src}"), [(store _.FRC:$src, addr:$dst)], _.ExeDomain, IIC_SSE_MOV_S_MR>, EVEX; def mrk: AVX512PI<0x11, MRMDestMem, (outs), (ins _.ScalarMemOp:$dst, VK1WM:$mask, _.FRC:$src), !strconcat(asm, "\t{$src, $dst {${mask}}|$dst {${mask}}, $src}"), [], _.ExeDomain, IIC_SSE_MOV_S_MR>, EVEX, EVEX_K; } // mayStore } defm VMOVSSZ : avx512_move_scalar<"vmovss", X86Movss, f32x_info>, VEX_LIG, XS, EVEX_CD8<32, CD8VT1>; defm VMOVSDZ : avx512_move_scalar<"vmovsd", X86Movsd, f64x_info>, VEX_LIG, XD, VEX_W, EVEX_CD8<64, CD8VT1>; def : Pat<(f32 (X86select VK1WM:$mask, (f32 FR32X:$src1), (f32 FR32X:$src2))), (COPY_TO_REGCLASS (VMOVSSZrr_Intk (COPY_TO_REGCLASS FR32X:$src2, VR128X), VK1WM:$mask, (v4f32 (IMPLICIT_DEF)),(COPY_TO_REGCLASS FR32X:$src1, VR128X)), FR32X)>; def : Pat<(f64 (X86select VK1WM:$mask, (f64 FR64X:$src1), (f64 FR64X:$src2))), (COPY_TO_REGCLASS (VMOVSDZrr_Intk (COPY_TO_REGCLASS FR64X:$src2, VR128X), VK1WM:$mask, (v2f64 (IMPLICIT_DEF)), (COPY_TO_REGCLASS FR64X:$src1, VR128X)), FR64X)>; def : Pat<(int_x86_avx512_mask_store_ss addr:$dst, VR128X:$src, GR8:$mask), (VMOVSSZmrk addr:$dst, (i1 (COPY_TO_REGCLASS GR8:$mask, VK1WM)), (COPY_TO_REGCLASS VR128X:$src, FR32X))>; defm VMOVSSZrr_REV : AVX512_maskable_in_asm<0x11, MRMDestReg, f32x_info, (outs VR128X:$dst), (ins VR128X:$src1, VR128X:$src2), "vmovss.s", "$src2, $src1", "$src1, $src2", []>, XS, EVEX_4V, VEX_LIG; defm VMOVSSDrr_REV : AVX512_maskable_in_asm<0x11, MRMDestReg, f64x_info, (outs VR128X:$dst), (ins VR128X:$src1, VR128X:$src2), "vmovsd.s", "$src2, $src1", "$src1, $src2", []>, XD, EVEX_4V, VEX_LIG, VEX_W; let Predicates = [HasAVX512] in { let AddedComplexity = 15 in { // Move scalar to XMM zero-extended, zeroing a VR128X then do a // MOVS{S,D} to the lower bits. def : Pat<(v4f32 (X86vzmovl (v4f32 (scalar_to_vector FR32X:$src)))), (VMOVSSZrr (v4f32 (V_SET0)), FR32X:$src)>; def : Pat<(v4f32 (X86vzmovl (v4f32 VR128X:$src))), (VMOVSSZrr (v4f32 (V_SET0)), (COPY_TO_REGCLASS VR128X:$src, FR32X))>; def : Pat<(v4i32 (X86vzmovl (v4i32 VR128X:$src))), (VMOVSSZrr (v4i32 (V_SET0)), (COPY_TO_REGCLASS VR128X:$src, FR32X))>; def : Pat<(v2f64 (X86vzmovl (v2f64 (scalar_to_vector FR64X:$src)))), (VMOVSDZrr (v2f64 (V_SET0)), FR64X:$src)>; // Move low f32 and clear high bits. def : Pat<(v8f32 (X86vzmovl (v8f32 VR256X:$src))), (SUBREG_TO_REG (i32 0), (VMOVSSZrr (v4f32 (V_SET0)), (EXTRACT_SUBREG (v8f32 VR256X:$src), sub_xmm)), sub_xmm)>; def : Pat<(v8i32 (X86vzmovl (v8i32 VR256X:$src))), (SUBREG_TO_REG (i32 0), (VMOVSSZrr (v4i32 (V_SET0)), (EXTRACT_SUBREG (v8i32 VR256X:$src), sub_xmm)), sub_xmm)>; } let AddedComplexity = 20 in { // MOVSSrm zeros the high parts of the register; represent this // with SUBREG_TO_REG. The AVX versions also write: DST[255:128] <- 0 def : Pat<(v4f32 (X86vzmovl (v4f32 (scalar_to_vector (loadf32 addr:$src))))), (COPY_TO_REGCLASS (VMOVSSZrm addr:$src), VR128X)>; def : Pat<(v4f32 (scalar_to_vector (loadf32 addr:$src))), (COPY_TO_REGCLASS (VMOVSSZrm addr:$src), VR128X)>; def : Pat<(v4f32 (X86vzmovl (loadv4f32 addr:$src))), (COPY_TO_REGCLASS (VMOVSSZrm addr:$src), VR128X)>; // MOVSDrm zeros the high parts of the register; represent this // with SUBREG_TO_REG. The AVX versions also write: DST[255:128] <- 0 def : Pat<(v2f64 (X86vzmovl (v2f64 (scalar_to_vector (loadf64 addr:$src))))), (COPY_TO_REGCLASS (VMOVSDZrm addr:$src), VR128X)>; def : Pat<(v2f64 (scalar_to_vector (loadf64 addr:$src))), (COPY_TO_REGCLASS (VMOVSDZrm addr:$src), VR128X)>; def : Pat<(v2f64 (X86vzmovl (loadv2f64 addr:$src))), (COPY_TO_REGCLASS (VMOVSDZrm addr:$src), VR128X)>; def : Pat<(v2f64 (X86vzmovl (bc_v2f64 (loadv4f32 addr:$src)))), (COPY_TO_REGCLASS (VMOVSDZrm addr:$src), VR128X)>; def : Pat<(v2f64 (X86vzload addr:$src)), (COPY_TO_REGCLASS (VMOVSDZrm addr:$src), VR128X)>; // Represent the same patterns above but in the form they appear for // 256-bit types def : Pat<(v8i32 (X86vzmovl (insert_subvector undef, (v4i32 (scalar_to_vector (loadi32 addr:$src))), (iPTR 0)))), (SUBREG_TO_REG (i32 0), (VMOVDI2PDIZrm addr:$src), sub_xmm)>; def : Pat<(v8f32 (X86vzmovl (insert_subvector undef, (v4f32 (scalar_to_vector (loadf32 addr:$src))), (iPTR 0)))), (SUBREG_TO_REG (i32 0), (VMOVSSZrm addr:$src), sub_xmm)>; def : Pat<(v4f64 (X86vzmovl (insert_subvector undef, (v2f64 (scalar_to_vector (loadf64 addr:$src))), (iPTR 0)))), (SUBREG_TO_REG (i32 0), (VMOVSDZrm addr:$src), sub_xmm)>; } def : Pat<(v8f32 (X86vzmovl (insert_subvector undef, (v4f32 (scalar_to_vector FR32X:$src)), (iPTR 0)))), (SUBREG_TO_REG (i32 0), (v4f32 (VMOVSSZrr (v4f32 (V_SET0)), FR32X:$src)), sub_xmm)>; def : Pat<(v4f64 (X86vzmovl (insert_subvector undef, (v2f64 (scalar_to_vector FR64X:$src)), (iPTR 0)))), (SUBREG_TO_REG (i64 0), (v2f64 (VMOVSDZrr (v2f64 (V_SET0)), FR64X:$src)), sub_xmm)>; def : Pat<(v4i64 (X86vzmovl (insert_subvector undef, (v2i64 (scalar_to_vector (loadi64 addr:$src))), (iPTR 0)))), (SUBREG_TO_REG (i64 0), (VMOVQI2PQIZrm addr:$src), sub_xmm)>; // Move low f64 and clear high bits. def : Pat<(v4f64 (X86vzmovl (v4f64 VR256X:$src))), (SUBREG_TO_REG (i32 0), (VMOVSDZrr (v2f64 (V_SET0)), (EXTRACT_SUBREG (v4f64 VR256X:$src), sub_xmm)), sub_xmm)>; def : Pat<(v4i64 (X86vzmovl (v4i64 VR256X:$src))), (SUBREG_TO_REG (i32 0), (VMOVSDZrr (v2i64 (V_SET0)), (EXTRACT_SUBREG (v4i64 VR256X:$src), sub_xmm)), sub_xmm)>; // Extract and store. def : Pat<(store (f32 (extractelt (v4f32 VR128X:$src), (iPTR 0))), addr:$dst), (VMOVSSZmr addr:$dst, (COPY_TO_REGCLASS (v4f32 VR128X:$src), FR32X))>; def : Pat<(store (f64 (extractelt (v2f64 VR128X:$src), (iPTR 0))), addr:$dst), (VMOVSDZmr addr:$dst, (COPY_TO_REGCLASS (v2f64 VR128X:$src), FR64X))>; // Shuffle with VMOVSS def : Pat<(v4i32 (X86Movss VR128X:$src1, VR128X:$src2)), (VMOVSSZrr (v4i32 VR128X:$src1), (COPY_TO_REGCLASS (v4i32 VR128X:$src2), FR32X))>; def : Pat<(v4f32 (X86Movss VR128X:$src1, VR128X:$src2)), (VMOVSSZrr (v4f32 VR128X:$src1), (COPY_TO_REGCLASS (v4f32 VR128X:$src2), FR32X))>; // 256-bit variants def : Pat<(v8i32 (X86Movss VR256X:$src1, VR256X:$src2)), (SUBREG_TO_REG (i32 0), (VMOVSSZrr (EXTRACT_SUBREG (v8i32 VR256X:$src1), sub_xmm), (EXTRACT_SUBREG (v8i32 VR256X:$src2), sub_xmm)), sub_xmm)>; def : Pat<(v8f32 (X86Movss VR256X:$src1, VR256X:$src2)), (SUBREG_TO_REG (i32 0), (VMOVSSZrr (EXTRACT_SUBREG (v8f32 VR256X:$src1), sub_xmm), (EXTRACT_SUBREG (v8f32 VR256X:$src2), sub_xmm)), sub_xmm)>; // Shuffle with VMOVSD def : Pat<(v2i64 (X86Movsd VR128X:$src1, VR128X:$src2)), (VMOVSDZrr VR128X:$src1, (COPY_TO_REGCLASS VR128X:$src2, FR64X))>; def : Pat<(v2f64 (X86Movsd VR128X:$src1, VR128X:$src2)), (VMOVSDZrr VR128X:$src1, (COPY_TO_REGCLASS VR128X:$src2, FR64X))>; def : Pat<(v4f32 (X86Movsd VR128X:$src1, VR128X:$src2)), (VMOVSDZrr VR128X:$src1, (COPY_TO_REGCLASS VR128X:$src2, FR64X))>; def : Pat<(v4i32 (X86Movsd VR128X:$src1, VR128X:$src2)), (VMOVSDZrr VR128X:$src1, (COPY_TO_REGCLASS VR128X:$src2, FR64X))>; // 256-bit variants def : Pat<(v4i64 (X86Movsd VR256X:$src1, VR256X:$src2)), (SUBREG_TO_REG (i32 0), (VMOVSDZrr (EXTRACT_SUBREG (v4i64 VR256X:$src1), sub_xmm), (EXTRACT_SUBREG (v4i64 VR256X:$src2), sub_xmm)), sub_xmm)>; def : Pat<(v4f64 (X86Movsd VR256X:$src1, VR256X:$src2)), (SUBREG_TO_REG (i32 0), (VMOVSDZrr (EXTRACT_SUBREG (v4f64 VR256X:$src1), sub_xmm), (EXTRACT_SUBREG (v4f64 VR256X:$src2), sub_xmm)), sub_xmm)>; def : Pat<(v2f64 (X86Movlpd VR128X:$src1, VR128X:$src2)), (VMOVSDZrr VR128X:$src1, (COPY_TO_REGCLASS VR128X:$src2, FR64X))>; def : Pat<(v2i64 (X86Movlpd VR128X:$src1, VR128X:$src2)), (VMOVSDZrr VR128X:$src1, (COPY_TO_REGCLASS VR128X:$src2, FR64X))>; def : Pat<(v4f32 (X86Movlps VR128X:$src1, VR128X:$src2)), (VMOVSDZrr VR128X:$src1, (COPY_TO_REGCLASS VR128X:$src2, FR64X))>; def : Pat<(v4i32 (X86Movlps VR128X:$src1, VR128X:$src2)), (VMOVSDZrr VR128X:$src1, (COPY_TO_REGCLASS VR128X:$src2, FR64X))>; } let AddedComplexity = 15 in def VMOVZPQILo2PQIZrr : AVX512XSI<0x7E, MRMSrcReg, (outs VR128X:$dst), (ins VR128X:$src), "vmovq\t{$src, $dst|$dst, $src}", [(set VR128X:$dst, (v2i64 (X86vzmovl (v2i64 VR128X:$src))))], IIC_SSE_MOVQ_RR>, EVEX, VEX_W; let AddedComplexity = 20 , isCodeGenOnly = 1 in def VMOVZPQILo2PQIZrm : AVX512XSI<0x7E, MRMSrcMem, (outs VR128X:$dst), (ins i128mem:$src), "vmovq\t{$src, $dst|$dst, $src}", [(set VR128X:$dst, (v2i64 (X86vzmovl (loadv2i64 addr:$src))))], IIC_SSE_MOVDQ>, EVEX, VEX_W, EVEX_CD8<8, CD8VT8>; let Predicates = [HasAVX512] in { // AVX 128-bit movd/movq instruction write zeros in the high 128-bit part. let AddedComplexity = 20 in { def : Pat<(v4i32 (X86vzmovl (v4i32 (scalar_to_vector (loadi32 addr:$src))))), (VMOVDI2PDIZrm addr:$src)>; def : Pat<(v2i64 (X86vzmovl (v2i64 (scalar_to_vector GR64:$src)))), (VMOV64toPQIZrr GR64:$src)>; def : Pat<(v4i32 (X86vzmovl (v4i32 (scalar_to_vector GR32:$src)))), (VMOVDI2PDIZrr GR32:$src)>; def : Pat<(v4i32 (X86vzmovl (bc_v4i32 (loadv4f32 addr:$src)))), (VMOVDI2PDIZrm addr:$src)>; def : Pat<(v4i32 (X86vzmovl (bc_v4i32 (loadv2i64 addr:$src)))), (VMOVDI2PDIZrm addr:$src)>; def : Pat<(v2i64 (X86vzmovl (loadv2i64 addr:$src))), (VMOVZPQILo2PQIZrm addr:$src)>; def : Pat<(v2f64 (X86vzmovl (v2f64 VR128X:$src))), (VMOVZPQILo2PQIZrr VR128X:$src)>; def : Pat<(v2i64 (X86vzload addr:$src)), (VMOVZPQILo2PQIZrm addr:$src)>; } // Use regular 128-bit instructions to match 256-bit scalar_to_vec+zext. def : Pat<(v8i32 (X86vzmovl (insert_subvector undef, (v4i32 (scalar_to_vector GR32:$src)),(iPTR 0)))), (SUBREG_TO_REG (i32 0), (VMOVDI2PDIZrr GR32:$src), sub_xmm)>; def : Pat<(v4i64 (X86vzmovl (insert_subvector undef, (v2i64 (scalar_to_vector GR64:$src)),(iPTR 0)))), (SUBREG_TO_REG (i64 0), (VMOV64toPQIZrr GR64:$src), sub_xmm)>; } def : Pat<(v16i32 (X86Vinsert (v16i32 immAllZerosV), GR32:$src2, (iPTR 0))), (SUBREG_TO_REG (i32 0), (VMOVDI2PDIZrr GR32:$src2), sub_xmm)>; def : Pat<(v8i64 (X86Vinsert (bc_v8i64 (v16i32 immAllZerosV)), GR64:$src2, (iPTR 0))), (SUBREG_TO_REG (i32 0), (VMOV64toPQIZrr GR64:$src2), sub_xmm)>; def : Pat<(v16i32 (X86Vinsert undef, GR32:$src2, (iPTR 0))), (SUBREG_TO_REG (i32 0), (VMOVDI2PDIZrr GR32:$src2), sub_xmm)>; def : Pat<(v8i64 (X86Vinsert undef, GR64:$src2, (iPTR 0))), (SUBREG_TO_REG (i32 0), (VMOV64toPQIZrr GR64:$src2), sub_xmm)>; //===----------------------------------------------------------------------===// // AVX-512 - Non-temporals //===----------------------------------------------------------------------===// let SchedRW = [WriteLoad] in { def VMOVNTDQAZrm : AVX512PI<0x2A, MRMSrcMem, (outs VR512:$dst), (ins i512mem:$src), "vmovntdqa\t{$src, $dst|$dst, $src}", [(set VR512:$dst, (int_x86_avx512_movntdqa addr:$src))], SSEPackedInt>, EVEX, T8PD, EVEX_V512, EVEX_CD8<64, CD8VF>; let Predicates = [HasAVX512, HasVLX] in { def VMOVNTDQAZ256rm : AVX512PI<0x2A, MRMSrcMem, (outs VR256X:$dst), (ins i256mem:$src), "vmovntdqa\t{$src, $dst|$dst, $src}", [], SSEPackedInt>, EVEX, T8PD, EVEX_V256, EVEX_CD8<64, CD8VF>; def VMOVNTDQAZ128rm : AVX512PI<0x2A, MRMSrcMem, (outs VR128X:$dst), (ins i128mem:$src), "vmovntdqa\t{$src, $dst|$dst, $src}", [], SSEPackedInt>, EVEX, T8PD, EVEX_V128, EVEX_CD8<64, CD8VF>; } } multiclass avx512_movnt opc, string OpcodeStr, PatFrag st_frag, ValueType OpVT, RegisterClass RC, X86MemOperand memop, Domain d, InstrItinClass itin = IIC_SSE_MOVNT> { let SchedRW = [WriteStore], mayStore = 1, AddedComplexity = 400 in def mr : AVX512PI, EVEX; } multiclass avx512_movnt_vl opc, string OpcodeStr, PatFrag st_frag, string elty, string elsz, string vsz512, string vsz256, string vsz128, Domain d, Predicate prd, InstrItinClass itin = IIC_SSE_MOVNT> { let Predicates = [prd] in defm Z : avx512_movnt("v"##vsz512##elty##elsz), VR512, !cast(elty##"512mem"), d, itin>, EVEX_V512; let Predicates = [prd, HasVLX] in { defm Z256 : avx512_movnt("v"##vsz256##elty##elsz), VR256X, !cast(elty##"256mem"), d, itin>, EVEX_V256; defm Z128 : avx512_movnt("v"##vsz128##elty##elsz), VR128X, !cast(elty##"128mem"), d, itin>, EVEX_V128; } } defm VMOVNTDQ : avx512_movnt_vl<0xE7, "vmovntdq", alignednontemporalstore, "i", "64", "8", "4", "2", SSEPackedInt, HasAVX512>, PD, EVEX_CD8<64, CD8VF>; defm VMOVNTPD : avx512_movnt_vl<0x2B, "vmovntpd", alignednontemporalstore, "f", "64", "8", "4", "2", SSEPackedDouble, HasAVX512>, PD, VEX_W, EVEX_CD8<64, CD8VF>; defm VMOVNTPS : avx512_movnt_vl<0x2B, "vmovntps", alignednontemporalstore, "f", "32", "16", "8", "4", SSEPackedSingle, HasAVX512>, PS, EVEX_CD8<32, CD8VF>; //===----------------------------------------------------------------------===// // AVX-512 - Integer arithmetic // multiclass avx512_binop_rm opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _, OpndItins itins, bit IsCommutable = 0> { defm rr : AVX512_maskable, AVX512BIBase, EVEX_4V; let mayLoad = 1 in defm rm : AVX512_maskable, AVX512BIBase, EVEX_4V; } multiclass avx512_binop_rmb opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _, OpndItins itins, bit IsCommutable = 0> : avx512_binop_rm { let mayLoad = 1 in defm rmb : AVX512_maskable, AVX512BIBase, EVEX_4V, EVEX_B; } multiclass avx512_binop_rm_vl opc, string OpcodeStr, SDNode OpNode, AVX512VLVectorVTInfo VTInfo, OpndItins itins, Predicate prd, bit IsCommutable = 0> { let Predicates = [prd] in defm Z : avx512_binop_rm, EVEX_V512; let Predicates = [prd, HasVLX] in { defm Z256 : avx512_binop_rm, EVEX_V256; defm Z128 : avx512_binop_rm, EVEX_V128; } } multiclass avx512_binop_rmb_vl opc, string OpcodeStr, SDNode OpNode, AVX512VLVectorVTInfo VTInfo, OpndItins itins, Predicate prd, bit IsCommutable = 0> { let Predicates = [prd] in defm Z : avx512_binop_rmb, EVEX_V512; let Predicates = [prd, HasVLX] in { defm Z256 : avx512_binop_rmb, EVEX_V256; defm Z128 : avx512_binop_rmb, EVEX_V128; } } multiclass avx512_binop_rm_vl_q opc, string OpcodeStr, SDNode OpNode, OpndItins itins, Predicate prd, bit IsCommutable = 0> { defm NAME : avx512_binop_rmb_vl, VEX_W, EVEX_CD8<64, CD8VF>; } multiclass avx512_binop_rm_vl_d opc, string OpcodeStr, SDNode OpNode, OpndItins itins, Predicate prd, bit IsCommutable = 0> { defm NAME : avx512_binop_rmb_vl, EVEX_CD8<32, CD8VF>; } multiclass avx512_binop_rm_vl_w opc, string OpcodeStr, SDNode OpNode, OpndItins itins, Predicate prd, bit IsCommutable = 0> { defm NAME : avx512_binop_rm_vl, EVEX_CD8<16, CD8VF>; } multiclass avx512_binop_rm_vl_b opc, string OpcodeStr, SDNode OpNode, OpndItins itins, Predicate prd, bit IsCommutable = 0> { defm NAME : avx512_binop_rm_vl, EVEX_CD8<8, CD8VF>; } multiclass avx512_binop_rm_vl_dq opc_d, bits<8> opc_q, string OpcodeStr, SDNode OpNode, OpndItins itins, Predicate prd, bit IsCommutable = 0> { defm Q : avx512_binop_rm_vl_q; defm D : avx512_binop_rm_vl_d; } multiclass avx512_binop_rm_vl_bw opc_b, bits<8> opc_w, string OpcodeStr, SDNode OpNode, OpndItins itins, Predicate prd, bit IsCommutable = 0> { defm W : avx512_binop_rm_vl_w; defm B : avx512_binop_rm_vl_b; } multiclass avx512_binop_rm_vl_all opc_b, bits<8> opc_w, bits<8> opc_d, bits<8> opc_q, string OpcodeStr, SDNode OpNode, OpndItins itins, bit IsCommutable = 0> { defm NAME : avx512_binop_rm_vl_dq, avx512_binop_rm_vl_bw; } multiclass avx512_binop_rm2 opc, string OpcodeStr, OpndItins itins, SDNode OpNode,X86VectorVTInfo _Src, X86VectorVTInfo _Dst, bit IsCommutable = 0> { defm rr : AVX512_maskable, AVX512BIBase, EVEX_4V; let mayLoad = 1 in { defm rm : AVX512_maskable, AVX512BIBase, EVEX_4V; defm rmb : AVX512_maskable, AVX512BIBase, EVEX_4V, EVEX_B; } } defm VPADD : avx512_binop_rm_vl_all<0xFC, 0xFD, 0xFE, 0xD4, "vpadd", add, SSE_INTALU_ITINS_P, 1>; defm VPSUB : avx512_binop_rm_vl_all<0xF8, 0xF9, 0xFA, 0xFB, "vpsub", sub, SSE_INTALU_ITINS_P, 0>; defm VPADDS : avx512_binop_rm_vl_bw<0xEC, 0xED, "vpadds", X86adds, SSE_INTALU_ITINS_P, HasBWI, 1>; defm VPSUBS : avx512_binop_rm_vl_bw<0xE8, 0xE9, "vpsubs", X86subs, SSE_INTALU_ITINS_P, HasBWI, 0>; defm VPADDUS : avx512_binop_rm_vl_bw<0xDC, 0xDD, "vpaddus", X86addus, SSE_INTALU_ITINS_P, HasBWI, 1>; defm VPSUBUS : avx512_binop_rm_vl_bw<0xD8, 0xD9, "vpsubus", X86subus, SSE_INTALU_ITINS_P, HasBWI, 0>; defm VPMULLD : avx512_binop_rm_vl_d<0x40, "vpmulld", mul, SSE_INTALU_ITINS_P, HasAVX512, 1>, T8PD; defm VPMULLW : avx512_binop_rm_vl_w<0xD5, "vpmullw", mul, SSE_INTALU_ITINS_P, HasBWI, 1>; defm VPMULLQ : avx512_binop_rm_vl_q<0x40, "vpmullq", mul, SSE_INTALU_ITINS_P, HasDQI, 1>, T8PD; defm VPMULHW : avx512_binop_rm_vl_w<0xE5, "vpmulhw", mulhs, SSE_INTALU_ITINS_P, HasBWI, 1>; defm VPMULHUW : avx512_binop_rm_vl_w<0xE4, "vpmulhuw", mulhu, SSE_INTMUL_ITINS_P, HasBWI, 1>; defm VPMULHRSW : avx512_binop_rm_vl_w<0x0B, "vpmulhrsw", X86mulhrs, SSE_INTMUL_ITINS_P, HasBWI, 1>, T8PD; defm VPAVG : avx512_binop_rm_vl_bw<0xE0, 0xE3, "vpavg", X86avg, SSE_INTALU_ITINS_P, HasBWI, 1>; multiclass avx512_binop_all opc, string OpcodeStr, OpndItins itins, SDNode OpNode, bit IsCommutable = 0> { defm NAME#Z : avx512_binop_rm2, EVEX_V512, EVEX_CD8<64, CD8VF>, VEX_W; let Predicates = [HasVLX] in { defm NAME#Z256 : avx512_binop_rm2, EVEX_V256, EVEX_CD8<64, CD8VF>, VEX_W; defm NAME#Z128 : avx512_binop_rm2, EVEX_V128, EVEX_CD8<64, CD8VF>, VEX_W; } } defm VPMULDQ : avx512_binop_all<0x28, "vpmuldq", SSE_INTALU_ITINS_P, X86pmuldq, 1>,T8PD; defm VPMULUDQ : avx512_binop_all<0xF4, "vpmuludq", SSE_INTMUL_ITINS_P, X86pmuludq, 1>; multiclass avx512_packs_rmb opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _Src, X86VectorVTInfo _Dst> { let mayLoad = 1 in { defm rmb : AVX512_maskable, EVEX_4V, EVEX_B, EVEX_CD8<_Src.EltSize, CD8VF>; } } multiclass avx512_packs_rm opc, string OpcodeStr, SDNode OpNode,X86VectorVTInfo _Src, X86VectorVTInfo _Dst> { defm rr : AVX512_maskable, EVEX_CD8<_Src.EltSize, CD8VF>, EVEX_4V; let mayLoad = 1 in { defm rm : AVX512_maskable, EVEX_4V, EVEX_CD8<_Src.EltSize, CD8VF>; } } multiclass avx512_packs_all_i32_i16 opc, string OpcodeStr, SDNode OpNode> { defm NAME#Z : avx512_packs_rm, avx512_packs_rmb, EVEX_V512; let Predicates = [HasVLX] in { defm NAME#Z256 : avx512_packs_rm, avx512_packs_rmb, EVEX_V256; defm NAME#Z128 : avx512_packs_rm, avx512_packs_rmb, EVEX_V128; } } multiclass avx512_packs_all_i16_i8 opc, string OpcodeStr, SDNode OpNode> { defm NAME#Z : avx512_packs_rm, EVEX_V512; let Predicates = [HasVLX] in { defm NAME#Z256 : avx512_packs_rm, EVEX_V256; defm NAME#Z128 : avx512_packs_rm, EVEX_V128; } } multiclass avx512_vpmadd opc, string OpcodeStr, SDNode OpNode, AVX512VLVectorVTInfo _Src, AVX512VLVectorVTInfo _Dst> { defm NAME#Z : avx512_packs_rm, EVEX_V512; let Predicates = [HasVLX] in { defm NAME#Z256 : avx512_packs_rm, EVEX_V256; defm NAME#Z128 : avx512_packs_rm, EVEX_V128; } } let Predicates = [HasBWI] in { defm VPACKSSDW : avx512_packs_all_i32_i16<0x6B, "vpackssdw", X86Packss>, PD; defm VPACKUSDW : avx512_packs_all_i32_i16<0x2b, "vpackusdw", X86Packus>, T8PD; defm VPACKSSWB : avx512_packs_all_i16_i8 <0x63, "vpacksswb", X86Packss>, AVX512BIBase, VEX_W; defm VPACKUSWB : avx512_packs_all_i16_i8 <0x67, "vpackuswb", X86Packus>, AVX512BIBase, VEX_W; defm VPMADDUBSW : avx512_vpmadd<0x04, "vpmaddubsw", X86vpmaddubsw, avx512vl_i8_info, avx512vl_i16_info>, AVX512BIBase, T8PD; defm VPMADDWD : avx512_vpmadd<0xF5, "vpmaddwd", X86vpmaddwd, avx512vl_i16_info, avx512vl_i32_info>, AVX512BIBase; } defm VPMAXSB : avx512_binop_rm_vl_b<0x3C, "vpmaxsb", smax, SSE_INTALU_ITINS_P, HasBWI, 1>, T8PD; defm VPMAXSW : avx512_binop_rm_vl_w<0xEE, "vpmaxsw", smax, SSE_INTALU_ITINS_P, HasBWI, 1>; defm VPMAXS : avx512_binop_rm_vl_dq<0x3D, 0x3D, "vpmaxs", smax, SSE_INTALU_ITINS_P, HasAVX512, 1>, T8PD; defm VPMAXUB : avx512_binop_rm_vl_b<0xDE, "vpmaxub", umax, SSE_INTALU_ITINS_P, HasBWI, 1>; defm VPMAXUW : avx512_binop_rm_vl_w<0x3E, "vpmaxuw", umax, SSE_INTALU_ITINS_P, HasBWI, 1>, T8PD; defm VPMAXU : avx512_binop_rm_vl_dq<0x3F, 0x3F, "vpmaxu", umax, SSE_INTALU_ITINS_P, HasAVX512, 1>, T8PD; defm VPMINSB : avx512_binop_rm_vl_b<0x38, "vpminsb", smin, SSE_INTALU_ITINS_P, HasBWI, 1>, T8PD; defm VPMINSW : avx512_binop_rm_vl_w<0xEA, "vpminsw", smin, SSE_INTALU_ITINS_P, HasBWI, 1>; defm VPMINS : avx512_binop_rm_vl_dq<0x39, 0x39, "vpmins", smin, SSE_INTALU_ITINS_P, HasAVX512, 1>, T8PD; defm VPMINUB : avx512_binop_rm_vl_b<0xDA, "vpminub", umin, SSE_INTALU_ITINS_P, HasBWI, 1>; defm VPMINUW : avx512_binop_rm_vl_w<0x3A, "vpminuw", umin, SSE_INTALU_ITINS_P, HasBWI, 1>, T8PD; defm VPMINU : avx512_binop_rm_vl_dq<0x3B, 0x3B, "vpminu", umin, SSE_INTALU_ITINS_P, HasAVX512, 1>, T8PD; //===----------------------------------------------------------------------===// // AVX-512 Logical Instructions //===----------------------------------------------------------------------===// defm VPAND : avx512_binop_rm_vl_dq<0xDB, 0xDB, "vpand", and, SSE_INTALU_ITINS_P, HasAVX512, 1>; defm VPOR : avx512_binop_rm_vl_dq<0xEB, 0xEB, "vpor", or, SSE_INTALU_ITINS_P, HasAVX512, 1>; defm VPXOR : avx512_binop_rm_vl_dq<0xEF, 0xEF, "vpxor", xor, SSE_INTALU_ITINS_P, HasAVX512, 1>; defm VPANDN : avx512_binop_rm_vl_dq<0xDF, 0xDF, "vpandn", X86andnp, SSE_INTALU_ITINS_P, HasAVX512, 0>; //===----------------------------------------------------------------------===// // AVX-512 FP arithmetic //===----------------------------------------------------------------------===// multiclass avx512_fp_scalar opc, string OpcodeStr,X86VectorVTInfo _, SDNode OpNode, SDNode VecNode, OpndItins itins, bit IsCommutable> { defm rr_Int : AVX512_maskable_scalar; defm rm_Int : AVX512_maskable_scalar; let isCodeGenOnly = 1, isCommutable = IsCommutable, Predicates = [HasAVX512] in { def rr : I< opc, MRMSrcReg, (outs _.FRC:$dst), (ins _.FRC:$src1, _.FRC:$src2), OpcodeStr#"\t{$src2, $src1, $dst|$dst, $src1, $src2}", [(set _.FRC:$dst, (OpNode _.FRC:$src1, _.FRC:$src2))], itins.rr>; def rm : I< opc, MRMSrcMem, (outs _.FRC:$dst), (ins _.FRC:$src1, _.ScalarMemOp:$src2), OpcodeStr#"\t{$src2, $src1, $dst|$dst, $src1, $src2}", [(set _.FRC:$dst, (OpNode _.FRC:$src1, (_.ScalarLdFrag addr:$src2)))], itins.rr>; } } multiclass avx512_fp_scalar_round opc, string OpcodeStr,X86VectorVTInfo _, SDNode VecNode, OpndItins itins, bit IsCommutable = 0> { defm rrb : AVX512_maskable_scalar, EVEX_B, EVEX_RC; } multiclass avx512_fp_scalar_sae opc, string OpcodeStr,X86VectorVTInfo _, SDNode VecNode, OpndItins itins, bit IsCommutable> { defm rrb : AVX512_maskable_scalar, EVEX_B; } multiclass avx512_binop_s_round opc, string OpcodeStr, SDNode OpNode, SDNode VecNode, SizeItins itins, bit IsCommutable> { defm SSZ : avx512_fp_scalar, avx512_fp_scalar_round, XS, EVEX_4V, VEX_LIG, EVEX_CD8<32, CD8VT1>; defm SDZ : avx512_fp_scalar, avx512_fp_scalar_round, XD, VEX_W, EVEX_4V, VEX_LIG, EVEX_CD8<64, CD8VT1>; } multiclass avx512_binop_s_sae opc, string OpcodeStr, SDNode OpNode, SDNode VecNode, SizeItins itins, bit IsCommutable> { defm SSZ : avx512_fp_scalar, avx512_fp_scalar_sae, XS, EVEX_4V, VEX_LIG, EVEX_CD8<32, CD8VT1>; defm SDZ : avx512_fp_scalar, avx512_fp_scalar_sae, XD, VEX_W, EVEX_4V, VEX_LIG, EVEX_CD8<64, CD8VT1>; } defm VADD : avx512_binop_s_round<0x58, "vadd", fadd, X86faddRnd, SSE_ALU_ITINS_S, 1>; defm VMUL : avx512_binop_s_round<0x59, "vmul", fmul, X86fmulRnd, SSE_ALU_ITINS_S, 1>; defm VSUB : avx512_binop_s_round<0x5C, "vsub", fsub, X86fsubRnd, SSE_ALU_ITINS_S, 0>; defm VDIV : avx512_binop_s_round<0x5E, "vdiv", fdiv, X86fdivRnd, SSE_ALU_ITINS_S, 0>; defm VMIN : avx512_binop_s_sae <0x5D, "vmin", X86fmin, X86fminRnd, SSE_ALU_ITINS_S, 1>; defm VMAX : avx512_binop_s_sae <0x5F, "vmax", X86fmax, X86fmaxRnd, SSE_ALU_ITINS_S, 1>; multiclass avx512_fp_packed opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _, bit IsCommutable> { defm rr: AVX512_maskable, EVEX_4V; let mayLoad = 1 in { defm rm: AVX512_maskable, EVEX_4V; defm rmb: AVX512_maskable, EVEX_4V, EVEX_B; }//let mayLoad = 1 } multiclass avx512_fp_round_packed opc, string OpcodeStr, SDNode OpNodeRnd, X86VectorVTInfo _> { defm rb: AVX512_maskable, EVEX_4V, EVEX_B, EVEX_RC; } multiclass avx512_fp_sae_packed opc, string OpcodeStr, SDNode OpNodeRnd, X86VectorVTInfo _> { defm rb: AVX512_maskable, EVEX_4V, EVEX_B; } multiclass avx512_fp_binop_p opc, string OpcodeStr, SDNode OpNode, bit IsCommutable = 0> { defm PSZ : avx512_fp_packed, EVEX_V512, PS, EVEX_CD8<32, CD8VF>; defm PDZ : avx512_fp_packed, EVEX_V512, PD, VEX_W, EVEX_CD8<64, CD8VF>; // Define only if AVX512VL feature is present. let Predicates = [HasVLX] in { defm PSZ128 : avx512_fp_packed, EVEX_V128, PS, EVEX_CD8<32, CD8VF>; defm PSZ256 : avx512_fp_packed, EVEX_V256, PS, EVEX_CD8<32, CD8VF>; defm PDZ128 : avx512_fp_packed, EVEX_V128, PD, VEX_W, EVEX_CD8<64, CD8VF>; defm PDZ256 : avx512_fp_packed, EVEX_V256, PD, VEX_W, EVEX_CD8<64, CD8VF>; } } multiclass avx512_fp_binop_p_round opc, string OpcodeStr, SDNode OpNodeRnd> { defm PSZ : avx512_fp_round_packed, EVEX_V512, PS, EVEX_CD8<32, CD8VF>; defm PDZ : avx512_fp_round_packed, EVEX_V512, PD, VEX_W,EVEX_CD8<64, CD8VF>; } multiclass avx512_fp_binop_p_sae opc, string OpcodeStr, SDNode OpNodeRnd> { defm PSZ : avx512_fp_sae_packed, EVEX_V512, PS, EVEX_CD8<32, CD8VF>; defm PDZ : avx512_fp_sae_packed, EVEX_V512, PD, VEX_W,EVEX_CD8<64, CD8VF>; } defm VADD : avx512_fp_binop_p<0x58, "vadd", fadd, 1>, avx512_fp_binop_p_round<0x58, "vadd", X86faddRnd>; defm VMUL : avx512_fp_binop_p<0x59, "vmul", fmul, 1>, avx512_fp_binop_p_round<0x59, "vmul", X86fmulRnd>; defm VSUB : avx512_fp_binop_p<0x5C, "vsub", fsub>, avx512_fp_binop_p_round<0x5C, "vsub", X86fsubRnd>; defm VDIV : avx512_fp_binop_p<0x5E, "vdiv", fdiv>, avx512_fp_binop_p_round<0x5E, "vdiv", X86fdivRnd>; defm VMIN : avx512_fp_binop_p<0x5D, "vmin", X86fmin, 1>, avx512_fp_binop_p_sae<0x5D, "vmin", X86fminRnd>; defm VMAX : avx512_fp_binop_p<0x5F, "vmax", X86fmax, 1>, avx512_fp_binop_p_sae<0x5F, "vmax", X86fmaxRnd>; let Predicates = [HasDQI] in { defm VAND : avx512_fp_binop_p<0x54, "vand", X86fand, 1>; defm VANDN : avx512_fp_binop_p<0x55, "vandn", X86fandn, 0>; defm VOR : avx512_fp_binop_p<0x56, "vor", X86for, 1>; defm VXOR : avx512_fp_binop_p<0x57, "vxor", X86fxor, 1>; } multiclass avx512_fp_scalef_p opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { defm rr: AVX512_maskable, EVEX_4V; let mayLoad = 1 in { defm rm: AVX512_maskable, EVEX_4V; defm rmb: AVX512_maskable, EVEX_4V, EVEX_B; }//let mayLoad = 1 } multiclass avx512_fp_scalef_scalar opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { defm rr: AVX512_maskable_scalar; let mayLoad = 1 in { defm rm: AVX512_maskable_scalar; }//let mayLoad = 1 } multiclass avx512_fp_scalef_all opc, bits<8> opcScaler, string OpcodeStr, SDNode OpNode> { defm PSZ : avx512_fp_scalef_p, avx512_fp_round_packed, EVEX_V512, EVEX_CD8<32, CD8VF>; defm PDZ : avx512_fp_scalef_p, avx512_fp_round_packed, EVEX_V512, VEX_W, EVEX_CD8<64, CD8VF>; defm SSZ128 : avx512_fp_scalef_scalar, avx512_fp_scalar_round, EVEX_4V,EVEX_CD8<32, CD8VT1>; defm SDZ128 : avx512_fp_scalef_scalar, avx512_fp_scalar_round, EVEX_4V, EVEX_CD8<64, CD8VT1>, VEX_W; // Define only if AVX512VL feature is present. let Predicates = [HasVLX] in { defm PSZ128 : avx512_fp_scalef_p, EVEX_V128, EVEX_CD8<32, CD8VF>; defm PSZ256 : avx512_fp_scalef_p, EVEX_V256, EVEX_CD8<32, CD8VF>; defm PDZ128 : avx512_fp_scalef_p, EVEX_V128, VEX_W, EVEX_CD8<64, CD8VF>; defm PDZ256 : avx512_fp_scalef_p, EVEX_V256, VEX_W, EVEX_CD8<64, CD8VF>; } } defm VSCALEF : avx512_fp_scalef_all<0x2C, 0x2D, "vscalef", X86scalef>, T8PD; //===----------------------------------------------------------------------===// // AVX-512 VPTESTM instructions //===----------------------------------------------------------------------===// multiclass avx512_vptest opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { defm rr : AVX512_maskable_cmp, EVEX_4V; let mayLoad = 1 in defm rm : AVX512_maskable_cmp, EVEX_4V, EVEX_CD8<_.EltSize, CD8VF>; } multiclass avx512_vptest_mb opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { let mayLoad = 1 in defm rmb : AVX512_maskable_cmp, EVEX_B, EVEX_4V, EVEX_CD8<_.EltSize, CD8VF>; } multiclass avx512_vptest_dq_sizes opc, string OpcodeStr, SDNode OpNode, AVX512VLVectorVTInfo _> { let Predicates = [HasAVX512] in defm Z : avx512_vptest, avx512_vptest_mb, EVEX_V512; let Predicates = [HasAVX512, HasVLX] in { defm Z256 : avx512_vptest, avx512_vptest_mb, EVEX_V256; defm Z128 : avx512_vptest, avx512_vptest_mb, EVEX_V128; } } multiclass avx512_vptest_dq opc, string OpcodeStr, SDNode OpNode> { defm D : avx512_vptest_dq_sizes; defm Q : avx512_vptest_dq_sizes, VEX_W; } multiclass avx512_vptest_wb opc, string OpcodeStr, SDNode OpNode> { let Predicates = [HasBWI] in { defm WZ: avx512_vptest, EVEX_V512, VEX_W; defm BZ: avx512_vptest, EVEX_V512; } let Predicates = [HasVLX, HasBWI] in { defm WZ256: avx512_vptest, EVEX_V256, VEX_W; defm WZ128: avx512_vptest, EVEX_V128, VEX_W; defm BZ256: avx512_vptest, EVEX_V256; defm BZ128: avx512_vptest, EVEX_V128; } } multiclass avx512_vptest_all_forms opc_wb, bits<8> opc_dq, string OpcodeStr, SDNode OpNode> : avx512_vptest_wb , avx512_vptest_dq; defm VPTESTM : avx512_vptest_all_forms<0x26, 0x27, "vptestm", X86testm>, T8PD; defm VPTESTNM : avx512_vptest_all_forms<0x26, 0x27, "vptestnm", X86testnm>, T8XS; def : Pat <(i16 (int_x86_avx512_mask_ptestm_d_512 (v16i32 VR512:$src1), (v16i32 VR512:$src2), (i16 -1))), (COPY_TO_REGCLASS (VPTESTMDZrr VR512:$src1, VR512:$src2), GR16)>; def : Pat <(i8 (int_x86_avx512_mask_ptestm_q_512 (v8i64 VR512:$src1), (v8i64 VR512:$src2), (i8 -1))), (COPY_TO_REGCLASS (VPTESTMQZrr VR512:$src1, VR512:$src2), GR8)>; //===----------------------------------------------------------------------===// // AVX-512 Shift instructions //===----------------------------------------------------------------------===// multiclass avx512_shift_rmi opc, Format ImmFormR, Format ImmFormM, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { defm ri : AVX512_maskable; let mayLoad = 1 in defm mi : AVX512_maskable; } multiclass avx512_shift_rmbi opc, Format ImmFormM, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { let mayLoad = 1 in defm mbi : AVX512_maskable, EVEX_B; } multiclass avx512_shift_rrm opc, string OpcodeStr, SDNode OpNode, ValueType SrcVT, PatFrag bc_frag, X86VectorVTInfo _> { // src2 is always 128-bit defm rr : AVX512_maskable, AVX512BIBase, EVEX_4V; defm rm : AVX512_maskable, AVX512BIBase, EVEX_4V; } multiclass avx512_shift_sizes opc, string OpcodeStr, SDNode OpNode, ValueType SrcVT, PatFrag bc_frag, AVX512VLVectorVTInfo VTInfo, Predicate prd> { let Predicates = [prd] in defm Z : avx512_shift_rrm, EVEX_V512, EVEX_CD8 ; let Predicates = [prd, HasVLX] in { defm Z256 : avx512_shift_rrm, EVEX_V256, EVEX_CD8; defm Z128 : avx512_shift_rrm, EVEX_V128, EVEX_CD8; } } multiclass avx512_shift_types opcd, bits<8> opcq, bits<8> opcw, string OpcodeStr, SDNode OpNode> { defm D : avx512_shift_sizes; defm Q : avx512_shift_sizes, VEX_W; defm W : avx512_shift_sizes; } multiclass avx512_shift_rmi_sizes opc, Format ImmFormR, Format ImmFormM, string OpcodeStr, SDNode OpNode, AVX512VLVectorVTInfo VTInfo> { let Predicates = [HasAVX512] in defm Z: avx512_shift_rmi, avx512_shift_rmbi, EVEX_V512; let Predicates = [HasAVX512, HasVLX] in { defm Z256: avx512_shift_rmi, avx512_shift_rmbi, EVEX_V256; defm Z128: avx512_shift_rmi, avx512_shift_rmbi, EVEX_V128; } } multiclass avx512_shift_rmi_w opcw, Format ImmFormR, Format ImmFormM, string OpcodeStr, SDNode OpNode> { let Predicates = [HasBWI] in defm WZ: avx512_shift_rmi, EVEX_V512; let Predicates = [HasVLX, HasBWI] in { defm WZ256: avx512_shift_rmi, EVEX_V256; defm WZ128: avx512_shift_rmi, EVEX_V128; } } multiclass avx512_shift_rmi_dq opcd, bits<8> opcq, Format ImmFormR, Format ImmFormM, string OpcodeStr, SDNode OpNode> { defm D: avx512_shift_rmi_sizes, EVEX_CD8<32, CD8VF>; defm Q: avx512_shift_rmi_sizes, EVEX_CD8<64, CD8VF>, VEX_W; } defm VPSRL : avx512_shift_rmi_dq<0x72, 0x73, MRM2r, MRM2m, "vpsrl", X86vsrli>, avx512_shift_rmi_w<0x71, MRM2r, MRM2m, "vpsrlw", X86vsrli>, AVX512BIi8Base, EVEX_4V; defm VPSLL : avx512_shift_rmi_dq<0x72, 0x73, MRM6r, MRM6m, "vpsll", X86vshli>, avx512_shift_rmi_w<0x71, MRM6r, MRM6m, "vpsllw", X86vshli>, AVX512BIi8Base, EVEX_4V; defm VPSRA : avx512_shift_rmi_dq<0x72, 0x72, MRM4r, MRM4m, "vpsra", X86vsrai>, avx512_shift_rmi_w<0x71, MRM4r, MRM4m, "vpsraw", X86vsrai>, AVX512BIi8Base, EVEX_4V; defm VPROR : avx512_shift_rmi_dq<0x72, 0x72, MRM0r, MRM0m, "vpror", X86vrotri>, AVX512BIi8Base, EVEX_4V; defm VPROL : avx512_shift_rmi_dq<0x72, 0x72, MRM1r, MRM1m, "vprol", X86vrotli>, AVX512BIi8Base, EVEX_4V; defm VPSLL : avx512_shift_types<0xF2, 0xF3, 0xF1, "vpsll", X86vshl>; defm VPSRA : avx512_shift_types<0xE2, 0xE2, 0xE1, "vpsra", X86vsra>; defm VPSRL : avx512_shift_types<0xD2, 0xD3, 0xD1, "vpsrl", X86vsrl>; //===-------------------------------------------------------------------===// // Variable Bit Shifts //===-------------------------------------------------------------------===// multiclass avx512_var_shift opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { defm rr : AVX512_maskable, AVX5128IBase, EVEX_4V; let mayLoad = 1 in defm rm : AVX512_maskable, AVX5128IBase, EVEX_4V, EVEX_CD8<_.EltSize, CD8VF>; } multiclass avx512_var_shift_mb opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { let mayLoad = 1 in defm rmb : AVX512_maskable, AVX5128IBase, EVEX_B, EVEX_4V, EVEX_CD8<_.EltSize, CD8VF>; } multiclass avx512_var_shift_sizes opc, string OpcodeStr, SDNode OpNode, AVX512VLVectorVTInfo _> { let Predicates = [HasAVX512] in defm Z : avx512_var_shift, avx512_var_shift_mb, EVEX_V512; let Predicates = [HasAVX512, HasVLX] in { defm Z256 : avx512_var_shift, avx512_var_shift_mb, EVEX_V256; defm Z128 : avx512_var_shift, avx512_var_shift_mb, EVEX_V128; } } multiclass avx512_var_shift_types opc, string OpcodeStr, SDNode OpNode> { defm D : avx512_var_shift_sizes; defm Q : avx512_var_shift_sizes, VEX_W; } // Use 512bit version to implement 128/256 bit in case NoVLX. multiclass avx512_var_shift_w_lowering { let Predicates = [HasBWI, NoVLX] in { def : Pat<(_.info256.VT (OpNode (_.info256.VT _.info256.RC:$src1), (_.info256.VT _.info256.RC:$src2))), (EXTRACT_SUBREG (!cast(NAME#"WZrr") (INSERT_SUBREG (_.info512.VT (IMPLICIT_DEF)), VR256X:$src1, sub_ymm), (INSERT_SUBREG (_.info512.VT (IMPLICIT_DEF)), VR256X:$src2, sub_ymm)), sub_ymm)>; def : Pat<(_.info128.VT (OpNode (_.info128.VT _.info128.RC:$src1), (_.info128.VT _.info128.RC:$src2))), (EXTRACT_SUBREG (!cast(NAME#"WZrr") (INSERT_SUBREG (_.info512.VT (IMPLICIT_DEF)), VR128X:$src1, sub_xmm), (INSERT_SUBREG (_.info512.VT (IMPLICIT_DEF)), VR128X:$src2, sub_xmm)), sub_xmm)>; } } multiclass avx512_var_shift_w opc, string OpcodeStr, SDNode OpNode> { let Predicates = [HasBWI] in defm WZ: avx512_var_shift, EVEX_V512, VEX_W; let Predicates = [HasVLX, HasBWI] in { defm WZ256: avx512_var_shift, EVEX_V256, VEX_W; defm WZ128: avx512_var_shift, EVEX_V128, VEX_W; } } defm VPSLLV : avx512_var_shift_types<0x47, "vpsllv", shl>, avx512_var_shift_w<0x12, "vpsllvw", shl>, avx512_var_shift_w_lowering; defm VPSRAV : avx512_var_shift_types<0x46, "vpsrav", sra>, avx512_var_shift_w<0x11, "vpsravw", sra>, avx512_var_shift_w_lowering; defm VPSRLV : avx512_var_shift_types<0x45, "vpsrlv", srl>, avx512_var_shift_w<0x10, "vpsrlvw", srl>, avx512_var_shift_w_lowering; defm VPRORV : avx512_var_shift_types<0x14, "vprorv", rotr>; defm VPROLV : avx512_var_shift_types<0x15, "vprolv", rotl>; //===-------------------------------------------------------------------===// // 1-src variable permutation VPERMW/D/Q //===-------------------------------------------------------------------===// multiclass avx512_vperm_dq_sizes opc, string OpcodeStr, SDNode OpNode, AVX512VLVectorVTInfo _> { let Predicates = [HasAVX512] in defm Z : avx512_var_shift, avx512_var_shift_mb, EVEX_V512; let Predicates = [HasAVX512, HasVLX] in defm Z256 : avx512_var_shift, avx512_var_shift_mb, EVEX_V256; } multiclass avx512_vpermi_dq_sizes opc, Format ImmFormR, Format ImmFormM, string OpcodeStr, SDNode OpNode, AVX512VLVectorVTInfo VTInfo> { let Predicates = [HasAVX512] in defm Z: avx512_shift_rmi, avx512_shift_rmbi, EVEX_V512; let Predicates = [HasAVX512, HasVLX] in defm Z256: avx512_shift_rmi, avx512_shift_rmbi, EVEX_V256; } defm VPERM : avx512_var_shift_w<0x8D, "vpermw", X86VPermv>; defm VPERMD : avx512_vperm_dq_sizes<0x36, "vpermd", X86VPermv, avx512vl_i32_info>; defm VPERMQ : avx512_vperm_dq_sizes<0x36, "vpermq", X86VPermv, avx512vl_i64_info>, VEX_W; defm VPERMPS : avx512_vperm_dq_sizes<0x16, "vpermps", X86VPermv, avx512vl_f32_info>; defm VPERMPD : avx512_vperm_dq_sizes<0x16, "vpermpd", X86VPermv, avx512vl_f64_info>, VEX_W; defm VPERMQ : avx512_vpermi_dq_sizes<0x00, MRMSrcReg, MRMSrcMem, "vpermq", X86VPermi, avx512vl_i64_info>, EVEX, AVX512AIi8Base, EVEX_CD8<64, CD8VF>, VEX_W; defm VPERMPD : avx512_vpermi_dq_sizes<0x01, MRMSrcReg, MRMSrcMem, "vpermpd", X86VPermi, avx512vl_f64_info>, EVEX, AVX512AIi8Base, EVEX_CD8<64, CD8VF>, VEX_W; //===----------------------------------------------------------------------===// // AVX-512 - VPERMIL //===----------------------------------------------------------------------===// multiclass avx512_permil_vec OpcVar, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _, X86VectorVTInfo Ctrl> { defm rr: AVX512_maskable, T8PD, EVEX_4V; let mayLoad = 1 in { defm rm: AVX512_maskable, T8PD, EVEX_4V, EVEX_CD8<_.EltSize, CD8VF>; defm rmb: AVX512_maskable, T8PD, EVEX_4V, EVEX_B, EVEX_CD8<_.EltSize, CD8VF>; }//let mayLoad = 1 } multiclass avx512_permil_vec_common OpcVar, AVX512VLVectorVTInfo _, AVX512VLVectorVTInfo Ctrl>{ let Predicates = [HasAVX512] in { defm Z : avx512_permil_vec, EVEX_V512; } let Predicates = [HasAVX512, HasVLX] in { defm Z128 : avx512_permil_vec, EVEX_V128; defm Z256 : avx512_permil_vec, EVEX_V256; } } multiclass avx512_permil OpcImm, bits<8> OpcVar, AVX512VLVectorVTInfo _, AVX512VLVectorVTInfo Ctrl>{ defm NAME: avx512_permil_vec_common; defm NAME: avx512_shift_rmi_sizes, EVEX, AVX512AIi8Base, EVEX_CD8<_.info128.EltSize, CD8VF>; } defm VPERMILPS : avx512_permil<"vpermilps", 0x04, 0x0C, avx512vl_f32_info, avx512vl_i32_info>; defm VPERMILPD : avx512_permil<"vpermilpd", 0x05, 0x0D, avx512vl_f64_info, avx512vl_i64_info>, VEX_W; //===----------------------------------------------------------------------===// // AVX-512 - VPSHUFD, VPSHUFLW, VPSHUFHW //===----------------------------------------------------------------------===// defm VPSHUFD : avx512_shift_rmi_sizes<0x70, MRMSrcReg, MRMSrcMem, "vpshufd", X86PShufd, avx512vl_i32_info>, EVEX, AVX512BIi8Base, EVEX_CD8<32, CD8VF>; defm VPSHUFH : avx512_shift_rmi_w<0x70, MRMSrcReg, MRMSrcMem, "vpshufhw", X86PShufhw>, EVEX, AVX512XSIi8Base; defm VPSHUFL : avx512_shift_rmi_w<0x70, MRMSrcReg, MRMSrcMem, "vpshuflw", X86PShuflw>, EVEX, AVX512XDIi8Base; multiclass avx512_pshufb_sizes opc, string OpcodeStr, SDNode OpNode> { let Predicates = [HasBWI] in defm Z: avx512_var_shift, EVEX_V512; let Predicates = [HasVLX, HasBWI] in { defm Z256: avx512_var_shift, EVEX_V256; defm Z128: avx512_var_shift, EVEX_V128; } } defm VPSHUFB: avx512_pshufb_sizes<0x00, "vpshufb", X86pshufb>; //===----------------------------------------------------------------------===// // Move Low to High and High to Low packed FP Instructions //===----------------------------------------------------------------------===// def VMOVLHPSZrr : AVX512PSI<0x16, MRMSrcReg, (outs VR128X:$dst), (ins VR128X:$src1, VR128X:$src2), "vmovlhps\t{$src2, $src1, $dst|$dst, $src1, $src2}", [(set VR128X:$dst, (v4f32 (X86Movlhps VR128X:$src1, VR128X:$src2)))], IIC_SSE_MOV_LH>, EVEX_4V; def VMOVHLPSZrr : AVX512PSI<0x12, MRMSrcReg, (outs VR128X:$dst), (ins VR128X:$src1, VR128X:$src2), "vmovhlps\t{$src2, $src1, $dst|$dst, $src1, $src2}", [(set VR128X:$dst, (v4f32 (X86Movhlps VR128X:$src1, VR128X:$src2)))], IIC_SSE_MOV_LH>, EVEX_4V; let Predicates = [HasAVX512] in { // MOVLHPS patterns def : Pat<(v4i32 (X86Movlhps VR128X:$src1, VR128X:$src2)), (VMOVLHPSZrr VR128X:$src1, VR128X:$src2)>; def : Pat<(v2i64 (X86Movlhps VR128X:$src1, VR128X:$src2)), (VMOVLHPSZrr (v2i64 VR128X:$src1), VR128X:$src2)>; // MOVHLPS patterns def : Pat<(v4i32 (X86Movhlps VR128X:$src1, VR128X:$src2)), (VMOVHLPSZrr VR128X:$src1, VR128X:$src2)>; } //===----------------------------------------------------------------------===// // VMOVHPS/PD VMOVLPS Instructions // All patterns was taken from SSS implementation. //===----------------------------------------------------------------------===// multiclass avx512_mov_hilo_packed opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { let mayLoad = 1 in def rm : AVX512, EVEX_4V; } defm VMOVHPSZ128 : avx512_mov_hilo_packed<0x16, "vmovhps", X86Movlhps, v4f32x_info>, EVEX_CD8<32, CD8VT2>, PS; defm VMOVHPDZ128 : avx512_mov_hilo_packed<0x16, "vmovhpd", X86Movlhpd, v2f64x_info>, EVEX_CD8<64, CD8VT1>, PD, VEX_W; defm VMOVLPSZ128 : avx512_mov_hilo_packed<0x12, "vmovlps", X86Movlps, v4f32x_info>, EVEX_CD8<32, CD8VT2>, PS; defm VMOVLPDZ128 : avx512_mov_hilo_packed<0x12, "vmovlpd", X86Movlpd, v2f64x_info>, EVEX_CD8<64, CD8VT1>, PD, VEX_W; let Predicates = [HasAVX512] in { // VMOVHPS patterns def : Pat<(X86Movlhps VR128X:$src1, (bc_v4f32 (v2i64 (scalar_to_vector (loadi64 addr:$src2))))), (VMOVHPSZ128rm VR128X:$src1, addr:$src2)>; def : Pat<(X86Movlhps VR128X:$src1, (bc_v4i32 (v2i64 (X86vzload addr:$src2)))), (VMOVHPSZ128rm VR128X:$src1, addr:$src2)>; // VMOVHPD patterns def : Pat<(v2f64 (X86Unpckl VR128X:$src1, (scalar_to_vector (loadf64 addr:$src2)))), (VMOVHPDZ128rm VR128X:$src1, addr:$src2)>; def : Pat<(v2f64 (X86Unpckl VR128X:$src1, (bc_v2f64 (v2i64 (scalar_to_vector (loadi64 addr:$src2)))))), (VMOVHPDZ128rm VR128X:$src1, addr:$src2)>; // VMOVLPS patterns def : Pat<(v4f32 (X86Movlps VR128X:$src1, (load addr:$src2))), (VMOVLPSZ128rm VR128X:$src1, addr:$src2)>; def : Pat<(v4i32 (X86Movlps VR128X:$src1, (load addr:$src2))), (VMOVLPSZ128rm VR128X:$src1, addr:$src2)>; // VMOVLPD patterns def : Pat<(v2f64 (X86Movlpd VR128X:$src1, (load addr:$src2))), (VMOVLPDZ128rm VR128X:$src1, addr:$src2)>; def : Pat<(v2i64 (X86Movlpd VR128X:$src1, (load addr:$src2))), (VMOVLPDZ128rm VR128X:$src1, addr:$src2)>; def : Pat<(v2f64 (X86Movsd VR128X:$src1, (v2f64 (scalar_to_vector (loadf64 addr:$src2))))), (VMOVLPDZ128rm VR128X:$src1, addr:$src2)>; } let mayStore = 1 in { def VMOVHPSZ128mr : AVX512PSI<0x17, MRMDestMem, (outs), (ins f64mem:$dst, VR128X:$src), "vmovhps\t{$src, $dst|$dst, $src}", [(store (f64 (vector_extract (X86Unpckh (bc_v2f64 (v4f32 VR128X:$src)), (bc_v2f64 (v4f32 VR128X:$src))), (iPTR 0))), addr:$dst)], IIC_SSE_MOV_LH>, EVEX, EVEX_CD8<32, CD8VT2>; def VMOVHPDZ128mr : AVX512PDI<0x17, MRMDestMem, (outs), (ins f64mem:$dst, VR128X:$src), "vmovhpd\t{$src, $dst|$dst, $src}", [(store (f64 (vector_extract (v2f64 (X86Unpckh VR128X:$src, VR128X:$src)), (iPTR 0))), addr:$dst)], IIC_SSE_MOV_LH>, EVEX, EVEX_CD8<64, CD8VT1>, VEX_W; def VMOVLPSZ128mr : AVX512PSI<0x13, MRMDestMem, (outs), (ins f64mem:$dst, VR128X:$src), "vmovlps\t{$src, $dst|$dst, $src}", [(store (f64 (vector_extract (bc_v2f64 (v4f32 VR128X:$src)), (iPTR 0))), addr:$dst)], IIC_SSE_MOV_LH>, EVEX, EVEX_CD8<32, CD8VT2>; def VMOVLPDZ128mr : AVX512PDI<0x13, MRMDestMem, (outs), (ins f64mem:$dst, VR128X:$src), "vmovlpd\t{$src, $dst|$dst, $src}", [(store (f64 (vector_extract (v2f64 VR128X:$src), (iPTR 0))), addr:$dst)], IIC_SSE_MOV_LH>, EVEX, EVEX_CD8<64, CD8VT1>, VEX_W; } let Predicates = [HasAVX512] in { // VMOVHPD patterns def : Pat<(store (f64 (vector_extract (v2f64 (X86VPermilpi VR128X:$src, (i8 1))), (iPTR 0))), addr:$dst), (VMOVHPDZ128mr addr:$dst, VR128X:$src)>; // VMOVLPS patterns def : Pat<(store (v4f32 (X86Movlps (load addr:$src1), VR128X:$src2)), addr:$src1), (VMOVLPSZ128mr addr:$src1, VR128X:$src2)>; def : Pat<(store (v4i32 (X86Movlps (bc_v4i32 (loadv2i64 addr:$src1)), VR128X:$src2)), addr:$src1), (VMOVLPSZ128mr addr:$src1, VR128X:$src2)>; // VMOVLPD patterns def : Pat<(store (v2f64 (X86Movlpd (load addr:$src1), VR128X:$src2)), addr:$src1), (VMOVLPDZ128mr addr:$src1, VR128X:$src2)>; def : Pat<(store (v2i64 (X86Movlpd (load addr:$src1), VR128X:$src2)), addr:$src1), (VMOVLPDZ128mr addr:$src1, VR128X:$src2)>; } //===----------------------------------------------------------------------===// // FMA - Fused Multiply Operations // let Constraints = "$src1 = $dst" in { multiclass avx512_fma3p_213_rm opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { defm r: AVX512_maskable_3src, AVX512FMA3Base; let mayLoad = 1 in { defm m: AVX512_maskable_3src, AVX512FMA3Base; defm mb: AVX512_maskable_3src, AVX512FMA3Base, EVEX_B; } } multiclass avx512_fma3_213_round opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { defm rb: AVX512_maskable_3src, AVX512FMA3Base, EVEX_B, EVEX_RC; } } // Constraints = "$src1 = $dst" multiclass avx512_fma3p_213_common opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd, AVX512VLVectorVTInfo _> { let Predicates = [HasAVX512] in { defm Z : avx512_fma3p_213_rm, avx512_fma3_213_round, EVEX_V512, EVEX_CD8<_.info512.EltSize, CD8VF>; } let Predicates = [HasVLX, HasAVX512] in { defm Z256 : avx512_fma3p_213_rm, EVEX_V256, EVEX_CD8<_.info256.EltSize, CD8VF>; defm Z128 : avx512_fma3p_213_rm, EVEX_V128, EVEX_CD8<_.info128.EltSize, CD8VF>; } } multiclass avx512_fma3p_213_f opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd > { defm PS : avx512_fma3p_213_common; defm PD : avx512_fma3p_213_common, VEX_W; } defm VFMADD213 : avx512_fma3p_213_f<0xA8, "vfmadd213", X86Fmadd, X86FmaddRnd>; defm VFMSUB213 : avx512_fma3p_213_f<0xAA, "vfmsub213", X86Fmsub, X86FmsubRnd>; defm VFMADDSUB213 : avx512_fma3p_213_f<0xA6, "vfmaddsub213", X86Fmaddsub, X86FmaddsubRnd>; defm VFMSUBADD213 : avx512_fma3p_213_f<0xA7, "vfmsubadd213", X86Fmsubadd, X86FmsubaddRnd>; defm VFNMADD213 : avx512_fma3p_213_f<0xAC, "vfnmadd213", X86Fnmadd, X86FnmaddRnd>; defm VFNMSUB213 : avx512_fma3p_213_f<0xAE, "vfnmsub213", X86Fnmsub, X86FnmsubRnd>; let Constraints = "$src1 = $dst" in { multiclass avx512_fma3p_231_rm opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { defm r: AVX512_maskable_3src, AVX512FMA3Base; let mayLoad = 1 in { defm m: AVX512_maskable_3src, AVX512FMA3Base; defm mb: AVX512_maskable_3src, AVX512FMA3Base, EVEX_B; } } multiclass avx512_fma3_231_round opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { defm rb: AVX512_maskable_3src, AVX512FMA3Base, EVEX_B, EVEX_RC; } } // Constraints = "$src1 = $dst" multiclass avx512_fma3p_231_common opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd, AVX512VLVectorVTInfo _> { let Predicates = [HasAVX512] in { defm Z : avx512_fma3p_231_rm, avx512_fma3_231_round, EVEX_V512, EVEX_CD8<_.info512.EltSize, CD8VF>; } let Predicates = [HasVLX, HasAVX512] in { defm Z256 : avx512_fma3p_231_rm, EVEX_V256, EVEX_CD8<_.info256.EltSize, CD8VF>; defm Z128 : avx512_fma3p_231_rm, EVEX_V128, EVEX_CD8<_.info128.EltSize, CD8VF>; } } multiclass avx512_fma3p_231_f opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd > { defm PS : avx512_fma3p_231_common; defm PD : avx512_fma3p_231_common, VEX_W; } defm VFMADD231 : avx512_fma3p_231_f<0xB8, "vfmadd231", X86Fmadd, X86FmaddRnd>; defm VFMSUB231 : avx512_fma3p_231_f<0xBA, "vfmsub231", X86Fmsub, X86FmsubRnd>; defm VFMADDSUB231 : avx512_fma3p_231_f<0xB6, "vfmaddsub231", X86Fmaddsub, X86FmaddsubRnd>; defm VFMSUBADD231 : avx512_fma3p_231_f<0xB7, "vfmsubadd231", X86Fmsubadd, X86FmsubaddRnd>; defm VFNMADD231 : avx512_fma3p_231_f<0xBC, "vfnmadd231", X86Fnmadd, X86FnmaddRnd>; defm VFNMSUB231 : avx512_fma3p_231_f<0xBE, "vfnmsub231", X86Fnmsub, X86FnmsubRnd>; let Constraints = "$src1 = $dst" in { multiclass avx512_fma3p_132_rm opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { defm r: AVX512_maskable_3src, AVX512FMA3Base; let mayLoad = 1 in { defm m: AVX512_maskable_3src, AVX512FMA3Base; defm mb: AVX512_maskable_3src, AVX512FMA3Base, EVEX_B; } } multiclass avx512_fma3_132_round opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { defm rb: AVX512_maskable_3src, AVX512FMA3Base, EVEX_B, EVEX_RC; } } // Constraints = "$src1 = $dst" multiclass avx512_fma3p_132_common opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd, AVX512VLVectorVTInfo _> { let Predicates = [HasAVX512] in { defm Z : avx512_fma3p_132_rm, avx512_fma3_132_round, EVEX_V512, EVEX_CD8<_.info512.EltSize, CD8VF>; } let Predicates = [HasVLX, HasAVX512] in { defm Z256 : avx512_fma3p_132_rm, EVEX_V256, EVEX_CD8<_.info256.EltSize, CD8VF>; defm Z128 : avx512_fma3p_132_rm, EVEX_V128, EVEX_CD8<_.info128.EltSize, CD8VF>; } } multiclass avx512_fma3p_132_f opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd > { defm PS : avx512_fma3p_132_common; defm PD : avx512_fma3p_132_common, VEX_W; } defm VFMADD132 : avx512_fma3p_132_f<0x98, "vfmadd132", X86Fmadd, X86FmaddRnd>; defm VFMSUB132 : avx512_fma3p_132_f<0x9A, "vfmsub132", X86Fmsub, X86FmsubRnd>; defm VFMADDSUB132 : avx512_fma3p_132_f<0x96, "vfmaddsub132", X86Fmaddsub, X86FmaddsubRnd>; defm VFMSUBADD132 : avx512_fma3p_132_f<0x97, "vfmsubadd132", X86Fmsubadd, X86FmsubaddRnd>; defm VFNMADD132 : avx512_fma3p_132_f<0x9C, "vfnmadd132", X86Fnmadd, X86FnmaddRnd>; defm VFNMSUB132 : avx512_fma3p_132_f<0x9E, "vfnmsub132", X86Fnmsub, X86FnmsubRnd>; // Scalar FMA let Constraints = "$src1 = $dst" in { multiclass avx512_fma3s_common opc, string OpcodeStr, X86VectorVTInfo _, dag RHS_VEC_r, dag RHS_VEC_m, dag RHS_VEC_rb, dag RHS_r, dag RHS_m > { defm r_Int: AVX512_maskable_3src_scalar, AVX512FMA3Base; let mayLoad = 1 in defm m_Int: AVX512_maskable_3src_scalar, AVX512FMA3Base; defm rb_Int: AVX512_maskable_3src_scalar, AVX512FMA3Base, EVEX_B, EVEX_RC; let isCodeGenOnly = 1 in { def r : AVX512FMA3; let mayLoad = 1 in def m : AVX512FMA3; }// isCodeGenOnly = 1 } }// Constraints = "$src1 = $dst" multiclass avx512_fma3s_all opc213, bits<8> opc231, bits<8> opc132, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd, X86VectorVTInfo _ , string SUFF> { defm NAME#213#SUFF: avx512_fma3s_common; defm NAME#231#SUFF: avx512_fma3s_common; defm NAME#132#SUFF: avx512_fma3s_common; } multiclass avx512_fma3s opc213, bits<8> opc231, bits<8> opc132, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd>{ let Predicates = [HasAVX512] in { defm NAME : avx512_fma3s_all, EVEX_CD8<32, CD8VT1>, VEX_LIG; defm NAME : avx512_fma3s_all, EVEX_CD8<64, CD8VT1>, VEX_LIG, VEX_W; } } defm VFMADD : avx512_fma3s<0xA9, 0xB9, 0x99, "vfmadd", X86Fmadd, X86FmaddRnd>; defm VFMSUB : avx512_fma3s<0xAB, 0xBB, 0x9B, "vfmsub", X86Fmsub, X86FmsubRnd>; defm VFNMADD : avx512_fma3s<0xAD, 0xBD, 0x9D, "vfnmadd", X86Fnmadd, X86FnmaddRnd>; defm VFNMSUB : avx512_fma3s<0xAF, 0xBF, 0x9F, "vfnmsub", X86Fnmsub, X86FnmsubRnd>; //===----------------------------------------------------------------------===// // AVX-512 Scalar convert from sign integer to float/double //===----------------------------------------------------------------------===// multiclass avx512_vcvtsi opc, SDNode OpNode, RegisterClass SrcRC, X86VectorVTInfo DstVT, X86MemOperand x86memop, PatFrag ld_frag, string asm> { let hasSideEffects = 0 in { def rr : SI, EVEX_4V; let mayLoad = 1 in def rm : SI, EVEX_4V; } // hasSideEffects = 0 let isCodeGenOnly = 1 in { def rr_Int : SI, EVEX_4V; def rm_Int : SI, EVEX_4V; }//isCodeGenOnly = 1 } multiclass avx512_vcvtsi_round opc, SDNode OpNode, RegisterClass SrcRC, X86VectorVTInfo DstVT, string asm> { def rrb_Int : SI, EVEX_4V, EVEX_B, EVEX_RC; } multiclass avx512_vcvtsi_common opc, SDNode OpNode, RegisterClass SrcRC, X86VectorVTInfo DstVT, X86MemOperand x86memop, PatFrag ld_frag, string asm> { defm NAME : avx512_vcvtsi_round, avx512_vcvtsi, VEX_LIG; } let Predicates = [HasAVX512] in { defm VCVTSI2SSZ : avx512_vcvtsi_common<0x2A, X86SintToFpRnd, GR32, v4f32x_info, i32mem, loadi32, "cvtsi2ss{l}">, XS, EVEX_CD8<32, CD8VT1>; defm VCVTSI642SSZ: avx512_vcvtsi_common<0x2A, X86SintToFpRnd, GR64, v4f32x_info, i64mem, loadi64, "cvtsi2ss{q}">, XS, VEX_W, EVEX_CD8<64, CD8VT1>; defm VCVTSI2SDZ : avx512_vcvtsi_common<0x2A, X86SintToFpRnd, GR32, v2f64x_info, i32mem, loadi32, "cvtsi2sd{l}">, XD, EVEX_CD8<32, CD8VT1>; defm VCVTSI642SDZ: avx512_vcvtsi_common<0x2A, X86SintToFpRnd, GR64, v2f64x_info, i64mem, loadi64, "cvtsi2sd{q}">, XD, VEX_W, EVEX_CD8<64, CD8VT1>; def : Pat<(f32 (sint_to_fp (loadi32 addr:$src))), (VCVTSI2SSZrm (f32 (IMPLICIT_DEF)), addr:$src)>; def : Pat<(f32 (sint_to_fp (loadi64 addr:$src))), (VCVTSI642SSZrm (f32 (IMPLICIT_DEF)), addr:$src)>; def : Pat<(f64 (sint_to_fp (loadi32 addr:$src))), (VCVTSI2SDZrm (f64 (IMPLICIT_DEF)), addr:$src)>; def : Pat<(f64 (sint_to_fp (loadi64 addr:$src))), (VCVTSI642SDZrm (f64 (IMPLICIT_DEF)), addr:$src)>; def : Pat<(f32 (sint_to_fp GR32:$src)), (VCVTSI2SSZrr (f32 (IMPLICIT_DEF)), GR32:$src)>; def : Pat<(f32 (sint_to_fp GR64:$src)), (VCVTSI642SSZrr (f32 (IMPLICIT_DEF)), GR64:$src)>; def : Pat<(f64 (sint_to_fp GR32:$src)), (VCVTSI2SDZrr (f64 (IMPLICIT_DEF)), GR32:$src)>; def : Pat<(f64 (sint_to_fp GR64:$src)), (VCVTSI642SDZrr (f64 (IMPLICIT_DEF)), GR64:$src)>; defm VCVTUSI2SSZ : avx512_vcvtsi_common<0x7B, X86UintToFpRnd, GR32, v4f32x_info, i32mem, loadi32, "cvtusi2ss{l}">, XS, EVEX_CD8<32, CD8VT1>; defm VCVTUSI642SSZ : avx512_vcvtsi_common<0x7B, X86UintToFpRnd, GR64, v4f32x_info, i64mem, loadi64, "cvtusi2ss{q}">, XS, VEX_W, EVEX_CD8<64, CD8VT1>; defm VCVTUSI2SDZ : avx512_vcvtsi<0x7B, X86UintToFpRnd, GR32, v2f64x_info, i32mem, loadi32, "cvtusi2sd{l}">, XD, VEX_LIG, EVEX_CD8<32, CD8VT1>; defm VCVTUSI642SDZ : avx512_vcvtsi_common<0x7B, X86UintToFpRnd, GR64, v2f64x_info, i64mem, loadi64, "cvtusi2sd{q}">, XD, VEX_W, EVEX_CD8<64, CD8VT1>; def : Pat<(f32 (uint_to_fp (loadi32 addr:$src))), (VCVTUSI2SSZrm (f32 (IMPLICIT_DEF)), addr:$src)>; def : Pat<(f32 (uint_to_fp (loadi64 addr:$src))), (VCVTUSI642SSZrm (f32 (IMPLICIT_DEF)), addr:$src)>; def : Pat<(f64 (uint_to_fp (loadi32 addr:$src))), (VCVTUSI2SDZrm (f64 (IMPLICIT_DEF)), addr:$src)>; def : Pat<(f64 (uint_to_fp (loadi64 addr:$src))), (VCVTUSI642SDZrm (f64 (IMPLICIT_DEF)), addr:$src)>; def : Pat<(f32 (uint_to_fp GR32:$src)), (VCVTUSI2SSZrr (f32 (IMPLICIT_DEF)), GR32:$src)>; def : Pat<(f32 (uint_to_fp GR64:$src)), (VCVTUSI642SSZrr (f32 (IMPLICIT_DEF)), GR64:$src)>; def : Pat<(f64 (uint_to_fp GR32:$src)), (VCVTUSI2SDZrr (f64 (IMPLICIT_DEF)), GR32:$src)>; def : Pat<(f64 (uint_to_fp GR64:$src)), (VCVTUSI642SDZrr (f64 (IMPLICIT_DEF)), GR64:$src)>; } //===----------------------------------------------------------------------===// // AVX-512 Scalar convert from float/double to integer //===----------------------------------------------------------------------===// multiclass avx512_cvt_s_int_round opc, RegisterClass SrcRC, RegisterClass DstRC, Intrinsic Int, Operand memop, ComplexPattern mem_cpat, string asm> { let hasSideEffects = 0, Predicates = [HasAVX512] in { def rr : SI, EVEX, VEX_LIG; def rb : SI, EVEX, VEX_LIG, EVEX_B, EVEX_RC; let mayLoad = 1 in def rm : SI, EVEX, VEX_LIG; } // hasSideEffects = 0, Predicates = [HasAVX512] } // Convert float/double to signed/unsigned int 32/64 defm VCVTSS2SIZ: avx512_cvt_s_int_round<0x2D, VR128X, GR32, int_x86_sse_cvtss2si, ssmem, sse_load_f32, "cvtss2si">, XS, EVEX_CD8<32, CD8VT1>; defm VCVTSS2SI64Z: avx512_cvt_s_int_round<0x2D, VR128X, GR64, int_x86_sse_cvtss2si64, ssmem, sse_load_f32, "cvtss2si">, XS, VEX_W, EVEX_CD8<32, CD8VT1>; defm VCVTSS2USIZ: avx512_cvt_s_int_round<0x79, VR128X, GR32, int_x86_avx512_cvtss2usi, ssmem, sse_load_f32, "cvtss2usi">, XS, EVEX_CD8<32, CD8VT1>; defm VCVTSS2USI64Z: avx512_cvt_s_int_round<0x79, VR128X, GR64, int_x86_avx512_cvtss2usi64, ssmem, sse_load_f32, "cvtss2usi">, XS, VEX_W, EVEX_CD8<32, CD8VT1>; defm VCVTSD2SIZ: avx512_cvt_s_int_round<0x2D, VR128X, GR32, int_x86_sse2_cvtsd2si, sdmem, sse_load_f64, "cvtsd2si">, XD, EVEX_CD8<64, CD8VT1>; defm VCVTSD2SI64Z: avx512_cvt_s_int_round<0x2D, VR128X, GR64, int_x86_sse2_cvtsd2si64, sdmem, sse_load_f64, "cvtsd2si">, XD, VEX_W, EVEX_CD8<64, CD8VT1>; defm VCVTSD2USIZ: avx512_cvt_s_int_round<0x79, VR128X, GR32, int_x86_avx512_cvtsd2usi, sdmem, sse_load_f64, "cvtsd2usi">, XD, EVEX_CD8<64, CD8VT1>; defm VCVTSD2USI64Z: avx512_cvt_s_int_round<0x79, VR128X, GR64, int_x86_avx512_cvtsd2usi64, sdmem, sse_load_f64, "cvtsd2usi">, XD, VEX_W, EVEX_CD8<64, CD8VT1>; let isCodeGenOnly = 1 , Predicates = [HasAVX512] in { defm Int_VCVTSI2SSZ : sse12_cvt_sint_3addr<0x2A, GR32, VR128X, int_x86_sse_cvtsi2ss, i32mem, loadi32, "cvtsi2ss{l}", SSE_CVT_Scalar, 0>, XS, EVEX_4V; defm Int_VCVTSI2SS64Z : sse12_cvt_sint_3addr<0x2A, GR64, VR128X, int_x86_sse_cvtsi642ss, i64mem, loadi64, "cvtsi2ss{q}", SSE_CVT_Scalar, 0>, XS, EVEX_4V, VEX_W; defm Int_VCVTSI2SDZ : sse12_cvt_sint_3addr<0x2A, GR32, VR128X, int_x86_sse2_cvtsi2sd, i32mem, loadi32, "cvtsi2sd{l}", SSE_CVT_Scalar, 0>, XD, EVEX_4V; defm Int_VCVTSI2SD64Z : sse12_cvt_sint_3addr<0x2A, GR64, VR128X, int_x86_sse2_cvtsi642sd, i64mem, loadi64, "cvtsi2sd{q}", SSE_CVT_Scalar, 0>, XD, EVEX_4V, VEX_W; defm Int_VCVTUSI2SDZ : sse12_cvt_sint_3addr<0x2A, GR32, VR128X, int_x86_avx512_cvtusi2sd, i32mem, loadi32, "cvtusi2sd{l}", SSE_CVT_Scalar, 0>, XD, EVEX_4V; } // isCodeGenOnly = 1, Predicates = [HasAVX512] // Convert float/double to signed/unsigned int 32/64 with truncation multiclass avx512_cvt_s_all opc, string asm, X86VectorVTInfo _SrcRC, X86VectorVTInfo _DstRC, SDNode OpNode, SDNode OpNodeRnd>{ let Predicates = [HasAVX512] in { def rr : SI, EVEX; def rb : SI, EVEX, EVEX_B; def rm : SI, EVEX; let isCodeGenOnly = 1,hasSideEffects = 0 in { def rr_Int : SI, EVEX, VEX_LIG; def rb_Int : SI, EVEX,VEX_LIG , EVEX_B; let mayLoad = 1 in def rm_Int : SI, EVEX, VEX_LIG; } // isCodeGenOnly = 1, hasSideEffects = 0 } //HasAVX512 } defm VCVTTSS2SIZ: avx512_cvt_s_all<0x2C, "cvttss2si", f32x_info, i32x_info, fp_to_sint,X86cvttss2IntRnd>, XS, EVEX_CD8<32, CD8VT1>; defm VCVTTSS2SI64Z: avx512_cvt_s_all<0x2C, "cvttss2si", f32x_info, i64x_info, fp_to_sint,X86cvttss2IntRnd>, VEX_W, XS, EVEX_CD8<32, CD8VT1>; defm VCVTTSD2SIZ: avx512_cvt_s_all<0x2C, "cvttsd2si", f64x_info, i32x_info, fp_to_sint,X86cvttsd2IntRnd>, XD, EVEX_CD8<64, CD8VT1>; defm VCVTTSD2SI64Z: avx512_cvt_s_all<0x2C, "cvttsd2si", f64x_info, i64x_info, fp_to_sint,X86cvttsd2IntRnd>, VEX_W, XD, EVEX_CD8<64, CD8VT1>; defm VCVTTSS2USIZ: avx512_cvt_s_all<0x78, "cvttss2usi", f32x_info, i32x_info, fp_to_uint,X86cvttss2UIntRnd>, XS, EVEX_CD8<32, CD8VT1>; defm VCVTTSS2USI64Z: avx512_cvt_s_all<0x78, "cvttss2usi", f32x_info, i64x_info, fp_to_uint,X86cvttss2UIntRnd>, XS,VEX_W, EVEX_CD8<32, CD8VT1>; defm VCVTTSD2USIZ: avx512_cvt_s_all<0x78, "cvttsd2usi", f64x_info, i32x_info, fp_to_uint,X86cvttsd2UIntRnd>, XD, EVEX_CD8<64, CD8VT1>; defm VCVTTSD2USI64Z: avx512_cvt_s_all<0x78, "cvttsd2usi", f64x_info, i64x_info, fp_to_uint,X86cvttsd2UIntRnd>, XD, VEX_W, EVEX_CD8<64, CD8VT1>; let Predicates = [HasAVX512] in { def : Pat<(i32 (int_x86_sse_cvttss2si (v4f32 VR128X:$src))), (VCVTTSS2SIZrr_Int (COPY_TO_REGCLASS VR128X:$src, FR32X))>; def : Pat<(i64 (int_x86_sse_cvttss2si64 (v4f32 VR128X:$src))), (VCVTTSS2SI64Zrr_Int (COPY_TO_REGCLASS VR128X:$src, FR32X))>; def : Pat<(i32 (int_x86_sse2_cvttsd2si (v2f64 VR128X:$src))), (VCVTTSD2SIZrr_Int (COPY_TO_REGCLASS VR128X:$src, FR64X))>; def : Pat<(i64 (int_x86_sse2_cvttsd2si64 (v2f64 VR128X:$src))), (VCVTTSD2SI64Zrr_Int (COPY_TO_REGCLASS VR128X:$src, FR64X))>; } // HasAVX512 //===----------------------------------------------------------------------===// // AVX-512 Convert form float to double and back //===----------------------------------------------------------------------===// multiclass avx512_cvt_fp_scalar opc, string OpcodeStr, X86VectorVTInfo _, X86VectorVTInfo _Src, SDNode OpNode> { defm rr : AVX512_maskable_scalar, EVEX_4V, VEX_LIG, Sched<[WriteCvtF2F]>; defm rm : AVX512_maskable_scalar, EVEX_4V, VEX_LIG, Sched<[WriteCvtF2FLd, ReadAfterLd]>; } // Scalar Coversion with SAE - suppress all exceptions multiclass avx512_cvt_fp_sae_scalar opc, string OpcodeStr, X86VectorVTInfo _, X86VectorVTInfo _Src, SDNode OpNodeRnd> { defm rrb : AVX512_maskable_scalar, EVEX_4V, VEX_LIG, EVEX_B; } // Scalar Conversion with rounding control (RC) multiclass avx512_cvt_fp_rc_scalar opc, string OpcodeStr, X86VectorVTInfo _, X86VectorVTInfo _Src, SDNode OpNodeRnd> { defm rrb : AVX512_maskable_scalar, EVEX_4V, VEX_LIG, Sched<[WriteCvtF2FLd, ReadAfterLd]>, EVEX_B, EVEX_RC; } multiclass avx512_cvt_fp_scalar_sd2ss opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd, X86VectorVTInfo _src, X86VectorVTInfo _dst> { let Predicates = [HasAVX512] in { defm Z : avx512_cvt_fp_scalar, avx512_cvt_fp_rc_scalar, VEX_W, EVEX_CD8<64, CD8VT1>, EVEX_V512, XD; } } multiclass avx512_cvt_fp_scalar_ss2sd opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd, X86VectorVTInfo _src, X86VectorVTInfo _dst> { let Predicates = [HasAVX512] in { defm Z : avx512_cvt_fp_scalar, avx512_cvt_fp_sae_scalar, EVEX_CD8<32, CD8VT1>, XS, EVEX_V512; } } defm VCVTSD2SS : avx512_cvt_fp_scalar_sd2ss<0x5A, "vcvtsd2ss", X86fround, X86froundRnd, f64x_info, f32x_info>; defm VCVTSS2SD : avx512_cvt_fp_scalar_ss2sd<0x5A, "vcvtss2sd", X86fpext, X86fpextRnd,f32x_info, f64x_info >; def : Pat<(f64 (fextend FR32X:$src)), (COPY_TO_REGCLASS (VCVTSS2SDZrr (COPY_TO_REGCLASS FR32X:$src, VR128X), (COPY_TO_REGCLASS FR32X:$src, VR128X)), VR128X)>, Requires<[HasAVX512]>; def : Pat<(f64 (fextend (loadf32 addr:$src))), (COPY_TO_REGCLASS (VCVTSS2SDZrm (v4f32 (IMPLICIT_DEF)), addr:$src), VR128X)>, Requires<[HasAVX512]>; def : Pat<(f64 (extloadf32 addr:$src)), (COPY_TO_REGCLASS (VCVTSS2SDZrm (v4f32 (IMPLICIT_DEF)), addr:$src), VR128X)>, Requires<[HasAVX512, OptForSize]>; def : Pat<(f64 (extloadf32 addr:$src)), (COPY_TO_REGCLASS (VCVTSS2SDZrr (v4f32 (IMPLICIT_DEF)), (COPY_TO_REGCLASS (VMOVSSZrm addr:$src), VR128X)), VR128X)>, Requires<[HasAVX512, OptForSpeed]>; def : Pat<(f32 (fround FR64X:$src)), (COPY_TO_REGCLASS (VCVTSD2SSZrr (COPY_TO_REGCLASS FR64X:$src, VR128X), (COPY_TO_REGCLASS FR64X:$src, VR128X)), VR128X)>, Requires<[HasAVX512]>; //===----------------------------------------------------------------------===// // AVX-512 Vector convert from signed/unsigned integer to float/double // and from float/double to signed/unsigned integer //===----------------------------------------------------------------------===// multiclass avx512_vcvt_fp opc, string OpcodeStr, X86VectorVTInfo _, X86VectorVTInfo _Src, SDNode OpNode, string Broadcast = _.BroadcastStr, string Alias = ""> { defm rr : AVX512_maskable, EVEX; defm rm : AVX512_maskable, EVEX; defm rmb : AVX512_maskable, EVEX, EVEX_B; } // Coversion with SAE - suppress all exceptions multiclass avx512_vcvt_fp_sae opc, string OpcodeStr, X86VectorVTInfo _, X86VectorVTInfo _Src, SDNode OpNodeRnd> { defm rrb : AVX512_maskable, EVEX, EVEX_B; } // Conversion with rounding control (RC) multiclass avx512_vcvt_fp_rc opc, string OpcodeStr, X86VectorVTInfo _, X86VectorVTInfo _Src, SDNode OpNodeRnd> { defm rrb : AVX512_maskable, EVEX, EVEX_B, EVEX_RC; } // Extend Float to Double multiclass avx512_cvtps2pd opc, string OpcodeStr> { let Predicates = [HasAVX512] in { defm Z : avx512_vcvt_fp, avx512_vcvt_fp_sae, EVEX_V512; } let Predicates = [HasVLX] in { defm Z128 : avx512_vcvt_fp, EVEX_V128; defm Z256 : avx512_vcvt_fp, EVEX_V256; } } // Truncate Double to Float multiclass avx512_cvtpd2ps opc, string OpcodeStr> { let Predicates = [HasAVX512] in { defm Z : avx512_vcvt_fp, avx512_vcvt_fp_rc, EVEX_V512; } let Predicates = [HasVLX] in { defm Z128 : avx512_vcvt_fp, EVEX_V128; defm Z256 : avx512_vcvt_fp, EVEX_V256; } } defm VCVTPD2PS : avx512_cvtpd2ps<0x5A, "vcvtpd2ps">, VEX_W, PD, EVEX_CD8<64, CD8VF>; defm VCVTPS2PD : avx512_cvtps2pd<0x5A, "vcvtps2pd">, PS, EVEX_CD8<32, CD8VH>; def : Pat<(v8f64 (extloadv8f32 addr:$src)), (VCVTPS2PDZrm addr:$src)>; let Predicates = [HasVLX] in { def : Pat<(v4f64 (extloadv4f32 addr:$src)), (VCVTPS2PDZ256rm addr:$src)>; } // Convert Signed/Unsigned Doubleword to Double multiclass avx512_cvtdq2pd opc, string OpcodeStr, SDNode OpNode, SDNode OpNode128> { // No rounding in this op let Predicates = [HasAVX512] in defm Z : avx512_vcvt_fp, EVEX_V512; let Predicates = [HasVLX] in { defm Z128 : avx512_vcvt_fp, EVEX_V128; defm Z256 : avx512_vcvt_fp, EVEX_V256; } } // Convert Signed/Unsigned Doubleword to Float multiclass avx512_cvtdq2ps opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd> { let Predicates = [HasAVX512] in defm Z : avx512_vcvt_fp, avx512_vcvt_fp_rc, EVEX_V512; let Predicates = [HasVLX] in { defm Z128 : avx512_vcvt_fp, EVEX_V128; defm Z256 : avx512_vcvt_fp, EVEX_V256; } } // Convert Float to Signed/Unsigned Doubleword with truncation multiclass avx512_cvttps2dq opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd> { let Predicates = [HasAVX512] in { defm Z : avx512_vcvt_fp, avx512_vcvt_fp_sae, EVEX_V512; } let Predicates = [HasVLX] in { defm Z128 : avx512_vcvt_fp, EVEX_V128; defm Z256 : avx512_vcvt_fp, EVEX_V256; } } // Convert Float to Signed/Unsigned Doubleword multiclass avx512_cvtps2dq opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd> { let Predicates = [HasAVX512] in { defm Z : avx512_vcvt_fp, avx512_vcvt_fp_rc, EVEX_V512; } let Predicates = [HasVLX] in { defm Z128 : avx512_vcvt_fp, EVEX_V128; defm Z256 : avx512_vcvt_fp, EVEX_V256; } } // Convert Double to Signed/Unsigned Doubleword with truncation multiclass avx512_cvttpd2dq opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd> { let Predicates = [HasAVX512] in { defm Z : avx512_vcvt_fp, avx512_vcvt_fp_sae, EVEX_V512; } let Predicates = [HasVLX] in { // we need "x"/"y" suffixes in order to distinguish between 128 and 256 // memory forms of these instructions in Asm Parcer. They have the same // dest type - 'v4i32x_info'. We also specify the broadcast string explicitly // due to the same reason. defm Z128 : avx512_vcvt_fp, EVEX_V128; defm Z256 : avx512_vcvt_fp, EVEX_V256; } } // Convert Double to Signed/Unsigned Doubleword multiclass avx512_cvtpd2dq opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd> { let Predicates = [HasAVX512] in { defm Z : avx512_vcvt_fp, avx512_vcvt_fp_rc, EVEX_V512; } let Predicates = [HasVLX] in { // we need "x"/"y" suffixes in order to distinguish between 128 and 256 // memory forms of these instructions in Asm Parcer. They have the same // dest type - 'v4i32x_info'. We also specify the broadcast string explicitly // due to the same reason. defm Z128 : avx512_vcvt_fp, EVEX_V128; defm Z256 : avx512_vcvt_fp, EVEX_V256; } } // Convert Double to Signed/Unsigned Quardword multiclass avx512_cvtpd2qq opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd> { let Predicates = [HasDQI] in { defm Z : avx512_vcvt_fp, avx512_vcvt_fp_rc, EVEX_V512; } let Predicates = [HasDQI, HasVLX] in { defm Z128 : avx512_vcvt_fp, EVEX_V128; defm Z256 : avx512_vcvt_fp, EVEX_V256; } } // Convert Double to Signed/Unsigned Quardword with truncation multiclass avx512_cvttpd2qq opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd> { let Predicates = [HasDQI] in { defm Z : avx512_vcvt_fp, avx512_vcvt_fp_sae, EVEX_V512; } let Predicates = [HasDQI, HasVLX] in { defm Z128 : avx512_vcvt_fp, EVEX_V128; defm Z256 : avx512_vcvt_fp, EVEX_V256; } } // Convert Signed/Unsigned Quardword to Double multiclass avx512_cvtqq2pd opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd> { let Predicates = [HasDQI] in { defm Z : avx512_vcvt_fp, avx512_vcvt_fp_rc, EVEX_V512; } let Predicates = [HasDQI, HasVLX] in { defm Z128 : avx512_vcvt_fp, EVEX_V128; defm Z256 : avx512_vcvt_fp, EVEX_V256; } } // Convert Float to Signed/Unsigned Quardword multiclass avx512_cvtps2qq opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd> { let Predicates = [HasDQI] in { defm Z : avx512_vcvt_fp, avx512_vcvt_fp_rc, EVEX_V512; } let Predicates = [HasDQI, HasVLX] in { // Explicitly specified broadcast string, since we take only 2 elements // from v4f32x_info source defm Z128 : avx512_vcvt_fp, EVEX_V128; defm Z256 : avx512_vcvt_fp, EVEX_V256; } } // Convert Float to Signed/Unsigned Quardword with truncation multiclass avx512_cvttps2qq opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd> { let Predicates = [HasDQI] in { defm Z : avx512_vcvt_fp, avx512_vcvt_fp_sae, EVEX_V512; } let Predicates = [HasDQI, HasVLX] in { // Explicitly specified broadcast string, since we take only 2 elements // from v4f32x_info source defm Z128 : avx512_vcvt_fp, EVEX_V128; defm Z256 : avx512_vcvt_fp, EVEX_V256; } } // Convert Signed/Unsigned Quardword to Float multiclass avx512_cvtqq2ps opc, string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd> { let Predicates = [HasDQI] in { defm Z : avx512_vcvt_fp, avx512_vcvt_fp_rc, EVEX_V512; } let Predicates = [HasDQI, HasVLX] in { // we need "x"/"y" suffixes in order to distinguish between 128 and 256 // memory forms of these instructions in Asm Parcer. They have the same // dest type - 'v4i32x_info'. We also specify the broadcast string explicitly // due to the same reason. defm Z128 : avx512_vcvt_fp, EVEX_V128; defm Z256 : avx512_vcvt_fp, EVEX_V256; } } defm VCVTDQ2PD : avx512_cvtdq2pd<0xE6, "vcvtdq2pd", sint_to_fp, X86cvtdq2pd>, XS, EVEX_CD8<32, CD8VH>; defm VCVTDQ2PS : avx512_cvtdq2ps<0x5B, "vcvtdq2ps", sint_to_fp, X86VSintToFpRnd>, PS, EVEX_CD8<32, CD8VF>; defm VCVTTPS2DQ : avx512_cvttps2dq<0x5B, "vcvttps2dq", fp_to_sint, X86VFpToSintRnd>, XS, EVEX_CD8<32, CD8VF>; defm VCVTTPD2DQ : avx512_cvttpd2dq<0xE6, "vcvttpd2dq", fp_to_sint, X86VFpToSintRnd>, PD, VEX_W, EVEX_CD8<64, CD8VF>; defm VCVTTPS2UDQ : avx512_cvttps2dq<0x78, "vcvttps2udq", fp_to_uint, X86VFpToUintRnd>, PS, EVEX_CD8<32, CD8VF>; defm VCVTTPD2UDQ : avx512_cvttpd2dq<0x78, "vcvttpd2udq", fp_to_uint, X86VFpToUintRnd>, PS, VEX_W, EVEX_CD8<64, CD8VF>; defm VCVTUDQ2PD : avx512_cvtdq2pd<0x7A, "vcvtudq2pd", uint_to_fp, X86cvtudq2pd>, XS, EVEX_CD8<32, CD8VH>; defm VCVTUDQ2PS : avx512_cvtdq2ps<0x7A, "vcvtudq2ps", uint_to_fp, X86VUintToFpRnd>, XD, EVEX_CD8<32, CD8VF>; defm VCVTPS2DQ : avx512_cvtps2dq<0x5B, "vcvtps2dq", X86cvtps2Int, X86cvtps2IntRnd>, PD, EVEX_CD8<32, CD8VF>; defm VCVTPD2DQ : avx512_cvtpd2dq<0xE6, "vcvtpd2dq", X86cvtpd2Int, X86cvtpd2IntRnd>, XD, VEX_W, EVEX_CD8<64, CD8VF>; defm VCVTPS2UDQ : avx512_cvtps2dq<0x79, "vcvtps2udq", X86cvtps2UInt, X86cvtps2UIntRnd>, PS, EVEX_CD8<32, CD8VF>; defm VCVTPD2UDQ : avx512_cvtpd2dq<0x79, "vcvtpd2udq", X86cvtpd2UInt, X86cvtpd2UIntRnd>, VEX_W, PS, EVEX_CD8<64, CD8VF>; defm VCVTPD2QQ : avx512_cvtpd2qq<0x7B, "vcvtpd2qq", X86cvtpd2Int, X86cvtpd2IntRnd>, VEX_W, PD, EVEX_CD8<64, CD8VF>; defm VCVTPS2QQ : avx512_cvtps2qq<0x7B, "vcvtps2qq", X86cvtps2Int, X86cvtps2IntRnd>, PD, EVEX_CD8<32, CD8VH>; defm VCVTPD2UQQ : avx512_cvtpd2qq<0x79, "vcvtpd2uqq", X86cvtpd2UInt, X86cvtpd2UIntRnd>, VEX_W, PD, EVEX_CD8<64, CD8VF>; defm VCVTPS2UQQ : avx512_cvtps2qq<0x79, "vcvtps2uqq", X86cvtps2UInt, X86cvtps2UIntRnd>, PD, EVEX_CD8<32, CD8VH>; defm VCVTTPD2QQ : avx512_cvttpd2qq<0x7A, "vcvttpd2qq", fp_to_sint, X86VFpToSlongRnd>, VEX_W, PD, EVEX_CD8<64, CD8VF>; defm VCVTTPS2QQ : avx512_cvttps2qq<0x7A, "vcvttps2qq", fp_to_sint, X86VFpToSlongRnd>, PD, EVEX_CD8<32, CD8VH>; defm VCVTTPD2UQQ : avx512_cvttpd2qq<0x78, "vcvttpd2uqq", fp_to_uint, X86VFpToUlongRnd>, VEX_W, PD, EVEX_CD8<64, CD8VF>; defm VCVTTPS2UQQ : avx512_cvttps2qq<0x78, "vcvttps2uqq", fp_to_uint, X86VFpToUlongRnd>, PD, EVEX_CD8<32, CD8VH>; defm VCVTQQ2PD : avx512_cvtqq2pd<0xE6, "vcvtqq2pd", sint_to_fp, X86VSlongToFpRnd>, VEX_W, XS, EVEX_CD8<64, CD8VF>; defm VCVTUQQ2PD : avx512_cvtqq2pd<0x7A, "vcvtuqq2pd", uint_to_fp, X86VUlongToFpRnd>, VEX_W, XS, EVEX_CD8<64, CD8VF>; defm VCVTQQ2PS : avx512_cvtqq2ps<0x5B, "vcvtqq2ps", sint_to_fp, X86VSlongToFpRnd>, VEX_W, PS, EVEX_CD8<64, CD8VF>; defm VCVTUQQ2PS : avx512_cvtqq2ps<0x7A, "vcvtuqq2ps", uint_to_fp, X86VUlongToFpRnd>, VEX_W, XD, EVEX_CD8<64, CD8VF>; let Predicates = [HasAVX512, NoVLX] in { def : Pat<(v8i32 (fp_to_uint (v8f32 VR256X:$src1))), (EXTRACT_SUBREG (v16i32 (VCVTTPS2UDQZrr (v16f32 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)))), sub_ymm)>; def : Pat<(v4i32 (fp_to_uint (v4f32 VR128X:$src1))), (EXTRACT_SUBREG (v16i32 (VCVTTPS2UDQZrr (v16f32 (SUBREG_TO_REG (i32 0), VR128X:$src1, sub_xmm)))), sub_xmm)>; def : Pat<(v8f32 (uint_to_fp (v8i32 VR256X:$src1))), (EXTRACT_SUBREG (v16f32 (VCVTUDQ2PSZrr (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)))), sub_ymm)>; def : Pat<(v4f32 (uint_to_fp (v4i32 VR128X:$src1))), (EXTRACT_SUBREG (v16f32 (VCVTUDQ2PSZrr (v16i32 (SUBREG_TO_REG (i32 0), VR128X:$src1, sub_xmm)))), sub_xmm)>; def : Pat<(v4f64 (uint_to_fp (v4i32 VR128X:$src1))), (EXTRACT_SUBREG (v8f64 (VCVTUDQ2PDZrr (v8i32 (SUBREG_TO_REG (i32 0), VR128X:$src1, sub_xmm)))), sub_ymm)>; } let Predicates = [HasAVX512] in { def : Pat<(v8f32 (fround (loadv8f64 addr:$src))), (VCVTPD2PSZrm addr:$src)>; def : Pat<(v8f64 (extloadv8f32 addr:$src)), (VCVTPS2PDZrm addr:$src)>; } //===----------------------------------------------------------------------===// // Half precision conversion instructions //===----------------------------------------------------------------------===// multiclass avx512_cvtph2ps { defm rr : AVX512_maskable<0x13, MRMSrcReg, _dest ,(outs _dest.RC:$dst), (ins _src.RC:$src), "vcvtph2ps", "$src", "$src", (X86cvtph2ps (_src.VT _src.RC:$src), (i32 FROUND_CURRENT))>, T8PD; let hasSideEffects = 0, mayLoad = 1 in { defm rm : AVX512_maskable<0x13, MRMSrcMem, _dest, (outs _dest.RC:$dst), (ins x86memop:$src), "vcvtph2ps", "$src", "$src", (X86cvtph2ps (_src.VT (bitconvert (ld_frag addr:$src))), (i32 FROUND_CURRENT))>, T8PD; } } multiclass avx512_cvtph2ps_sae { defm rb : AVX512_maskable<0x13, MRMSrcReg, _dest ,(outs _dest.RC:$dst), (ins _src.RC:$src), "vcvtph2ps", "{sae}, $src", "$src, {sae}", (X86cvtph2ps (_src.VT _src.RC:$src), (i32 FROUND_NO_EXC))>, T8PD, EVEX_B; } let Predicates = [HasAVX512] in { defm VCVTPH2PSZ : avx512_cvtph2ps, avx512_cvtph2ps_sae, EVEX, EVEX_V512, EVEX_CD8<32, CD8VH>; let Predicates = [HasVLX] in { defm VCVTPH2PSZ256 : avx512_cvtph2ps,EVEX, EVEX_V256, EVEX_CD8<32, CD8VH>; defm VCVTPH2PSZ128 : avx512_cvtph2ps, EVEX, EVEX_V128, EVEX_CD8<32, CD8VH>; } } multiclass avx512_cvtps2ph { defm rr : AVX512_maskable<0x1D, MRMDestReg, _dest ,(outs _dest.RC:$dst), (ins _src.RC:$src1, i32u8imm:$src2), "vcvtps2ph", "$src2, $src1", "$src1, $src2", (X86cvtps2ph (_src.VT _src.RC:$src1), (i32 imm:$src2), (i32 FROUND_CURRENT))>, AVX512AIi8Base; let hasSideEffects = 0, mayStore = 1 in { def mr : AVX512AIi8<0x1D, MRMDestMem, (outs), (ins x86memop:$dst, _src.RC:$src1, i32u8imm:$src2), "vcvtps2ph\t{$src2, $src1, $dst|$dst, $src1, $src2}", [(store (_dest.VT (X86cvtps2ph (_src.VT _src.RC:$src1), (i32 imm:$src2), (i32 FROUND_CURRENT) )), addr:$dst)]>; def mrk : AVX512AIi8<0x1D, MRMDestMem, (outs), (ins x86memop:$dst, _dest.KRCWM:$mask, _src.RC:$src1, i32u8imm:$src2), "vcvtps2ph\t{$src2, $src1, $dst {${mask}}|$dst {${mask}}, $src1, $src2}", []>, EVEX_K; } } multiclass avx512_cvtps2ph_sae { defm rb : AVX512_maskable<0x1D, MRMDestReg, _dest ,(outs _dest.RC:$dst), (ins _src.RC:$src1, i32u8imm:$src2), "vcvtps2ph", "$src2, {sae}, $src1", "$src1, $src2, {sae}", (X86cvtps2ph (_src.VT _src.RC:$src1), (i32 imm:$src2), (i32 FROUND_NO_EXC))>, EVEX_B, AVX512AIi8Base; } let Predicates = [HasAVX512] in { defm VCVTPS2PHZ : avx512_cvtps2ph, avx512_cvtps2ph_sae, EVEX, EVEX_V512, EVEX_CD8<32, CD8VH>; let Predicates = [HasVLX] in { defm VCVTPS2PHZ256 : avx512_cvtps2ph, EVEX, EVEX_V256, EVEX_CD8<32, CD8VH>; defm VCVTPS2PHZ128 : avx512_cvtps2ph, EVEX, EVEX_V128, EVEX_CD8<32, CD8VH>; } } // Unordered/Ordered scalar fp compare with Sea and set EFLAGS multiclass avx512_ord_cmp_sae opc, X86VectorVTInfo _, SDNode OpNode, string OpcodeStr> { def rb: AVX512, EVEX, EVEX_B, VEX_LIG, EVEX_V128, Sched<[WriteFAdd]>; } let Defs = [EFLAGS], Predicates = [HasAVX512] in { defm VUCOMISSZ : avx512_ord_cmp_sae<0x2E, v4f32x_info, X86ucomiSae, "vucomiss">, AVX512PSIi8Base, EVEX_CD8<32, CD8VT1>; defm VUCOMISDZ : avx512_ord_cmp_sae<0x2E, v2f64x_info, X86ucomiSae, "vucomisd">, AVX512PDIi8Base, VEX_W, EVEX_CD8<64, CD8VT1>; defm VCOMISSZ : avx512_ord_cmp_sae<0x2F, v4f32x_info, X86comiSae, "vcomiss">, AVX512PSIi8Base, EVEX_CD8<32, CD8VT1>; defm VCOMISDZ : avx512_ord_cmp_sae<0x2F, v2f64x_info, X86comiSae, "vcomisd">, AVX512PDIi8Base, VEX_W, EVEX_CD8<64, CD8VT1>; } let Defs = [EFLAGS], Predicates = [HasAVX512] in { defm VUCOMISSZ : sse12_ord_cmp<0x2E, FR32X, X86cmp, f32, f32mem, loadf32, "ucomiss">, PS, EVEX, VEX_LIG, EVEX_CD8<32, CD8VT1>; defm VUCOMISDZ : sse12_ord_cmp<0x2E, FR64X, X86cmp, f64, f64mem, loadf64, "ucomisd">, PD, EVEX, VEX_LIG, VEX_W, EVEX_CD8<64, CD8VT1>; let Pattern = [] in { defm VCOMISSZ : sse12_ord_cmp<0x2F, FR32X, undef, f32, f32mem, loadf32, "comiss">, PS, EVEX, VEX_LIG, EVEX_CD8<32, CD8VT1>; defm VCOMISDZ : sse12_ord_cmp<0x2F, FR64X, undef, f64, f64mem, loadf64, "comisd">, PD, EVEX, VEX_LIG, VEX_W, EVEX_CD8<64, CD8VT1>; } let isCodeGenOnly = 1 in { defm Int_VUCOMISSZ : sse12_ord_cmp<0x2E, VR128X, X86ucomi, v4f32, f128mem, load, "ucomiss">, PS, EVEX, VEX_LIG, EVEX_CD8<32, CD8VT1>; defm Int_VUCOMISDZ : sse12_ord_cmp<0x2E, VR128X, X86ucomi, v2f64, f128mem, load, "ucomisd">, PD, EVEX, VEX_LIG, VEX_W, EVEX_CD8<64, CD8VT1>; defm Int_VCOMISSZ : sse12_ord_cmp<0x2F, VR128X, X86comi, v4f32, f128mem, load, "comiss">, PS, EVEX, VEX_LIG, EVEX_CD8<32, CD8VT1>; defm Int_VCOMISDZ : sse12_ord_cmp<0x2F, VR128X, X86comi, v2f64, f128mem, load, "comisd">, PD, EVEX, VEX_LIG, VEX_W, EVEX_CD8<64, CD8VT1>; } } /// avx512_fp14_s rcp14ss, rcp14sd, rsqrt14ss, rsqrt14sd multiclass avx512_fp14_s opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { let hasSideEffects = 0, AddedComplexity = 20 , Predicates = [HasAVX512] in { defm rr : AVX512_maskable_scalar, EVEX_4V; let mayLoad = 1 in { defm rm : AVX512_maskable_scalar, EVEX_4V; } } } defm VRCP14SS : avx512_fp14_s<0x4D, "vrcp14ss", X86frcp14s, f32x_info>, EVEX_CD8<32, CD8VT1>, T8PD; defm VRCP14SD : avx512_fp14_s<0x4D, "vrcp14sd", X86frcp14s, f64x_info>, VEX_W, EVEX_CD8<64, CD8VT1>, T8PD; defm VRSQRT14SS : avx512_fp14_s<0x4F, "vrsqrt14ss", X86frsqrt14s, f32x_info>, EVEX_CD8<32, CD8VT1>, T8PD; defm VRSQRT14SD : avx512_fp14_s<0x4F, "vrsqrt14sd", X86frsqrt14s, f64x_info>, VEX_W, EVEX_CD8<64, CD8VT1>, T8PD; /// avx512_fp14_p rcp14ps, rcp14pd, rsqrt14ps, rsqrt14pd multiclass avx512_fp14_p opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { defm r: AVX512_maskable, EVEX, T8PD; let mayLoad = 1 in { defm m: AVX512_maskable, EVEX, T8PD; defm mb: AVX512_maskable, EVEX, T8PD, EVEX_B; } } multiclass avx512_fp14_p_vl_all opc, string OpcodeStr, SDNode OpNode> { defm PSZ : avx512_fp14_p, EVEX_V512, EVEX_CD8<32, CD8VF>; defm PDZ : avx512_fp14_p, EVEX_V512, VEX_W, EVEX_CD8<64, CD8VF>; // Define only if AVX512VL feature is present. let Predicates = [HasVLX] in { defm PSZ128 : avx512_fp14_p, EVEX_V128, EVEX_CD8<32, CD8VF>; defm PSZ256 : avx512_fp14_p, EVEX_V256, EVEX_CD8<32, CD8VF>; defm PDZ128 : avx512_fp14_p, EVEX_V128, VEX_W, EVEX_CD8<64, CD8VF>; defm PDZ256 : avx512_fp14_p, EVEX_V256, VEX_W, EVEX_CD8<64, CD8VF>; } } defm VRSQRT14 : avx512_fp14_p_vl_all<0x4E, "vrsqrt14", X86frsqrt>; defm VRCP14 : avx512_fp14_p_vl_all<0x4C, "vrcp14", X86frcp>; /// avx512_fp28_s rcp28ss, rcp28sd, rsqrt28ss, rsqrt28sd multiclass avx512_fp28_s opc, string OpcodeStr,X86VectorVTInfo _, SDNode OpNode> { defm r : AVX512_maskable_scalar; defm rb : AVX512_maskable_scalar, EVEX_B; defm m : AVX512_maskable_scalar; } multiclass avx512_eri_s opc, string OpcodeStr, SDNode OpNode> { defm SS : avx512_fp28_s, EVEX_CD8<32, CD8VT1>; defm SD : avx512_fp28_s, EVEX_CD8<64, CD8VT1>, VEX_W; } let hasSideEffects = 0, Predicates = [HasERI] in { defm VRCP28 : avx512_eri_s<0xCB, "vrcp28", X86rcp28s>, T8PD, EVEX_4V; defm VRSQRT28 : avx512_eri_s<0xCD, "vrsqrt28", X86rsqrt28s>, T8PD, EVEX_4V; } defm VGETEXP : avx512_eri_s<0x43, "vgetexp", X86fgetexpRnds>, T8PD, EVEX_4V; /// avx512_fp28_p rcp28ps, rcp28pd, rsqrt28ps, rsqrt28pd multiclass avx512_fp28_p opc, string OpcodeStr, X86VectorVTInfo _, SDNode OpNode> { defm r : AVX512_maskable; defm m : AVX512_maskable; defm mb : AVX512_maskable, EVEX_B; } multiclass avx512_fp28_p_round opc, string OpcodeStr, X86VectorVTInfo _, SDNode OpNode> { defm rb : AVX512_maskable, EVEX_B; } multiclass avx512_eri opc, string OpcodeStr, SDNode OpNode> { defm PS : avx512_fp28_p, avx512_fp28_p_round, T8PD, EVEX_V512, EVEX_CD8<32, CD8VF>; defm PD : avx512_fp28_p, avx512_fp28_p_round, T8PD, EVEX_V512, VEX_W, EVEX_CD8<64, CD8VF>; } multiclass avx512_fp_unaryop_packed opc, string OpcodeStr, SDNode OpNode> { // Define only if AVX512VL feature is present. let Predicates = [HasVLX] in { defm PSZ128 : avx512_fp28_p, EVEX_V128, T8PD, EVEX_CD8<32, CD8VF>; defm PSZ256 : avx512_fp28_p, EVEX_V256, T8PD, EVEX_CD8<32, CD8VF>; defm PDZ128 : avx512_fp28_p, EVEX_V128, VEX_W, T8PD, EVEX_CD8<64, CD8VF>; defm PDZ256 : avx512_fp28_p, EVEX_V256, VEX_W, T8PD, EVEX_CD8<64, CD8VF>; } } let Predicates = [HasERI], hasSideEffects = 0 in { defm VRSQRT28 : avx512_eri<0xCC, "vrsqrt28", X86rsqrt28>, EVEX; defm VRCP28 : avx512_eri<0xCA, "vrcp28", X86rcp28>, EVEX; defm VEXP2 : avx512_eri<0xC8, "vexp2", X86exp2>, EVEX; } defm VGETEXP : avx512_eri<0x42, "vgetexp", X86fgetexpRnd>, avx512_fp_unaryop_packed<0x42, "vgetexp", X86fgetexpRnd> , EVEX; multiclass avx512_sqrt_packed_round opc, string OpcodeStr, SDNode OpNodeRnd, X86VectorVTInfo _>{ defm rb: AVX512_maskable, EVEX, EVEX_B, EVEX_RC; } multiclass avx512_sqrt_packed opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _>{ defm r: AVX512_maskable, EVEX; let mayLoad = 1 in { defm m: AVX512_maskable, EVEX; defm mb: AVX512_maskable, EVEX, EVEX_B; } } multiclass avx512_sqrt_packed_all opc, string OpcodeStr, SDNode OpNode> { defm PSZ : avx512_sqrt_packed, EVEX_V512, PS, EVEX_CD8<32, CD8VF>; defm PDZ : avx512_sqrt_packed, EVEX_V512, VEX_W, PD, EVEX_CD8<64, CD8VF>; // Define only if AVX512VL feature is present. let Predicates = [HasVLX] in { defm PSZ128 : avx512_sqrt_packed, EVEX_V128, PS, EVEX_CD8<32, CD8VF>; defm PSZ256 : avx512_sqrt_packed, EVEX_V256, PS, EVEX_CD8<32, CD8VF>; defm PDZ128 : avx512_sqrt_packed, EVEX_V128, VEX_W, PD, EVEX_CD8<64, CD8VF>; defm PDZ256 : avx512_sqrt_packed, EVEX_V256, VEX_W, PD, EVEX_CD8<64, CD8VF>; } } multiclass avx512_sqrt_packed_all_round opc, string OpcodeStr, SDNode OpNodeRnd> { defm PSZ : avx512_sqrt_packed_round, EVEX_V512, PS, EVEX_CD8<32, CD8VF>; defm PDZ : avx512_sqrt_packed_round, EVEX_V512, VEX_W, PD, EVEX_CD8<64, CD8VF>; } multiclass avx512_sqrt_scalar opc, string OpcodeStr,X86VectorVTInfo _, string SUFF, SDNode OpNode, SDNode OpNodeRnd> { defm r_Int : AVX512_maskable_scalar; let mayLoad = 1 in defm m_Int : AVX512_maskable_scalar; defm rb_Int : AVX512_maskable_scalar, EVEX_B, EVEX_RC; let isCodeGenOnly = 1 in { def r : I; let mayLoad = 1 in def m : I; } def : Pat<(_.EltVT (OpNode _.FRC:$src)), (!cast(NAME#SUFF#Zr) (_.EltVT (IMPLICIT_DEF)), _.FRC:$src)>; def : Pat<(_.EltVT (OpNode (load addr:$src))), (!cast(NAME#SUFF#Zm) - (_.EltVT (IMPLICIT_DEF)), addr:$src)>, Requires<[OptForSize]>; + (_.EltVT (IMPLICIT_DEF)), addr:$src)>, Requires<[HasAVX512, OptForSize]>; } multiclass avx512_sqrt_scalar_all opc, string OpcodeStr> { defm SSZ : avx512_sqrt_scalar, EVEX_CD8<32, CD8VT1>, EVEX_4V, XS; defm SDZ : avx512_sqrt_scalar, EVEX_CD8<64, CD8VT1>, EVEX_4V, XD, VEX_W; } defm VSQRT : avx512_sqrt_packed_all<0x51, "vsqrt", fsqrt>, avx512_sqrt_packed_all_round<0x51, "vsqrt", X86fsqrtRnd>; defm VSQRT : avx512_sqrt_scalar_all<0x51, "vsqrt">, VEX_LIG; let Predicates = [HasAVX512] in { def : Pat<(f32 (X86frsqrt FR32X:$src)), (COPY_TO_REGCLASS (VRSQRT14SSrr (v4f32 (IMPLICIT_DEF)), (COPY_TO_REGCLASS FR32X:$src, VR128X)), VR128X)>; def : Pat<(f32 (X86frsqrt (load addr:$src))), (COPY_TO_REGCLASS (VRSQRT14SSrm (v4f32 (IMPLICIT_DEF)), addr:$src), VR128X)>, Requires<[OptForSize]>; def : Pat<(f32 (X86frcp FR32X:$src)), (COPY_TO_REGCLASS (VRCP14SSrr (v4f32 (IMPLICIT_DEF)), (COPY_TO_REGCLASS FR32X:$src, VR128X)), VR128X )>; def : Pat<(f32 (X86frcp (load addr:$src))), (COPY_TO_REGCLASS (VRCP14SSrm (v4f32 (IMPLICIT_DEF)), addr:$src), VR128X)>, Requires<[OptForSize]>; } multiclass avx512_rndscale_scalar opc, string OpcodeStr, X86VectorVTInfo _> { let ExeDomain = _.ExeDomain in { defm r : AVX512_maskable_scalar; defm rb : AVX512_maskable_scalar, EVEX_B; let mayLoad = 1 in defm m : AVX512_maskable_scalar; } let Predicates = [HasAVX512] in { def : Pat<(ffloor _.FRC:$src), (COPY_TO_REGCLASS (_.VT (!cast(NAME##r) (_.VT (IMPLICIT_DEF)), (_.VT (COPY_TO_REGCLASS _.FRC:$src, _.RC)), (i32 0x1))), _.FRC)>; def : Pat<(fceil _.FRC:$src), (COPY_TO_REGCLASS (_.VT (!cast(NAME##r) (_.VT (IMPLICIT_DEF)), (_.VT (COPY_TO_REGCLASS _.FRC:$src, _.RC)), (i32 0x2))), _.FRC)>; def : Pat<(ftrunc _.FRC:$src), (COPY_TO_REGCLASS (_.VT (!cast(NAME##r) (_.VT (IMPLICIT_DEF)), (_.VT (COPY_TO_REGCLASS _.FRC:$src, _.RC)), (i32 0x3))), _.FRC)>; def : Pat<(frint _.FRC:$src), (COPY_TO_REGCLASS (_.VT (!cast(NAME##r) (_.VT (IMPLICIT_DEF)), (_.VT (COPY_TO_REGCLASS _.FRC:$src, _.RC)), (i32 0x4))), _.FRC)>; def : Pat<(fnearbyint _.FRC:$src), (COPY_TO_REGCLASS (_.VT (!cast(NAME##r) (_.VT (IMPLICIT_DEF)), (_.VT (COPY_TO_REGCLASS _.FRC:$src, _.RC)), (i32 0xc))), _.FRC)>; def : Pat<(ffloor (_.ScalarLdFrag addr:$src)), (COPY_TO_REGCLASS (_.VT (!cast(NAME##m) (_.VT (IMPLICIT_DEF)), addr:$src, (i32 0x1))), _.FRC)>; def : Pat<(fceil (_.ScalarLdFrag addr:$src)), (COPY_TO_REGCLASS (_.VT (!cast(NAME##m) (_.VT (IMPLICIT_DEF)), addr:$src, (i32 0x2))), _.FRC)>; def : Pat<(ftrunc (_.ScalarLdFrag addr:$src)), (COPY_TO_REGCLASS (_.VT (!cast(NAME##m) (_.VT (IMPLICIT_DEF)), addr:$src, (i32 0x3))), _.FRC)>; def : Pat<(frint (_.ScalarLdFrag addr:$src)), (COPY_TO_REGCLASS (_.VT (!cast(NAME##m) (_.VT (IMPLICIT_DEF)), addr:$src, (i32 0x4))), _.FRC)>; def : Pat<(fnearbyint (_.ScalarLdFrag addr:$src)), (COPY_TO_REGCLASS (_.VT (!cast(NAME##m) (_.VT (IMPLICIT_DEF)), addr:$src, (i32 0xc))), _.FRC)>; } } defm VRNDSCALESS : avx512_rndscale_scalar<0x0A, "vrndscaless", f32x_info>, AVX512AIi8Base, EVEX_4V, EVEX_CD8<32, CD8VT1>; defm VRNDSCALESD : avx512_rndscale_scalar<0x0B, "vrndscalesd", f64x_info>, VEX_W, AVX512AIi8Base, EVEX_4V, EVEX_CD8<64, CD8VT1>; //------------------------------------------------- // Integer truncate and extend operations //------------------------------------------------- multiclass avx512_trunc_common opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo SrcInfo, X86VectorVTInfo DestInfo, X86MemOperand x86memop> { defm rr : AVX512_maskable, EVEX, T8XS; // for intrinsic patter match def : Pat<(DestInfo.VT (X86select DestInfo.KRCWM:$mask, (DestInfo.VT (OpNode (SrcInfo.VT SrcInfo.RC:$src1))), undef)), (!cast(NAME#SrcInfo.ZSuffix##rrkz) DestInfo.KRCWM:$mask , SrcInfo.RC:$src1)>; def : Pat<(DestInfo.VT (X86select DestInfo.KRCWM:$mask, (DestInfo.VT (OpNode (SrcInfo.VT SrcInfo.RC:$src1))), DestInfo.ImmAllZerosV)), (!cast(NAME#SrcInfo.ZSuffix##rrkz) DestInfo.KRCWM:$mask , SrcInfo.RC:$src1)>; def : Pat<(DestInfo.VT (X86select DestInfo.KRCWM:$mask, (DestInfo.VT (OpNode (SrcInfo.VT SrcInfo.RC:$src1))), DestInfo.RC:$src0)), (!cast(NAME#SrcInfo.ZSuffix##rrk) DestInfo.RC:$src0, DestInfo.KRCWM:$mask , SrcInfo.RC:$src1)>; let mayStore = 1 in { def mr : AVX512XS8I, EVEX; def mrk : AVX512XS8I, EVEX, EVEX_K; }//mayStore = 1 } multiclass avx512_trunc_mr_lowering { def : Pat<(truncFrag (SrcInfo.VT SrcInfo.RC:$src), addr:$dst), (!cast(NAME#SrcInfo.ZSuffix##mr) addr:$dst, SrcInfo.RC:$src)>; def : Pat<(mtruncFrag addr:$dst, SrcInfo.KRCWM:$mask, (SrcInfo.VT SrcInfo.RC:$src)), (!cast(NAME#SrcInfo.ZSuffix##mrk) addr:$dst, SrcInfo.KRCWM:$mask, SrcInfo.RC:$src)>; } multiclass avx512_trunc_sat_mr_lowering { def: Pat<(!cast("int_x86_avx512_mask_pmov"#sat#"_"#SrcInfo.Suffix# DestInfo.Suffix#"_mem_"#SrcInfo.Size) addr:$ptr, (SrcInfo.VT SrcInfo.RC:$src), SrcInfo.MRC:$mask), (!cast(NAME#SrcInfo.ZSuffix##mrk) addr:$ptr, (COPY_TO_REGCLASS SrcInfo.MRC:$mask, SrcInfo.KRCWM), (SrcInfo.VT SrcInfo.RC:$src))>; def: Pat<(!cast("int_x86_avx512_mask_pmov"#sat#"_"#SrcInfo.Suffix# DestInfo.Suffix#"_mem_"#SrcInfo.Size) addr:$ptr, (SrcInfo.VT SrcInfo.RC:$src), -1), (!cast(NAME#SrcInfo.ZSuffix##mr) addr:$ptr, (SrcInfo.VT SrcInfo.RC:$src))>; } multiclass avx512_trunc opc, string OpcodeStr, SDNode OpNode, AVX512VLVectorVTInfo VTSrcInfo, X86VectorVTInfo DestInfoZ128, X86VectorVTInfo DestInfoZ256, X86VectorVTInfo DestInfoZ, X86MemOperand x86memopZ128, X86MemOperand x86memopZ256, X86MemOperand x86memopZ, PatFrag truncFrag, PatFrag mtruncFrag, Predicate prd = HasAVX512>{ let Predicates = [HasVLX, prd] in { defm Z128: avx512_trunc_common, avx512_trunc_mr_lowering, EVEX_V128; defm Z256: avx512_trunc_common, avx512_trunc_mr_lowering, EVEX_V256; } let Predicates = [prd] in defm Z: avx512_trunc_common, avx512_trunc_mr_lowering, EVEX_V512; } multiclass avx512_trunc_sat opc, string OpcodeStr, SDNode OpNode, AVX512VLVectorVTInfo VTSrcInfo, X86VectorVTInfo DestInfoZ128, X86VectorVTInfo DestInfoZ256, X86VectorVTInfo DestInfoZ, X86MemOperand x86memopZ128, X86MemOperand x86memopZ256, X86MemOperand x86memopZ, string sat, Predicate prd = HasAVX512>{ let Predicates = [HasVLX, prd] in { defm Z128: avx512_trunc_common, avx512_trunc_sat_mr_lowering, EVEX_V128; defm Z256: avx512_trunc_common, avx512_trunc_sat_mr_lowering, EVEX_V256; } let Predicates = [prd] in defm Z: avx512_trunc_common, avx512_trunc_sat_mr_lowering, EVEX_V512; } multiclass avx512_trunc_qb opc, string OpcodeStr, SDNode OpNode> { defm NAME: avx512_trunc, EVEX_CD8<8, CD8VO>; } multiclass avx512_trunc_sat_qb opc, string sat, SDNode OpNode> { defm NAME: avx512_trunc_sat, EVEX_CD8<8, CD8VO>; } multiclass avx512_trunc_qw opc, string OpcodeStr, SDNode OpNode> { defm NAME: avx512_trunc, EVEX_CD8<16, CD8VQ>; } multiclass avx512_trunc_sat_qw opc, string sat, SDNode OpNode> { defm NAME: avx512_trunc_sat, EVEX_CD8<16, CD8VQ>; } multiclass avx512_trunc_qd opc, string OpcodeStr, SDNode OpNode> { defm NAME: avx512_trunc, EVEX_CD8<32, CD8VH>; } multiclass avx512_trunc_sat_qd opc, string sat, SDNode OpNode> { defm NAME: avx512_trunc_sat, EVEX_CD8<32, CD8VH>; } multiclass avx512_trunc_db opc, string OpcodeStr, SDNode OpNode> { defm NAME: avx512_trunc, EVEX_CD8<8, CD8VQ>; } multiclass avx512_trunc_sat_db opc, string sat, SDNode OpNode> { defm NAME: avx512_trunc_sat, EVEX_CD8<8, CD8VQ>; } multiclass avx512_trunc_dw opc, string OpcodeStr, SDNode OpNode> { defm NAME: avx512_trunc, EVEX_CD8<16, CD8VH>; } multiclass avx512_trunc_sat_dw opc, string sat, SDNode OpNode> { defm NAME: avx512_trunc_sat, EVEX_CD8<16, CD8VH>; } multiclass avx512_trunc_wb opc, string OpcodeStr, SDNode OpNode> { defm NAME: avx512_trunc, EVEX_CD8<16, CD8VH>; } multiclass avx512_trunc_sat_wb opc, string sat, SDNode OpNode> { defm NAME: avx512_trunc_sat, EVEX_CD8<16, CD8VH>; } defm VPMOVQB : avx512_trunc_qb<0x32, "vpmovqb", X86vtrunc>; defm VPMOVSQB : avx512_trunc_sat_qb<0x22, "s", X86vtruncs>; defm VPMOVUSQB : avx512_trunc_sat_qb<0x12, "us", X86vtruncus>; defm VPMOVQW : avx512_trunc_qw<0x34, "vpmovqw", X86vtrunc>; defm VPMOVSQW : avx512_trunc_sat_qw<0x24, "s", X86vtruncs>; defm VPMOVUSQW : avx512_trunc_sat_qw<0x14, "us", X86vtruncus>; defm VPMOVQD : avx512_trunc_qd<0x35, "vpmovqd", X86vtrunc>; defm VPMOVSQD : avx512_trunc_sat_qd<0x25, "s", X86vtruncs>; defm VPMOVUSQD : avx512_trunc_sat_qd<0x15, "us", X86vtruncus>; defm VPMOVDB : avx512_trunc_db<0x31, "vpmovdb", X86vtrunc>; defm VPMOVSDB : avx512_trunc_sat_db<0x21, "s", X86vtruncs>; defm VPMOVUSDB : avx512_trunc_sat_db<0x11, "us", X86vtruncus>; defm VPMOVDW : avx512_trunc_dw<0x33, "vpmovdw", X86vtrunc>; defm VPMOVSDW : avx512_trunc_sat_dw<0x23, "s", X86vtruncs>; defm VPMOVUSDW : avx512_trunc_sat_dw<0x13, "us", X86vtruncus>; defm VPMOVWB : avx512_trunc_wb<0x30, "vpmovwb", X86vtrunc>; defm VPMOVSWB : avx512_trunc_sat_wb<0x20, "s", X86vtruncs>; defm VPMOVUSWB : avx512_trunc_sat_wb<0x10, "us", X86vtruncus>; let Predicates = [HasAVX512, NoVLX] in { def: Pat<(v8i16 (X86vtrunc (v8i32 VR256X:$src))), (v8i16 (EXTRACT_SUBREG (v16i16 (VPMOVDWZrr (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src, sub_ymm)))), sub_xmm))>; def: Pat<(v4i32 (X86vtrunc (v4i64 VR256X:$src))), (v4i32 (EXTRACT_SUBREG (v8i32 (VPMOVQDZrr (v8i64 (SUBREG_TO_REG (i32 0), VR256X:$src, sub_ymm)))), sub_xmm))>; } let Predicates = [HasBWI, NoVLX] in { def: Pat<(v16i8 (X86vtrunc (v16i16 VR256X:$src))), (v16i8 (EXTRACT_SUBREG (VPMOVWBZrr (v32i16 (SUBREG_TO_REG (i32 0), VR256X:$src, sub_ymm))), sub_xmm))>; } multiclass avx512_extend_common opc, string OpcodeStr, X86VectorVTInfo DestInfo, X86VectorVTInfo SrcInfo, X86MemOperand x86memop, PatFrag LdFrag, SDNode OpNode>{ defm rr : AVX512_maskable, EVEX; let mayLoad = 1 in { defm rm : AVX512_maskable, EVEX; } } multiclass avx512_extend_BW opc, string OpcodeStr, SDNode OpNode, string ExtTy,PatFrag LdFrag = !cast(ExtTy#"extloadvi8")> { let Predicates = [HasVLX, HasBWI] in { defm Z128: avx512_extend_common, EVEX_CD8<8, CD8VH>, T8PD, EVEX_V128; defm Z256: avx512_extend_common, EVEX_CD8<8, CD8VH>, T8PD, EVEX_V256; } let Predicates = [HasBWI] in { defm Z : avx512_extend_common, EVEX_CD8<8, CD8VH>, T8PD, EVEX_V512; } } multiclass avx512_extend_BD opc, string OpcodeStr, SDNode OpNode, string ExtTy,PatFrag LdFrag = !cast(ExtTy#"extloadvi8")> { let Predicates = [HasVLX, HasAVX512] in { defm Z128: avx512_extend_common, EVEX_CD8<8, CD8VQ>, T8PD, EVEX_V128; defm Z256: avx512_extend_common, EVEX_CD8<8, CD8VQ>, T8PD, EVEX_V256; } let Predicates = [HasAVX512] in { defm Z : avx512_extend_common, EVEX_CD8<8, CD8VQ>, T8PD, EVEX_V512; } } multiclass avx512_extend_BQ opc, string OpcodeStr, SDNode OpNode, string ExtTy,PatFrag LdFrag = !cast(ExtTy#"extloadvi8")> { let Predicates = [HasVLX, HasAVX512] in { defm Z128: avx512_extend_common, EVEX_CD8<8, CD8VO>, T8PD, EVEX_V128; defm Z256: avx512_extend_common, EVEX_CD8<8, CD8VO>, T8PD, EVEX_V256; } let Predicates = [HasAVX512] in { defm Z : avx512_extend_common, EVEX_CD8<8, CD8VO>, T8PD, EVEX_V512; } } multiclass avx512_extend_WD opc, string OpcodeStr, SDNode OpNode, string ExtTy,PatFrag LdFrag = !cast(ExtTy#"extloadvi16")> { let Predicates = [HasVLX, HasAVX512] in { defm Z128: avx512_extend_common, EVEX_CD8<16, CD8VH>, T8PD, EVEX_V128; defm Z256: avx512_extend_common, EVEX_CD8<16, CD8VH>, T8PD, EVEX_V256; } let Predicates = [HasAVX512] in { defm Z : avx512_extend_common, EVEX_CD8<16, CD8VH>, T8PD, EVEX_V512; } } multiclass avx512_extend_WQ opc, string OpcodeStr, SDNode OpNode, string ExtTy,PatFrag LdFrag = !cast(ExtTy#"extloadvi16")> { let Predicates = [HasVLX, HasAVX512] in { defm Z128: avx512_extend_common, EVEX_CD8<16, CD8VQ>, T8PD, EVEX_V128; defm Z256: avx512_extend_common, EVEX_CD8<16, CD8VQ>, T8PD, EVEX_V256; } let Predicates = [HasAVX512] in { defm Z : avx512_extend_common, EVEX_CD8<16, CD8VQ>, T8PD, EVEX_V512; } } multiclass avx512_extend_DQ opc, string OpcodeStr, SDNode OpNode, string ExtTy,PatFrag LdFrag = !cast(ExtTy#"extloadvi32")> { let Predicates = [HasVLX, HasAVX512] in { defm Z128: avx512_extend_common, EVEX_CD8<32, CD8VH>, T8PD, EVEX_V128; defm Z256: avx512_extend_common, EVEX_CD8<32, CD8VH>, T8PD, EVEX_V256; } let Predicates = [HasAVX512] in { defm Z : avx512_extend_common, EVEX_CD8<32, CD8VH>, T8PD, EVEX_V512; } } defm VPMOVZXBW : avx512_extend_BW<0x30, "vpmovzxbw", X86vzext, "z">; defm VPMOVZXBD : avx512_extend_BD<0x31, "vpmovzxbd", X86vzext, "z">; defm VPMOVZXBQ : avx512_extend_BQ<0x32, "vpmovzxbq", X86vzext, "z">; defm VPMOVZXWD : avx512_extend_WD<0x33, "vpmovzxwd", X86vzext, "z">; defm VPMOVZXWQ : avx512_extend_WQ<0x34, "vpmovzxwq", X86vzext, "z">; defm VPMOVZXDQ : avx512_extend_DQ<0x35, "vpmovzxdq", X86vzext, "z">; defm VPMOVSXBW: avx512_extend_BW<0x20, "vpmovsxbw", X86vsext, "s">; defm VPMOVSXBD: avx512_extend_BD<0x21, "vpmovsxbd", X86vsext, "s">; defm VPMOVSXBQ: avx512_extend_BQ<0x22, "vpmovsxbq", X86vsext, "s">; defm VPMOVSXWD: avx512_extend_WD<0x23, "vpmovsxwd", X86vsext, "s">; defm VPMOVSXWQ: avx512_extend_WQ<0x24, "vpmovsxwq", X86vsext, "s">; defm VPMOVSXDQ: avx512_extend_DQ<0x25, "vpmovsxdq", X86vsext, "s">; //===----------------------------------------------------------------------===// // GATHER - SCATTER Operations multiclass avx512_gather opc, string OpcodeStr, X86VectorVTInfo _, X86MemOperand memop, PatFrag GatherNode> { let Constraints = "@earlyclobber $dst, $src1 = $dst, $mask = $mask_wb", ExeDomain = _.ExeDomain in def rm : AVX5128I, EVEX, EVEX_K, EVEX_CD8<_.EltSize, CD8VT1>; } multiclass avx512_gather_q_pd dopc, bits<8> qopc, AVX512VLVectorVTInfo _, string OpcodeStr, string SUFF> { defm NAME##D##SUFF##Z: avx512_gather, EVEX_V512, VEX_W; defm NAME##Q##SUFF##Z: avx512_gather, EVEX_V512, VEX_W; let Predicates = [HasVLX] in { defm NAME##D##SUFF##Z256: avx512_gather, EVEX_V256, VEX_W; defm NAME##Q##SUFF##Z256: avx512_gather, EVEX_V256, VEX_W; defm NAME##D##SUFF##Z128: avx512_gather, EVEX_V128, VEX_W; defm NAME##Q##SUFF##Z128: avx512_gather, EVEX_V128, VEX_W; } } multiclass avx512_gather_d_ps dopc, bits<8> qopc, AVX512VLVectorVTInfo _, string OpcodeStr, string SUFF> { defm NAME##D##SUFF##Z: avx512_gather, EVEX_V512; defm NAME##Q##SUFF##Z: avx512_gather, EVEX_V512; let Predicates = [HasVLX] in { defm NAME##D##SUFF##Z256: avx512_gather, EVEX_V256; defm NAME##Q##SUFF##Z256: avx512_gather, EVEX_V256; defm NAME##D##SUFF##Z128: avx512_gather, EVEX_V128; defm NAME##Q##SUFF##Z128: avx512_gather, EVEX_V128; } } defm VGATHER : avx512_gather_q_pd<0x92, 0x93, avx512vl_f64_info, "vgather", "PD">, avx512_gather_d_ps<0x92, 0x93, avx512vl_f32_info, "vgather", "PS">; defm VPGATHER : avx512_gather_q_pd<0x90, 0x91, avx512vl_i64_info, "vpgather", "Q">, avx512_gather_d_ps<0x90, 0x91, avx512vl_i32_info, "vpgather", "D">; multiclass avx512_scatter opc, string OpcodeStr, X86VectorVTInfo _, X86MemOperand memop, PatFrag ScatterNode> { let mayStore = 1, Constraints = "$mask = $mask_wb", ExeDomain = _.ExeDomain in def mr : AVX5128I, EVEX, EVEX_K, EVEX_CD8<_.EltSize, CD8VT1>; } multiclass avx512_scatter_q_pd dopc, bits<8> qopc, AVX512VLVectorVTInfo _, string OpcodeStr, string SUFF> { defm NAME##D##SUFF##Z: avx512_scatter, EVEX_V512, VEX_W; defm NAME##Q##SUFF##Z: avx512_scatter, EVEX_V512, VEX_W; let Predicates = [HasVLX] in { defm NAME##D##SUFF##Z256: avx512_scatter, EVEX_V256, VEX_W; defm NAME##Q##SUFF##Z256: avx512_scatter, EVEX_V256, VEX_W; defm NAME##D##SUFF##Z128: avx512_scatter, EVEX_V128, VEX_W; defm NAME##Q##SUFF##Z128: avx512_scatter, EVEX_V128, VEX_W; } } multiclass avx512_scatter_d_ps dopc, bits<8> qopc, AVX512VLVectorVTInfo _, string OpcodeStr, string SUFF> { defm NAME##D##SUFF##Z: avx512_scatter, EVEX_V512; defm NAME##Q##SUFF##Z: avx512_scatter, EVEX_V512; let Predicates = [HasVLX] in { defm NAME##D##SUFF##Z256: avx512_scatter, EVEX_V256; defm NAME##Q##SUFF##Z256: avx512_scatter, EVEX_V256; defm NAME##D##SUFF##Z128: avx512_scatter, EVEX_V128; defm NAME##Q##SUFF##Z128: avx512_scatter, EVEX_V128; } } defm VSCATTER : avx512_scatter_q_pd<0xA2, 0xA3, avx512vl_f64_info, "vscatter", "PD">, avx512_scatter_d_ps<0xA2, 0xA3, avx512vl_f32_info, "vscatter", "PS">; defm VPSCATTER : avx512_scatter_q_pd<0xA0, 0xA1, avx512vl_i64_info, "vpscatter", "Q">, avx512_scatter_d_ps<0xA0, 0xA1, avx512vl_i32_info, "vpscatter", "D">; // prefetch multiclass avx512_gather_scatter_prefetch opc, Format F, string OpcodeStr, RegisterClass KRC, X86MemOperand memop> { let Predicates = [HasPFI], hasSideEffects = 1 in def m : AVX5128I, EVEX, EVEX_K; } defm VGATHERPF0DPS: avx512_gather_scatter_prefetch<0xC6, MRM1m, "vgatherpf0dps", VK16WM, vz32mem>, EVEX_V512, EVEX_CD8<32, CD8VT1>; defm VGATHERPF0QPS: avx512_gather_scatter_prefetch<0xC7, MRM1m, "vgatherpf0qps", VK8WM, vz64mem>, EVEX_V512, EVEX_CD8<64, CD8VT1>; defm VGATHERPF0DPD: avx512_gather_scatter_prefetch<0xC6, MRM1m, "vgatherpf0dpd", VK8WM, vy32mem>, EVEX_V512, VEX_W, EVEX_CD8<32, CD8VT1>; defm VGATHERPF0QPD: avx512_gather_scatter_prefetch<0xC7, MRM1m, "vgatherpf0qpd", VK8WM, vz64mem>, EVEX_V512, VEX_W, EVEX_CD8<64, CD8VT1>; defm VGATHERPF1DPS: avx512_gather_scatter_prefetch<0xC6, MRM2m, "vgatherpf1dps", VK16WM, vz32mem>, EVEX_V512, EVEX_CD8<32, CD8VT1>; defm VGATHERPF1QPS: avx512_gather_scatter_prefetch<0xC7, MRM2m, "vgatherpf1qps", VK8WM, vz64mem>, EVEX_V512, EVEX_CD8<64, CD8VT1>; defm VGATHERPF1DPD: avx512_gather_scatter_prefetch<0xC6, MRM2m, "vgatherpf1dpd", VK8WM, vy32mem>, EVEX_V512, VEX_W, EVEX_CD8<32, CD8VT1>; defm VGATHERPF1QPD: avx512_gather_scatter_prefetch<0xC7, MRM2m, "vgatherpf1qpd", VK8WM, vz64mem>, EVEX_V512, VEX_W, EVEX_CD8<64, CD8VT1>; defm VSCATTERPF0DPS: avx512_gather_scatter_prefetch<0xC6, MRM5m, "vscatterpf0dps", VK16WM, vz32mem>, EVEX_V512, EVEX_CD8<32, CD8VT1>; defm VSCATTERPF0QPS: avx512_gather_scatter_prefetch<0xC7, MRM5m, "vscatterpf0qps", VK8WM, vz64mem>, EVEX_V512, EVEX_CD8<64, CD8VT1>; defm VSCATTERPF0DPD: avx512_gather_scatter_prefetch<0xC6, MRM5m, "vscatterpf0dpd", VK8WM, vy32mem>, EVEX_V512, VEX_W, EVEX_CD8<32, CD8VT1>; defm VSCATTERPF0QPD: avx512_gather_scatter_prefetch<0xC7, MRM5m, "vscatterpf0qpd", VK8WM, vz64mem>, EVEX_V512, VEX_W, EVEX_CD8<64, CD8VT1>; defm VSCATTERPF1DPS: avx512_gather_scatter_prefetch<0xC6, MRM6m, "vscatterpf1dps", VK16WM, vz32mem>, EVEX_V512, EVEX_CD8<32, CD8VT1>; defm VSCATTERPF1QPS: avx512_gather_scatter_prefetch<0xC7, MRM6m, "vscatterpf1qps", VK8WM, vz64mem>, EVEX_V512, EVEX_CD8<64, CD8VT1>; defm VSCATTERPF1DPD: avx512_gather_scatter_prefetch<0xC6, MRM6m, "vscatterpf1dpd", VK8WM, vy32mem>, EVEX_V512, VEX_W, EVEX_CD8<32, CD8VT1>; defm VSCATTERPF1QPD: avx512_gather_scatter_prefetch<0xC7, MRM6m, "vscatterpf1qpd", VK8WM, vz64mem>, EVEX_V512, VEX_W, EVEX_CD8<64, CD8VT1>; // Helper fragments to match sext vXi1 to vXiY. def v16i1sextv16i32 : PatLeaf<(v16i32 (X86vsrai VR512:$src, (i8 31)))>; def v8i1sextv8i64 : PatLeaf<(v8i64 (X86vsrai VR512:$src, (i8 63)))>; def : Pat<(store (i1 -1), addr:$dst), (MOV8mi addr:$dst, (i8 1))>; def : Pat<(store (i1 1), addr:$dst), (MOV8mi addr:$dst, (i8 1))>; def : Pat<(store (i1 0), addr:$dst), (MOV8mi addr:$dst, (i8 0))>; def : Pat<(store VK1:$src, addr:$dst), (MOV8mr addr:$dst, (EXTRACT_SUBREG (KMOVWrk (COPY_TO_REGCLASS VK1:$src, VK16)), sub_8bit))>, Requires<[HasAVX512, NoDQI]>; def : Pat<(store VK8:$src, addr:$dst), (MOV8mr addr:$dst, (EXTRACT_SUBREG (KMOVWrk (COPY_TO_REGCLASS VK8:$src, VK16)), sub_8bit))>, Requires<[HasAVX512, NoDQI]>; def truncstorei1 : PatFrag<(ops node:$val, node:$ptr), (truncstore node:$val, node:$ptr), [{ return cast(N)->getMemoryVT() == MVT::i1; }]>; def : Pat<(truncstorei1 GR8:$src, addr:$dst), (MOV8mr addr:$dst, GR8:$src)>; multiclass cvt_by_vec_width opc, X86VectorVTInfo Vec, string OpcodeStr > { def rr : AVX512XS8I, EVEX; } multiclass cvt_mask_by_elt_width opc, AVX512VLVectorVTInfo VTInfo, string OpcodeStr, Predicate prd> { let Predicates = [prd] in defm Z : cvt_by_vec_width, EVEX_V512; let Predicates = [prd, HasVLX] in { defm Z256 : cvt_by_vec_width, EVEX_V256; defm Z128 : cvt_by_vec_width, EVEX_V128; } } multiclass avx512_convert_mask_to_vector { defm NAME##B : cvt_mask_by_elt_width<0x28, avx512vl_i8_info, OpcodeStr, HasBWI>; defm NAME##W : cvt_mask_by_elt_width<0x28, avx512vl_i16_info, OpcodeStr, HasBWI>, VEX_W; defm NAME##D : cvt_mask_by_elt_width<0x38, avx512vl_i32_info, OpcodeStr, HasDQI>; defm NAME##Q : cvt_mask_by_elt_width<0x38, avx512vl_i64_info, OpcodeStr, HasDQI>, VEX_W; } defm VPMOVM2 : avx512_convert_mask_to_vector<"vpmovm2">; multiclass convert_vector_to_mask_common opc, X86VectorVTInfo _, string OpcodeStr > { def rr : AVX512XS8I, EVEX; } multiclass avx512_convert_vector_to_mask opc, string OpcodeStr, AVX512VLVectorVTInfo VTInfo, Predicate prd> { let Predicates = [prd] in defm Z : convert_vector_to_mask_common , EVEX_V512; let Predicates = [prd, HasVLX] in { defm Z256 : convert_vector_to_mask_common, EVEX_V256; defm Z128 : convert_vector_to_mask_common, EVEX_V128; } } defm VPMOVB2M : avx512_convert_vector_to_mask<0x29, "vpmovb2m", avx512vl_i8_info, HasBWI>; defm VPMOVW2M : avx512_convert_vector_to_mask<0x29, "vpmovw2m", avx512vl_i16_info, HasBWI>, VEX_W; defm VPMOVD2M : avx512_convert_vector_to_mask<0x39, "vpmovd2m", avx512vl_i32_info, HasDQI>; defm VPMOVQ2M : avx512_convert_vector_to_mask<0x39, "vpmovq2m", avx512vl_i64_info, HasDQI>, VEX_W; //===----------------------------------------------------------------------===// // AVX-512 - COMPRESS and EXPAND // multiclass compress_by_vec_width opc, X86VectorVTInfo _, string OpcodeStr> { defm rr : AVX512_maskable, AVX5128IBase; let mayStore = 1 in { def mr : AVX5128I, EVEX_CD8<_.EltSize, CD8VT1>; def mrk : AVX5128I, EVEX_K, EVEX_CD8<_.EltSize, CD8VT1>; } } multiclass compress_by_elt_width opc, string OpcodeStr, AVX512VLVectorVTInfo VTInfo> { defm Z : compress_by_vec_width, EVEX_V512; let Predicates = [HasVLX] in { defm Z256 : compress_by_vec_width, EVEX_V256; defm Z128 : compress_by_vec_width, EVEX_V128; } } defm VPCOMPRESSD : compress_by_elt_width <0x8B, "vpcompressd", avx512vl_i32_info>, EVEX; defm VPCOMPRESSQ : compress_by_elt_width <0x8B, "vpcompressq", avx512vl_i64_info>, EVEX, VEX_W; defm VCOMPRESSPS : compress_by_elt_width <0x8A, "vcompressps", avx512vl_f32_info>, EVEX; defm VCOMPRESSPD : compress_by_elt_width <0x8A, "vcompresspd", avx512vl_f64_info>, EVEX, VEX_W; // expand multiclass expand_by_vec_width opc, X86VectorVTInfo _, string OpcodeStr> { defm rr : AVX512_maskable, AVX5128IBase; let mayLoad = 1 in defm rm : AVX512_maskable, AVX5128IBase, EVEX_CD8<_.EltSize, CD8VT1>; } multiclass expand_by_elt_width opc, string OpcodeStr, AVX512VLVectorVTInfo VTInfo> { defm Z : expand_by_vec_width, EVEX_V512; let Predicates = [HasVLX] in { defm Z256 : expand_by_vec_width, EVEX_V256; defm Z128 : expand_by_vec_width, EVEX_V128; } } defm VPEXPANDD : expand_by_elt_width <0x89, "vpexpandd", avx512vl_i32_info>, EVEX; defm VPEXPANDQ : expand_by_elt_width <0x89, "vpexpandq", avx512vl_i64_info>, EVEX, VEX_W; defm VEXPANDPS : expand_by_elt_width <0x88, "vexpandps", avx512vl_f32_info>, EVEX; defm VEXPANDPD : expand_by_elt_width <0x88, "vexpandpd", avx512vl_f64_info>, EVEX, VEX_W; //handle instruction reg_vec1 = op(reg_vec,imm) // op(mem_vec,imm) // op(broadcast(eltVt),imm) //all instruction created with FROUND_CURRENT multiclass avx512_unary_fp_packed_imm opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _>{ defm rri : AVX512_maskable; let mayLoad = 1 in { defm rmi : AVX512_maskable; defm rmbi : AVX512_maskable, EVEX_B; } } //handle instruction reg_vec1 = op(reg_vec2,reg_vec3,imm),{sae} multiclass avx512_unary_fp_sae_packed_imm opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _>{ defm rrib : AVX512_maskable, EVEX_B; } multiclass avx512_common_unary_fp_sae_packed_imm opc, SDNode OpNode, Predicate prd>{ let Predicates = [prd] in { defm Z : avx512_unary_fp_packed_imm, avx512_unary_fp_sae_packed_imm, EVEX_V512; } let Predicates = [prd, HasVLX] in { defm Z128 : avx512_unary_fp_packed_imm, EVEX_V128; defm Z256 : avx512_unary_fp_packed_imm, EVEX_V256; } } //handle instruction reg_vec1 = op(reg_vec2,reg_vec3,imm) // op(reg_vec2,mem_vec,imm) // op(reg_vec2,broadcast(eltVt),imm) //all instruction created with FROUND_CURRENT multiclass avx512_fp_packed_imm opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _>{ defm rri : AVX512_maskable; let mayLoad = 1 in { defm rmi : AVX512_maskable; defm rmbi : AVX512_maskable, EVEX_B; } } //handle instruction reg_vec1 = op(reg_vec2,reg_vec3,imm) // op(reg_vec2,mem_vec,imm) multiclass avx512_3Op_rm_imm8 opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo DestInfo, X86VectorVTInfo SrcInfo>{ defm rri : AVX512_maskable; let mayLoad = 1 in defm rmi : AVX512_maskable; } //handle instruction reg_vec1 = op(reg_vec2,reg_vec3,imm) // op(reg_vec2,mem_vec,imm) // op(reg_vec2,broadcast(eltVt),imm) multiclass avx512_3Op_imm8 opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _>: avx512_3Op_rm_imm8{ let mayLoad = 1 in defm rmbi : AVX512_maskable, EVEX_B; } //handle scalar instruction reg_vec1 = op(reg_vec2,reg_vec3,imm) // op(reg_vec2,mem_scalar,imm) //all instruction created with FROUND_CURRENT multiclass avx512_fp_scalar_imm opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { defm rri : AVX512_maskable_scalar; let mayLoad = 1 in { defm rmi : AVX512_maskable_scalar; let isAsmParserOnly = 1 in { defm rmi_alt :AVX512_maskable_in_asm; } } } //handle instruction reg_vec1 = op(reg_vec2,reg_vec3,imm),{sae} multiclass avx512_fp_sae_packed_imm opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _>{ defm rrib : AVX512_maskable, EVEX_B; } //handle scalar instruction reg_vec1 = op(reg_vec2,reg_vec3,imm),{sae} multiclass avx512_fp_sae_scalar_imm opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { defm NAME#rrib : AVX512_maskable_scalar, EVEX_B; } multiclass avx512_common_fp_sae_packed_imm opc, SDNode OpNode, Predicate prd>{ let Predicates = [prd] in { defm Z : avx512_fp_packed_imm, avx512_fp_sae_packed_imm, EVEX_V512; } let Predicates = [prd, HasVLX] in { defm Z128 : avx512_fp_packed_imm, EVEX_V128; defm Z256 : avx512_fp_packed_imm, EVEX_V256; } } multiclass avx512_common_3Op_rm_imm8 opc, SDNode OpNode, string OpStr, AVX512VLVectorVTInfo DestInfo, AVX512VLVectorVTInfo SrcInfo>{ let Predicates = [HasBWI] in { defm Z : avx512_3Op_rm_imm8, EVEX_V512, AVX512AIi8Base, EVEX_4V; } let Predicates = [HasBWI, HasVLX] in { defm Z128 : avx512_3Op_rm_imm8, EVEX_V128, AVX512AIi8Base, EVEX_4V; defm Z256 : avx512_3Op_rm_imm8, EVEX_V256, AVX512AIi8Base, EVEX_4V; } } multiclass avx512_common_3Op_imm8 opc, SDNode OpNode>{ let Predicates = [HasAVX512] in { defm Z : avx512_3Op_imm8, EVEX_V512; } let Predicates = [HasAVX512, HasVLX] in { defm Z128 : avx512_3Op_imm8, EVEX_V128; defm Z256 : avx512_3Op_imm8, EVEX_V256; } } multiclass avx512_common_fp_sae_scalar_imm opc, SDNode OpNode, Predicate prd>{ let Predicates = [prd] in { defm Z128 : avx512_fp_scalar_imm, avx512_fp_sae_scalar_imm; } } multiclass avx512_common_unary_fp_sae_packed_imm_all opcPs, bits<8> opcPd, SDNode OpNode, Predicate prd>{ defm PS : avx512_common_unary_fp_sae_packed_imm, EVEX_CD8<32, CD8VF>; defm PD : avx512_common_unary_fp_sae_packed_imm, EVEX_CD8<64, CD8VF>, VEX_W; } defm VFIXUPIMMPD : avx512_common_fp_sae_packed_imm<"vfixupimmpd", avx512vl_f64_info, 0x54, X86VFixupimm, HasAVX512>, AVX512AIi8Base, EVEX_4V, EVEX_CD8<64, CD8VF>, VEX_W; defm VFIXUPIMMPS : avx512_common_fp_sae_packed_imm<"vfixupimmps", avx512vl_f32_info, 0x54, X86VFixupimm, HasAVX512>, AVX512AIi8Base, EVEX_4V, EVEX_CD8<32, CD8VF>; defm VFIXUPIMMSD: avx512_common_fp_sae_scalar_imm<"vfixupimmsd", f64x_info, 0x55, X86VFixupimm, HasAVX512>, AVX512AIi8Base, VEX_LIG, EVEX_4V, EVEX_CD8<64, CD8VT1>, VEX_W; defm VFIXUPIMMSS: avx512_common_fp_sae_scalar_imm<"vfixupimmss", f32x_info, 0x55, X86VFixupimm, HasAVX512>, AVX512AIi8Base, VEX_LIG, EVEX_4V, EVEX_CD8<32, CD8VT1>; defm VREDUCE : avx512_common_unary_fp_sae_packed_imm_all<"vreduce", 0x56, 0x56, X86VReduce, HasDQI>, AVX512AIi8Base, EVEX; defm VRNDSCALE : avx512_common_unary_fp_sae_packed_imm_all<"vrndscale", 0x08, 0x09, X86VRndScale, HasAVX512>, AVX512AIi8Base, EVEX; defm VGETMANT : avx512_common_unary_fp_sae_packed_imm_all<"vgetmant", 0x26, 0x26, X86VGetMant, HasAVX512>, AVX512AIi8Base, EVEX; defm VRANGEPD : avx512_common_fp_sae_packed_imm<"vrangepd", avx512vl_f64_info, 0x50, X86VRange, HasDQI>, AVX512AIi8Base, EVEX_4V, EVEX_CD8<64, CD8VF>, VEX_W; defm VRANGEPS : avx512_common_fp_sae_packed_imm<"vrangeps", avx512vl_f32_info, 0x50, X86VRange, HasDQI>, AVX512AIi8Base, EVEX_4V, EVEX_CD8<32, CD8VF>; defm VRANGESD: avx512_common_fp_sae_scalar_imm<"vrangesd", f64x_info, 0x51, X86VRange, HasDQI>, AVX512AIi8Base, VEX_LIG, EVEX_4V, EVEX_CD8<64, CD8VT1>, VEX_W; defm VRANGESS: avx512_common_fp_sae_scalar_imm<"vrangess", f32x_info, 0x51, X86VRange, HasDQI>, AVX512AIi8Base, VEX_LIG, EVEX_4V, EVEX_CD8<32, CD8VT1>; defm VREDUCESD: avx512_common_fp_sae_scalar_imm<"vreducesd", f64x_info, 0x57, X86Reduces, HasDQI>, AVX512AIi8Base, VEX_LIG, EVEX_4V, EVEX_CD8<64, CD8VT1>, VEX_W; defm VREDUCESS: avx512_common_fp_sae_scalar_imm<"vreducess", f32x_info, 0x57, X86Reduces, HasDQI>, AVX512AIi8Base, VEX_LIG, EVEX_4V, EVEX_CD8<32, CD8VT1>; defm VGETMANTSD: avx512_common_fp_sae_scalar_imm<"vgetmantsd", f64x_info, 0x27, X86GetMants, HasAVX512>, AVX512AIi8Base, VEX_LIG, EVEX_4V, EVEX_CD8<64, CD8VT1>, VEX_W; defm VGETMANTSS: avx512_common_fp_sae_scalar_imm<"vgetmantss", f32x_info, 0x27, X86GetMants, HasAVX512>, AVX512AIi8Base, VEX_LIG, EVEX_4V, EVEX_CD8<32, CD8VT1>; multiclass avx512_shuff_packed_128 opc, SDNode OpNode = X86Shuf128>{ let Predicates = [HasAVX512] in { defm Z : avx512_3Op_imm8, EVEX_V512; } let Predicates = [HasAVX512, HasVLX] in { defm Z256 : avx512_3Op_imm8, EVEX_V256; } } let Predicates = [HasAVX512] in { def : Pat<(v16f32 (ffloor VR512:$src)), (VRNDSCALEPSZrri VR512:$src, (i32 0x1))>; def : Pat<(v16f32 (fnearbyint VR512:$src)), (VRNDSCALEPSZrri VR512:$src, (i32 0xC))>; def : Pat<(v16f32 (fceil VR512:$src)), (VRNDSCALEPSZrri VR512:$src, (i32 0x2))>; def : Pat<(v16f32 (frint VR512:$src)), (VRNDSCALEPSZrri VR512:$src, (i32 0x4))>; def : Pat<(v16f32 (ftrunc VR512:$src)), (VRNDSCALEPSZrri VR512:$src, (i32 0x3))>; def : Pat<(v8f64 (ffloor VR512:$src)), (VRNDSCALEPDZrri VR512:$src, (i32 0x1))>; def : Pat<(v8f64 (fnearbyint VR512:$src)), (VRNDSCALEPDZrri VR512:$src, (i32 0xC))>; def : Pat<(v8f64 (fceil VR512:$src)), (VRNDSCALEPDZrri VR512:$src, (i32 0x2))>; def : Pat<(v8f64 (frint VR512:$src)), (VRNDSCALEPDZrri VR512:$src, (i32 0x4))>; def : Pat<(v8f64 (ftrunc VR512:$src)), (VRNDSCALEPDZrri VR512:$src, (i32 0x3))>; } defm VSHUFF32X4 : avx512_shuff_packed_128<"vshuff32x4",avx512vl_f32_info, 0x23>, AVX512AIi8Base, EVEX_4V, EVEX_CD8<32, CD8VF>; defm VSHUFF64X2 : avx512_shuff_packed_128<"vshuff64x2",avx512vl_f64_info, 0x23>, AVX512AIi8Base, EVEX_4V, EVEX_CD8<64, CD8VF>, VEX_W; defm VSHUFI32X4 : avx512_shuff_packed_128<"vshufi32x4",avx512vl_i32_info, 0x43>, AVX512AIi8Base, EVEX_4V, EVEX_CD8<32, CD8VF>; defm VSHUFI64X2 : avx512_shuff_packed_128<"vshufi64x2",avx512vl_i64_info, 0x43>, AVX512AIi8Base, EVEX_4V, EVEX_CD8<64, CD8VF>, VEX_W; multiclass avx512_valign { defm NAME: avx512_common_3Op_imm8, AVX512AIi8Base, EVEX_4V; } defm VALIGND: avx512_valign<"valignd", avx512vl_i32_info>, EVEX_CD8<32, CD8VF>; defm VALIGNQ: avx512_valign<"valignq", avx512vl_i64_info>, EVEX_CD8<64, CD8VF>, VEX_W; multiclass avx512_vpalign_lowering p>{ let Predicates = p in def NAME#_.VTName#rri: Pat<(_.VT (X86PAlignr _.RC:$src1, _.RC:$src2, (i8 imm:$imm))), (!cast(NAME#_.ZSuffix#rri) _.RC:$src1, _.RC:$src2, imm:$imm)>; } multiclass avx512_vpalign_lowering_common: avx512_vpalign_lowering<_.info512, [HasBWI]>, avx512_vpalign_lowering<_.info128, [HasBWI, HasVLX]>, avx512_vpalign_lowering<_.info256, [HasBWI, HasVLX]>; defm VPALIGN: avx512_common_3Op_rm_imm8<0x0F, X86PAlignr, "vpalignr" , avx512vl_i8_info, avx512vl_i8_info>, avx512_vpalign_lowering_common, avx512_vpalign_lowering_common, avx512_vpalign_lowering_common, avx512_vpalign_lowering_common, avx512_vpalign_lowering_common, EVEX_CD8<8, CD8VF>; defm VDBPSADBW: avx512_common_3Op_rm_imm8<0x42, X86dbpsadbw, "vdbpsadbw" , avx512vl_i16_info, avx512vl_i8_info>, EVEX_CD8<8, CD8VF>; multiclass avx512_unary_rm opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { defm rr : AVX512_maskable, EVEX, AVX5128IBase; let mayLoad = 1 in defm rm : AVX512_maskable, EVEX, AVX5128IBase, EVEX_CD8<_.EltSize, CD8VF>; } multiclass avx512_unary_rmb opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> : avx512_unary_rm { let mayLoad = 1 in defm rmb : AVX512_maskable, EVEX, AVX5128IBase, EVEX_B, EVEX_CD8<_.EltSize, CD8VF>; } multiclass avx512_unary_rm_vl opc, string OpcodeStr, SDNode OpNode, AVX512VLVectorVTInfo VTInfo, Predicate prd> { let Predicates = [prd] in defm Z : avx512_unary_rm, EVEX_V512; let Predicates = [prd, HasVLX] in { defm Z256 : avx512_unary_rm, EVEX_V256; defm Z128 : avx512_unary_rm, EVEX_V128; } } multiclass avx512_unary_rmb_vl opc, string OpcodeStr, SDNode OpNode, AVX512VLVectorVTInfo VTInfo, Predicate prd> { let Predicates = [prd] in defm Z : avx512_unary_rmb, EVEX_V512; let Predicates = [prd, HasVLX] in { defm Z256 : avx512_unary_rmb, EVEX_V256; defm Z128 : avx512_unary_rmb, EVEX_V128; } } multiclass avx512_unary_rm_vl_dq opc_d, bits<8> opc_q, string OpcodeStr, SDNode OpNode, Predicate prd> { defm Q : avx512_unary_rmb_vl, VEX_W; defm D : avx512_unary_rmb_vl; } multiclass avx512_unary_rm_vl_bw opc_b, bits<8> opc_w, string OpcodeStr, SDNode OpNode, Predicate prd> { defm W : avx512_unary_rm_vl; defm B : avx512_unary_rm_vl; } multiclass avx512_unary_rm_vl_all opc_b, bits<8> opc_w, bits<8> opc_d, bits<8> opc_q, string OpcodeStr, SDNode OpNode> { defm NAME : avx512_unary_rm_vl_dq, avx512_unary_rm_vl_bw; } defm VPABS : avx512_unary_rm_vl_all<0x1C, 0x1D, 0x1E, 0x1F, "vpabs", X86Abs>; def : Pat<(xor (bc_v16i32 (v16i1sextv16i32)), (bc_v16i32 (add (v16i32 VR512:$src), (v16i1sextv16i32)))), (VPABSDZrr VR512:$src)>; def : Pat<(xor (bc_v8i64 (v8i1sextv8i64)), (bc_v8i64 (add (v8i64 VR512:$src), (v8i1sextv8i64)))), (VPABSQZrr VR512:$src)>; multiclass avx512_ctlz opc, string OpcodeStr, Predicate prd>{ defm NAME : avx512_unary_rm_vl_dq; } defm VPLZCNT : avx512_ctlz<0x44, "vplzcnt", HasCDI>; defm VPCONFLICT : avx512_unary_rm_vl_dq<0xC4, 0xC4, "vpconflict", X86Conflict, HasCDI>; //===---------------------------------------------------------------------===// // Replicate Single FP - MOVSHDUP and MOVSLDUP //===---------------------------------------------------------------------===// multiclass avx512_replicate opc, string OpcodeStr, SDNode OpNode>{ defm NAME: avx512_unary_rm_vl, XS; } defm VMOVSHDUP : avx512_replicate<0x16, "vmovshdup", X86Movshdup>; defm VMOVSLDUP : avx512_replicate<0x12, "vmovsldup", X86Movsldup>; //===----------------------------------------------------------------------===// // AVX-512 - MOVDDUP //===----------------------------------------------------------------------===// multiclass avx512_movddup_128 opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { defm rr : AVX512_maskable, EVEX; let mayLoad = 1 in defm rm : AVX512_maskable, EVEX, EVEX_CD8<_.EltSize, CD8VH>; } multiclass avx512_movddup_common opc, string OpcodeStr, SDNode OpNode, AVX512VLVectorVTInfo VTInfo> { defm Z : avx512_unary_rm, EVEX_V512; let Predicates = [HasAVX512, HasVLX] in { defm Z256 : avx512_unary_rm, EVEX_V256; defm Z128 : avx512_movddup_128, EVEX_V128; } } multiclass avx512_movddup opc, string OpcodeStr, SDNode OpNode>{ defm NAME: avx512_movddup_common, XD, VEX_W; } defm VMOVDDUP : avx512_movddup<0x12, "vmovddup", X86Movddup>; def : Pat<(X86Movddup (loadv2f64 addr:$src)), (VMOVDDUPZ128rm addr:$src)>, Requires<[HasAVX512, HasVLX]>; def : Pat<(v2f64 (X86VBroadcast (loadf64 addr:$src))), (VMOVDDUPZ128rm addr:$src)>, Requires<[HasAVX512, HasVLX]>; //===----------------------------------------------------------------------===// // AVX-512 - Unpack Instructions //===----------------------------------------------------------------------===// defm VUNPCKH : avx512_fp_binop_p<0x15, "vunpckh", X86Unpckh>; defm VUNPCKL : avx512_fp_binop_p<0x14, "vunpckl", X86Unpckl>; defm VPUNPCKLBW : avx512_binop_rm_vl_b<0x60, "vpunpcklbw", X86Unpckl, SSE_INTALU_ITINS_P, HasBWI>; defm VPUNPCKHBW : avx512_binop_rm_vl_b<0x68, "vpunpckhbw", X86Unpckh, SSE_INTALU_ITINS_P, HasBWI>; defm VPUNPCKLWD : avx512_binop_rm_vl_w<0x61, "vpunpcklwd", X86Unpckl, SSE_INTALU_ITINS_P, HasBWI>; defm VPUNPCKHWD : avx512_binop_rm_vl_w<0x69, "vpunpckhwd", X86Unpckh, SSE_INTALU_ITINS_P, HasBWI>; defm VPUNPCKLDQ : avx512_binop_rm_vl_d<0x62, "vpunpckldq", X86Unpckl, SSE_INTALU_ITINS_P, HasAVX512>; defm VPUNPCKHDQ : avx512_binop_rm_vl_d<0x6A, "vpunpckhdq", X86Unpckh, SSE_INTALU_ITINS_P, HasAVX512>; defm VPUNPCKLQDQ : avx512_binop_rm_vl_q<0x6C, "vpunpcklqdq", X86Unpckl, SSE_INTALU_ITINS_P, HasAVX512>; defm VPUNPCKHQDQ : avx512_binop_rm_vl_q<0x6D, "vpunpckhqdq", X86Unpckh, SSE_INTALU_ITINS_P, HasAVX512>; //===----------------------------------------------------------------------===// // AVX-512 - Extract & Insert Integer Instructions //===----------------------------------------------------------------------===// multiclass avx512_extract_elt_bw_m opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> { let mayStore = 1 in def mr : AVX512Ii8, EVEX, EVEX_CD8<_.EltSize, CD8VT1>; } multiclass avx512_extract_elt_b { let Predicates = [HasBWI] in { def rr : AVX512Ii8<0x14, MRMDestReg, (outs GR32orGR64:$dst), (ins _.RC:$src1, u8imm:$src2), OpcodeStr#"\t{$src2, $src1, $dst|$dst, $src1, $src2}", [(set GR32orGR64:$dst, (X86pextrb (_.VT _.RC:$src1), imm:$src2))]>, EVEX, TAPD; defm NAME : avx512_extract_elt_bw_m<0x14, OpcodeStr, X86pextrb, _>, TAPD; } } multiclass avx512_extract_elt_w { let Predicates = [HasBWI] in { def rr : AVX512Ii8<0xC5, MRMSrcReg, (outs GR32orGR64:$dst), (ins _.RC:$src1, u8imm:$src2), OpcodeStr#"\t{$src2, $src1, $dst|$dst, $src1, $src2}", [(set GR32orGR64:$dst, (X86pextrw (_.VT _.RC:$src1), imm:$src2))]>, EVEX, PD; def rr_REV : AVX512Ii8<0x15, MRMDestReg, (outs GR32orGR64:$dst), (ins _.RC:$src1, u8imm:$src2), OpcodeStr#".s\t{$src2, $src1, $dst|$dst, $src1, $src2}", []>, EVEX, TAPD; defm NAME : avx512_extract_elt_bw_m<0x15, OpcodeStr, X86pextrw, _>, TAPD; } } multiclass avx512_extract_elt_dq { let Predicates = [HasDQI] in { def rr : AVX512Ii8<0x16, MRMDestReg, (outs GRC:$dst), (ins _.RC:$src1, u8imm:$src2), OpcodeStr#"\t{$src2, $src1, $dst|$dst, $src1, $src2}", [(set GRC:$dst, (extractelt (_.VT _.RC:$src1), imm:$src2))]>, EVEX, TAPD; let mayStore = 1 in def mr : AVX512Ii8<0x16, MRMDestMem, (outs), (ins _.ScalarMemOp:$dst, _.RC:$src1, u8imm:$src2), OpcodeStr#"\t{$src2, $src1, $dst|$dst, $src1, $src2}", [(store (extractelt (_.VT _.RC:$src1), imm:$src2),addr:$dst)]>, EVEX, EVEX_CD8<_.EltSize, CD8VT1>, TAPD; } } defm VPEXTRBZ : avx512_extract_elt_b<"vpextrb", v16i8x_info>; defm VPEXTRWZ : avx512_extract_elt_w<"vpextrw", v8i16x_info>; defm VPEXTRDZ : avx512_extract_elt_dq<"vpextrd", v4i32x_info, GR32>; defm VPEXTRQZ : avx512_extract_elt_dq<"vpextrq", v2i64x_info, GR64>, VEX_W; multiclass avx512_insert_elt_m opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _, PatFrag LdFrag> { def rm : AVX512Ii8, EVEX_4V, EVEX_CD8<_.EltSize, CD8VT1>; } multiclass avx512_insert_elt_bw opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _, PatFrag LdFrag> { let Predicates = [HasBWI] in { def rr : AVX512Ii8, EVEX_4V; defm NAME : avx512_insert_elt_m; } } multiclass avx512_insert_elt_dq opc, string OpcodeStr, X86VectorVTInfo _, RegisterClass GRC> { let Predicates = [HasDQI] in { def rr : AVX512Ii8, EVEX_4V, TAPD; defm NAME : avx512_insert_elt_m, TAPD; } } defm VPINSRBZ : avx512_insert_elt_bw<0x20, "vpinsrb", X86pinsrb, v16i8x_info, extloadi8>, TAPD; defm VPINSRWZ : avx512_insert_elt_bw<0xC4, "vpinsrw", X86pinsrw, v8i16x_info, extloadi16>, PD; defm VPINSRDZ : avx512_insert_elt_dq<0x22, "vpinsrd", v4i32x_info, GR32>; defm VPINSRQZ : avx512_insert_elt_dq<0x22, "vpinsrq", v2i64x_info, GR64>, VEX_W; //===----------------------------------------------------------------------===// // VSHUFPS - VSHUFPD Operations //===----------------------------------------------------------------------===// multiclass avx512_shufp{ defm NAME: avx512_common_3Op_imm8, EVEX_CD8, AVX512AIi8Base, EVEX_4V; } defm VSHUFPS: avx512_shufp<"vshufps", avx512vl_i32_info, avx512vl_f32_info>, PS; defm VSHUFPD: avx512_shufp<"vshufpd", avx512vl_i64_info, avx512vl_f64_info>, PD, VEX_W; //===----------------------------------------------------------------------===// // AVX-512 - Byte shift Left/Right //===----------------------------------------------------------------------===// multiclass avx512_shift_packed opc, SDNode OpNode, Format MRMr, Format MRMm, string OpcodeStr, X86VectorVTInfo _>{ def rr : AVX512; let mayLoad = 1 in def rm : AVX512; } multiclass avx512_shift_packed_all opc, SDNode OpNode, Format MRMr, Format MRMm, string OpcodeStr, Predicate prd>{ let Predicates = [prd] in defm Z512 : avx512_shift_packed, EVEX_V512; let Predicates = [prd, HasVLX] in { defm Z256 : avx512_shift_packed, EVEX_V256; defm Z128 : avx512_shift_packed, EVEX_V128; } } defm VPSLLDQ : avx512_shift_packed_all<0x73, X86vshldq, MRM7r, MRM7m, "vpslldq", HasBWI>, AVX512PDIi8Base, EVEX_4V; defm VPSRLDQ : avx512_shift_packed_all<0x73, X86vshrdq, MRM3r, MRM3m, "vpsrldq", HasBWI>, AVX512PDIi8Base, EVEX_4V; multiclass avx512_psadbw_packed opc, SDNode OpNode, string OpcodeStr, X86VectorVTInfo _dst, X86VectorVTInfo _src>{ def rr : AVX512BI; let mayLoad = 1 in def rm : AVX512BI; } multiclass avx512_psadbw_packed_all opc, SDNode OpNode, string OpcodeStr, Predicate prd> { let Predicates = [prd] in defm Z512 : avx512_psadbw_packed, EVEX_V512; let Predicates = [prd, HasVLX] in { defm Z256 : avx512_psadbw_packed, EVEX_V256; defm Z128 : avx512_psadbw_packed, EVEX_V128; } } defm VPSADBW : avx512_psadbw_packed_all<0xf6, X86psadbw, "vpsadbw", HasBWI>, EVEX_4V; multiclass avx512_ternlog opc, string OpcodeStr, SDNode OpNode, X86VectorVTInfo _>{ let Constraints = "$src1 = $dst" in { defm rri : AVX512_maskable_3src, AVX512AIi8Base, EVEX_4V; let mayLoad = 1 in { defm rmi : AVX512_maskable_3src, AVX512AIi8Base, EVEX_4V, EVEX_CD8<_.EltSize, CD8VF>; defm rmbi : AVX512_maskable_3src, EVEX_B, AVX512AIi8Base, EVEX_4V, EVEX_CD8<_.EltSize, CD8VF>; } }// Constraints = "$src1 = $dst" } multiclass avx512_common_ternlog{ let Predicates = [HasAVX512] in defm Z : avx512_ternlog<0x25, OpcodeStr, X86vpternlog, _.info512>, EVEX_V512; let Predicates = [HasAVX512, HasVLX] in { defm Z128 : avx512_ternlog<0x25, OpcodeStr, X86vpternlog, _.info128>, EVEX_V128; defm Z256 : avx512_ternlog<0x25, OpcodeStr, X86vpternlog, _.info256>, EVEX_V256; } } defm VPTERNLOGD : avx512_common_ternlog<"vpternlogd", avx512vl_i32_info>; defm VPTERNLOGQ : avx512_common_ternlog<"vpternlogq", avx512vl_i64_info>, VEX_W; Index: projects/clang380-import/contrib/llvm/lib/Transforms/IPO/PruneEH.cpp =================================================================== --- projects/clang380-import/contrib/llvm/lib/Transforms/IPO/PruneEH.cpp (revision 295858) +++ projects/clang380-import/contrib/llvm/lib/Transforms/IPO/PruneEH.cpp (revision 295859) @@ -1,273 +1,266 @@ //===- PruneEH.cpp - Pass which deletes unused exception handlers ---------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements a simple interprocedural pass which walks the // call-graph, turning invoke instructions into calls, iff the callee cannot // throw an exception, and marking functions 'nounwind' if they cannot throw. // It implements this as a bottom-up traversal of the call-graph. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/IPO.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/CallGraphSCCPass.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/IR/CFG.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/Transforms/Utils/Local.h" #include using namespace llvm; #define DEBUG_TYPE "prune-eh" STATISTIC(NumRemoved, "Number of invokes removed"); STATISTIC(NumUnreach, "Number of noreturn calls optimized"); namespace { struct PruneEH : public CallGraphSCCPass { static char ID; // Pass identification, replacement for typeid PruneEH() : CallGraphSCCPass(ID) { initializePruneEHPass(*PassRegistry::getPassRegistry()); } // runOnSCC - Analyze the SCC, performing the transformation if possible. bool runOnSCC(CallGraphSCC &SCC) override; bool SimplifyFunction(Function *F); void DeleteBasicBlock(BasicBlock *BB); }; } char PruneEH::ID = 0; INITIALIZE_PASS_BEGIN(PruneEH, "prune-eh", "Remove unused exception handling info", false, false) INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass) INITIALIZE_PASS_END(PruneEH, "prune-eh", "Remove unused exception handling info", false, false) Pass *llvm::createPruneEHPass() { return new PruneEH(); } bool PruneEH::runOnSCC(CallGraphSCC &SCC) { SmallPtrSet SCCNodes; CallGraph &CG = getAnalysis().getCallGraph(); bool MadeChange = false; // Fill SCCNodes with the elements of the SCC. Used for quickly // looking up whether a given CallGraphNode is in this SCC. for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) SCCNodes.insert(*I); // First pass, scan all of the functions in the SCC, simplifying them // according to what we know. for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) if (Function *F = (*I)->getFunction()) MadeChange |= SimplifyFunction(F); // Next, check to see if any callees might throw or if there are any external // functions in this SCC: if so, we cannot prune any functions in this SCC. // Definitions that are weak and not declared non-throwing might be // overridden at linktime with something that throws, so assume that. // If this SCC includes the unwind instruction, we KNOW it throws, so // obviously the SCC might throw. // bool SCCMightUnwind = false, SCCMightReturn = false; for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); (!SCCMightUnwind || !SCCMightReturn) && I != E; ++I) { Function *F = (*I)->getFunction(); if (!F) { SCCMightUnwind = true; SCCMightReturn = true; } else if (F->isDeclaration() || F->mayBeOverridden()) { SCCMightUnwind |= !F->doesNotThrow(); SCCMightReturn |= !F->doesNotReturn(); } else { bool CheckUnwind = !SCCMightUnwind && !F->doesNotThrow(); bool CheckReturn = !SCCMightReturn && !F->doesNotReturn(); // Determine if we should scan for InlineAsm in a naked function as it // is the only way to return without a ReturnInst. Only do this for // no-inline functions as functions which may be inlined cannot // meaningfully return via assembly. bool CheckReturnViaAsm = CheckReturn && F->hasFnAttribute(Attribute::Naked) && F->hasFnAttribute(Attribute::NoInline); if (!CheckUnwind && !CheckReturn) continue; for (const BasicBlock &BB : *F) { const TerminatorInst *TI = BB.getTerminator(); if (CheckUnwind && TI->mayThrow()) { SCCMightUnwind = true; } else if (CheckReturn && isa(TI)) { SCCMightReturn = true; } for (const Instruction &I : BB) { if ((!CheckUnwind || SCCMightUnwind) && (!CheckReturnViaAsm || SCCMightReturn)) break; // Check to see if this function performs an unwind or calls an // unwinding function. if (CheckUnwind && !SCCMightUnwind && I.mayThrow()) { bool InstMightUnwind = true; if (const auto *CI = dyn_cast(&I)) { if (Function *Callee = CI->getCalledFunction()) { CallGraphNode *CalleeNode = CG[Callee]; // If the callee is outside our current SCC then we may throw // because it might. If it is inside, do nothing. if (SCCNodes.count(CalleeNode) > 0) InstMightUnwind = false; } } SCCMightUnwind |= InstMightUnwind; } if (CheckReturnViaAsm && !SCCMightReturn) if (auto ICS = ImmutableCallSite(&I)) if (const auto *IA = dyn_cast(ICS.getCalledValue())) if (IA->hasSideEffects()) SCCMightReturn = true; } if (SCCMightUnwind && SCCMightReturn) break; } } } // If the SCC doesn't unwind or doesn't throw, note this fact. if (!SCCMightUnwind || !SCCMightReturn) for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) { Function *F = (*I)->getFunction(); if (!SCCMightUnwind && !F->hasFnAttribute(Attribute::NoUnwind)) { F->addFnAttr(Attribute::NoUnwind); MadeChange = true; } if (!SCCMightReturn && !F->hasFnAttribute(Attribute::NoReturn)) { F->addFnAttr(Attribute::NoReturn); MadeChange = true; } } for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) { // Convert any invoke instructions to non-throwing functions in this node // into call instructions with a branch. This makes the exception blocks // dead. if (Function *F = (*I)->getFunction()) MadeChange |= SimplifyFunction(F); } return MadeChange; } // SimplifyFunction - Given information about callees, simplify the specified // function if we have invokes to non-unwinding functions or code after calls to // no-return functions. bool PruneEH::SimplifyFunction(Function *F) { bool MadeChange = false; for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { if (InvokeInst *II = dyn_cast(BB->getTerminator())) if (II->doesNotThrow() && canSimplifyInvokeNoUnwind(F)) { - SmallVector Args(II->arg_begin(), II->arg_end()); - SmallVector OpBundles; - II->getOperandBundlesAsDefs(OpBundles); - - // Insert a call instruction before the invoke. - CallInst *Call = CallInst::Create(II->getCalledValue(), Args, OpBundles, - "", II); - Call->takeName(II); - Call->setCallingConv(II->getCallingConv()); - Call->setAttributes(II->getAttributes()); - Call->setDebugLoc(II->getDebugLoc()); - - // Anything that used the value produced by the invoke instruction - // now uses the value produced by the call instruction. Note that we - // do this even for void functions and calls with no uses so that the - // callgraph edge is updated. - II->replaceAllUsesWith(Call); BasicBlock *UnwindBlock = II->getUnwindDest(); - UnwindBlock->removePredecessor(II->getParent()); + removeUnwindEdge(&*BB); - // Insert a branch to the normal destination right before the - // invoke. - BranchInst::Create(II->getNormalDest(), II); - - // Finally, delete the invoke instruction! - BB->getInstList().pop_back(); - // If the unwind block is now dead, nuke it. if (pred_empty(UnwindBlock)) DeleteBasicBlock(UnwindBlock); // Delete the new BB. ++NumRemoved; MadeChange = true; } for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) if (CallInst *CI = dyn_cast(I++)) if (CI->doesNotReturn() && !isa(I)) { // This call calls a function that cannot return. Insert an // unreachable instruction after it and simplify the code. Do this // by splitting the BB, adding the unreachable, then deleting the // new BB. BasicBlock *New = BB->splitBasicBlock(I); // Remove the uncond branch and add an unreachable. BB->getInstList().pop_back(); new UnreachableInst(BB->getContext(), &*BB); DeleteBasicBlock(New); // Delete the new BB. MadeChange = true; ++NumUnreach; break; } } return MadeChange; } /// DeleteBasicBlock - remove the specified basic block from the program, /// updating the callgraph to reflect any now-obsolete edges due to calls that /// exist in the BB. void PruneEH::DeleteBasicBlock(BasicBlock *BB) { assert(pred_empty(BB) && "BB is not dead!"); CallGraph &CG = getAnalysis().getCallGraph(); + Instruction *TokenInst = nullptr; + CallGraphNode *CGN = CG[BB->getParent()]; for (BasicBlock::iterator I = BB->end(), E = BB->begin(); I != E; ) { --I; - if (CallInst *CI = dyn_cast(I)) { - if (!isa(I)) - CGN->removeCallEdgeFor(CI); - } else if (InvokeInst *II = dyn_cast(I)) - CGN->removeCallEdgeFor(II); + + if (I->getType()->isTokenTy()) { + TokenInst = &*I; + break; + } + + if (auto CS = CallSite (&*I)) { + const Function *Callee = CS.getCalledFunction(); + if (!Callee || !Intrinsic::isLeaf(Callee->getIntrinsicID())) + CGN->removeCallEdgeFor(CS); + else if (!Callee->isIntrinsic()) + CGN->removeCallEdgeFor(CS); + } + if (!I->use_empty()) I->replaceAllUsesWith(UndefValue::get(I->getType())); } - // Get the list of successors of this block. - std::vector Succs(succ_begin(BB), succ_end(BB)); + if (TokenInst) { + if (!isa(TokenInst)) + changeToUnreachable(TokenInst->getNextNode(), /*UseLLVMTrap=*/false); + } else { + // Get the list of successors of this block. + std::vector Succs(succ_begin(BB), succ_end(BB)); - for (unsigned i = 0, e = Succs.size(); i != e; ++i) - Succs[i]->removePredecessor(BB); + for (unsigned i = 0, e = Succs.size(); i != e; ++i) + Succs[i]->removePredecessor(BB); - BB->eraseFromParent(); + BB->eraseFromParent(); + } } Index: projects/clang380-import/contrib/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp =================================================================== --- projects/clang380-import/contrib/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp (revision 295858) +++ projects/clang380-import/contrib/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp (revision 295859) @@ -1,5024 +1,5035 @@ //===- LoopStrengthReduce.cpp - Strength Reduce IVs in Loops --------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This transformation analyzes and transforms the induction variables (and // computations derived from them) into forms suitable for efficient execution // on the target. // // This pass performs a strength reduction on array references inside loops that // have as one or more of their components the loop induction variable, it // rewrites expressions to take advantage of scaled-index addressing modes // available on the target, and it performs a variety of other optimizations // related to loop induction variables. // // Terminology note: this code has a lot of handling for "post-increment" or // "post-inc" users. This is not talking about post-increment addressing modes; // it is instead talking about code like this: // // %i = phi [ 0, %entry ], [ %i.next, %latch ] // ... // %i.next = add %i, 1 // %c = icmp eq %i.next, %n // // The SCEV for %i is {0,+,1}<%L>. The SCEV for %i.next is {1,+,1}<%L>, however // it's useful to think about these as the same register, with some uses using // the value of the register before the add and some using it after. In this // example, the icmp is a post-increment user, since it uses %i.next, which is // the value of the induction variable after the increment. The other common // case of post-increment users is users outside the loop. // // TODO: More sophistication in the way Formulae are generated and filtered. // // TODO: Handle multiple loops at a time. // // TODO: Should the addressing mode BaseGV be changed to a ConstantExpr instead // of a GlobalValue? // // TODO: When truncation is free, truncate ICmp users' operands to make it a // smaller encoding (on x86 at least). // // TODO: When a negated register is used by an add (such as in a list of // multiple base registers, or as the increment expression in an addrec), // we may not actually need both reg and (-1 * reg) in registers; the // negation can be implemented by using a sub instead of an add. The // lack of support for taking this into consideration when making // register pressure decisions is partly worked around by the "Special" // use kind. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/Scalar.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/Analysis/IVUsers.h" #include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/ScalarEvolutionExpander.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Local.h" #include using namespace llvm; #define DEBUG_TYPE "loop-reduce" /// MaxIVUsers is an arbitrary threshold that provides an early opportunitiy for /// bail out. This threshold is far beyond the number of users that LSR can /// conceivably solve, so it should not affect generated code, but catches the /// worst cases before LSR burns too much compile time and stack space. static const unsigned MaxIVUsers = 200; // Temporary flag to cleanup congruent phis after LSR phi expansion. // It's currently disabled until we can determine whether it's truly useful or // not. The flag should be removed after the v3.0 release. // This is now needed for ivchains. static cl::opt EnablePhiElim( "enable-lsr-phielim", cl::Hidden, cl::init(true), cl::desc("Enable LSR phi elimination")); #ifndef NDEBUG // Stress test IV chain generation. static cl::opt StressIVChain( "stress-ivchain", cl::Hidden, cl::init(false), cl::desc("Stress test LSR IV chains")); #else static bool StressIVChain = false; #endif namespace { struct MemAccessTy { /// Used in situations where the accessed memory type is unknown. static const unsigned UnknownAddressSpace = ~0u; Type *MemTy; unsigned AddrSpace; MemAccessTy() : MemTy(nullptr), AddrSpace(UnknownAddressSpace) {} MemAccessTy(Type *Ty, unsigned AS) : MemTy(Ty), AddrSpace(AS) {} bool operator==(MemAccessTy Other) const { return MemTy == Other.MemTy && AddrSpace == Other.AddrSpace; } bool operator!=(MemAccessTy Other) const { return !(*this == Other); } static MemAccessTy getUnknown(LLVMContext &Ctx) { return MemAccessTy(Type::getVoidTy(Ctx), UnknownAddressSpace); } }; /// This class holds data which is used to order reuse candidates. class RegSortData { public: /// This represents the set of LSRUse indices which reference /// a particular register. SmallBitVector UsedByIndices; void print(raw_ostream &OS) const; void dump() const; }; } void RegSortData::print(raw_ostream &OS) const { OS << "[NumUses=" << UsedByIndices.count() << ']'; } LLVM_DUMP_METHOD void RegSortData::dump() const { print(errs()); errs() << '\n'; } namespace { /// Map register candidates to information about how they are used. class RegUseTracker { typedef DenseMap RegUsesTy; RegUsesTy RegUsesMap; SmallVector RegSequence; public: void countRegister(const SCEV *Reg, size_t LUIdx); void dropRegister(const SCEV *Reg, size_t LUIdx); void swapAndDropUse(size_t LUIdx, size_t LastLUIdx); bool isRegUsedByUsesOtherThan(const SCEV *Reg, size_t LUIdx) const; const SmallBitVector &getUsedByIndices(const SCEV *Reg) const; void clear(); typedef SmallVectorImpl::iterator iterator; typedef SmallVectorImpl::const_iterator const_iterator; iterator begin() { return RegSequence.begin(); } iterator end() { return RegSequence.end(); } const_iterator begin() const { return RegSequence.begin(); } const_iterator end() const { return RegSequence.end(); } }; } void RegUseTracker::countRegister(const SCEV *Reg, size_t LUIdx) { std::pair Pair = RegUsesMap.insert(std::make_pair(Reg, RegSortData())); RegSortData &RSD = Pair.first->second; if (Pair.second) RegSequence.push_back(Reg); RSD.UsedByIndices.resize(std::max(RSD.UsedByIndices.size(), LUIdx + 1)); RSD.UsedByIndices.set(LUIdx); } void RegUseTracker::dropRegister(const SCEV *Reg, size_t LUIdx) { RegUsesTy::iterator It = RegUsesMap.find(Reg); assert(It != RegUsesMap.end()); RegSortData &RSD = It->second; assert(RSD.UsedByIndices.size() > LUIdx); RSD.UsedByIndices.reset(LUIdx); } void RegUseTracker::swapAndDropUse(size_t LUIdx, size_t LastLUIdx) { assert(LUIdx <= LastLUIdx); // Update RegUses. The data structure is not optimized for this purpose; // we must iterate through it and update each of the bit vectors. for (auto &Pair : RegUsesMap) { SmallBitVector &UsedByIndices = Pair.second.UsedByIndices; if (LUIdx < UsedByIndices.size()) UsedByIndices[LUIdx] = LastLUIdx < UsedByIndices.size() ? UsedByIndices[LastLUIdx] : 0; UsedByIndices.resize(std::min(UsedByIndices.size(), LastLUIdx)); } } bool RegUseTracker::isRegUsedByUsesOtherThan(const SCEV *Reg, size_t LUIdx) const { RegUsesTy::const_iterator I = RegUsesMap.find(Reg); if (I == RegUsesMap.end()) return false; const SmallBitVector &UsedByIndices = I->second.UsedByIndices; int i = UsedByIndices.find_first(); if (i == -1) return false; if ((size_t)i != LUIdx) return true; return UsedByIndices.find_next(i) != -1; } const SmallBitVector &RegUseTracker::getUsedByIndices(const SCEV *Reg) const { RegUsesTy::const_iterator I = RegUsesMap.find(Reg); assert(I != RegUsesMap.end() && "Unknown register!"); return I->second.UsedByIndices; } void RegUseTracker::clear() { RegUsesMap.clear(); RegSequence.clear(); } namespace { /// This class holds information that describes a formula for computing /// satisfying a use. It may include broken-out immediates and scaled registers. struct Formula { /// Global base address used for complex addressing. GlobalValue *BaseGV; /// Base offset for complex addressing. int64_t BaseOffset; /// Whether any complex addressing has a base register. bool HasBaseReg; /// The scale of any complex addressing. int64_t Scale; /// The list of "base" registers for this use. When this is non-empty. The /// canonical representation of a formula is /// 1. BaseRegs.size > 1 implies ScaledReg != NULL and /// 2. ScaledReg != NULL implies Scale != 1 || !BaseRegs.empty(). /// #1 enforces that the scaled register is always used when at least two /// registers are needed by the formula: e.g., reg1 + reg2 is reg1 + 1 * reg2. /// #2 enforces that 1 * reg is reg. /// This invariant can be temporarly broken while building a formula. /// However, every formula inserted into the LSRInstance must be in canonical /// form. SmallVector BaseRegs; /// The 'scaled' register for this use. This should be non-null when Scale is /// not zero. const SCEV *ScaledReg; /// An additional constant offset which added near the use. This requires a /// temporary register, but the offset itself can live in an add immediate /// field rather than a register. int64_t UnfoldedOffset; Formula() : BaseGV(nullptr), BaseOffset(0), HasBaseReg(false), Scale(0), ScaledReg(nullptr), UnfoldedOffset(0) {} void initialMatch(const SCEV *S, Loop *L, ScalarEvolution &SE); bool isCanonical() const; void canonicalize(); bool unscale(); size_t getNumRegs() const; Type *getType() const; void deleteBaseReg(const SCEV *&S); bool referencesReg(const SCEV *S) const; bool hasRegsUsedByUsesOtherThan(size_t LUIdx, const RegUseTracker &RegUses) const; void print(raw_ostream &OS) const; void dump() const; }; } /// Recursion helper for initialMatch. static void DoInitialMatch(const SCEV *S, Loop *L, SmallVectorImpl &Good, SmallVectorImpl &Bad, ScalarEvolution &SE) { // Collect expressions which properly dominate the loop header. if (SE.properlyDominates(S, L->getHeader())) { Good.push_back(S); return; } // Look at add operands. if (const SCEVAddExpr *Add = dyn_cast(S)) { for (const SCEV *S : Add->operands()) DoInitialMatch(S, L, Good, Bad, SE); return; } // Look at addrec operands. if (const SCEVAddRecExpr *AR = dyn_cast(S)) if (!AR->getStart()->isZero()) { DoInitialMatch(AR->getStart(), L, Good, Bad, SE); DoInitialMatch(SE.getAddRecExpr(SE.getConstant(AR->getType(), 0), AR->getStepRecurrence(SE), // FIXME: AR->getNoWrapFlags() AR->getLoop(), SCEV::FlagAnyWrap), L, Good, Bad, SE); return; } // Handle a multiplication by -1 (negation) if it didn't fold. if (const SCEVMulExpr *Mul = dyn_cast(S)) if (Mul->getOperand(0)->isAllOnesValue()) { SmallVector Ops(Mul->op_begin()+1, Mul->op_end()); const SCEV *NewMul = SE.getMulExpr(Ops); SmallVector MyGood; SmallVector MyBad; DoInitialMatch(NewMul, L, MyGood, MyBad, SE); const SCEV *NegOne = SE.getSCEV(ConstantInt::getAllOnesValue( SE.getEffectiveSCEVType(NewMul->getType()))); for (const SCEV *S : MyGood) Good.push_back(SE.getMulExpr(NegOne, S)); for (const SCEV *S : MyBad) Bad.push_back(SE.getMulExpr(NegOne, S)); return; } // Ok, we can't do anything interesting. Just stuff the whole thing into a // register and hope for the best. Bad.push_back(S); } /// Incorporate loop-variant parts of S into this Formula, attempting to keep /// all loop-invariant and loop-computable values in a single base register. void Formula::initialMatch(const SCEV *S, Loop *L, ScalarEvolution &SE) { SmallVector Good; SmallVector Bad; DoInitialMatch(S, L, Good, Bad, SE); if (!Good.empty()) { const SCEV *Sum = SE.getAddExpr(Good); if (!Sum->isZero()) BaseRegs.push_back(Sum); HasBaseReg = true; } if (!Bad.empty()) { const SCEV *Sum = SE.getAddExpr(Bad); if (!Sum->isZero()) BaseRegs.push_back(Sum); HasBaseReg = true; } canonicalize(); } /// \brief Check whether or not this formula statisfies the canonical /// representation. /// \see Formula::BaseRegs. bool Formula::isCanonical() const { if (ScaledReg) return Scale != 1 || !BaseRegs.empty(); return BaseRegs.size() <= 1; } /// \brief Helper method to morph a formula into its canonical representation. /// \see Formula::BaseRegs. /// Every formula having more than one base register, must use the ScaledReg /// field. Otherwise, we would have to do special cases everywhere in LSR /// to treat reg1 + reg2 + ... the same way as reg1 + 1*reg2 + ... /// On the other hand, 1*reg should be canonicalized into reg. void Formula::canonicalize() { if (isCanonical()) return; // So far we did not need this case. This is easy to implement but it is // useless to maintain dead code. Beside it could hurt compile time. assert(!BaseRegs.empty() && "1*reg => reg, should not be needed."); // Keep the invariant sum in BaseRegs and one of the variant sum in ScaledReg. ScaledReg = BaseRegs.back(); BaseRegs.pop_back(); Scale = 1; size_t BaseRegsSize = BaseRegs.size(); size_t Try = 0; // If ScaledReg is an invariant, try to find a variant expression. while (Try < BaseRegsSize && !isa(ScaledReg)) std::swap(ScaledReg, BaseRegs[Try++]); } /// \brief Get rid of the scale in the formula. /// In other words, this method morphes reg1 + 1*reg2 into reg1 + reg2. /// \return true if it was possible to get rid of the scale, false otherwise. /// \note After this operation the formula may not be in the canonical form. bool Formula::unscale() { if (Scale != 1) return false; Scale = 0; BaseRegs.push_back(ScaledReg); ScaledReg = nullptr; return true; } /// Return the total number of register operands used by this formula. This does /// not include register uses implied by non-constant addrec strides. size_t Formula::getNumRegs() const { return !!ScaledReg + BaseRegs.size(); } /// Return the type of this formula, if it has one, or null otherwise. This type /// is meaningless except for the bit size. Type *Formula::getType() const { return !BaseRegs.empty() ? BaseRegs.front()->getType() : ScaledReg ? ScaledReg->getType() : BaseGV ? BaseGV->getType() : nullptr; } /// Delete the given base reg from the BaseRegs list. void Formula::deleteBaseReg(const SCEV *&S) { if (&S != &BaseRegs.back()) std::swap(S, BaseRegs.back()); BaseRegs.pop_back(); } /// Test if this formula references the given register. bool Formula::referencesReg(const SCEV *S) const { return S == ScaledReg || std::find(BaseRegs.begin(), BaseRegs.end(), S) != BaseRegs.end(); } /// Test whether this formula uses registers which are used by uses other than /// the use with the given index. bool Formula::hasRegsUsedByUsesOtherThan(size_t LUIdx, const RegUseTracker &RegUses) const { if (ScaledReg) if (RegUses.isRegUsedByUsesOtherThan(ScaledReg, LUIdx)) return true; for (const SCEV *BaseReg : BaseRegs) if (RegUses.isRegUsedByUsesOtherThan(BaseReg, LUIdx)) return true; return false; } void Formula::print(raw_ostream &OS) const { bool First = true; if (BaseGV) { if (!First) OS << " + "; else First = false; BaseGV->printAsOperand(OS, /*PrintType=*/false); } if (BaseOffset != 0) { if (!First) OS << " + "; else First = false; OS << BaseOffset; } for (const SCEV *BaseReg : BaseRegs) { if (!First) OS << " + "; else First = false; OS << "reg(" << *BaseReg << ')'; } if (HasBaseReg && BaseRegs.empty()) { if (!First) OS << " + "; else First = false; OS << "**error: HasBaseReg**"; } else if (!HasBaseReg && !BaseRegs.empty()) { if (!First) OS << " + "; else First = false; OS << "**error: !HasBaseReg**"; } if (Scale != 0) { if (!First) OS << " + "; else First = false; OS << Scale << "*reg("; if (ScaledReg) OS << *ScaledReg; else OS << ""; OS << ')'; } if (UnfoldedOffset != 0) { if (!First) OS << " + "; OS << "imm(" << UnfoldedOffset << ')'; } } LLVM_DUMP_METHOD void Formula::dump() const { print(errs()); errs() << '\n'; } /// Return true if the given addrec can be sign-extended without changing its /// value. static bool isAddRecSExtable(const SCEVAddRecExpr *AR, ScalarEvolution &SE) { Type *WideTy = IntegerType::get(SE.getContext(), SE.getTypeSizeInBits(AR->getType()) + 1); return isa(SE.getSignExtendExpr(AR, WideTy)); } /// Return true if the given add can be sign-extended without changing its /// value. static bool isAddSExtable(const SCEVAddExpr *A, ScalarEvolution &SE) { Type *WideTy = IntegerType::get(SE.getContext(), SE.getTypeSizeInBits(A->getType()) + 1); return isa(SE.getSignExtendExpr(A, WideTy)); } /// Return true if the given mul can be sign-extended without changing its /// value. static bool isMulSExtable(const SCEVMulExpr *M, ScalarEvolution &SE) { Type *WideTy = IntegerType::get(SE.getContext(), SE.getTypeSizeInBits(M->getType()) * M->getNumOperands()); return isa(SE.getSignExtendExpr(M, WideTy)); } /// Return an expression for LHS /s RHS, if it can be determined and if the /// remainder is known to be zero, or null otherwise. If IgnoreSignificantBits /// is true, expressions like (X * Y) /s Y are simplified to Y, ignoring that /// the multiplication may overflow, which is useful when the result will be /// used in a context where the most significant bits are ignored. static const SCEV *getExactSDiv(const SCEV *LHS, const SCEV *RHS, ScalarEvolution &SE, bool IgnoreSignificantBits = false) { // Handle the trivial case, which works for any SCEV type. if (LHS == RHS) return SE.getConstant(LHS->getType(), 1); // Handle a few RHS special cases. const SCEVConstant *RC = dyn_cast(RHS); if (RC) { const APInt &RA = RC->getAPInt(); // Handle x /s -1 as x * -1, to give ScalarEvolution a chance to do // some folding. if (RA.isAllOnesValue()) return SE.getMulExpr(LHS, RC); // Handle x /s 1 as x. if (RA == 1) return LHS; } // Check for a division of a constant by a constant. if (const SCEVConstant *C = dyn_cast(LHS)) { if (!RC) return nullptr; const APInt &LA = C->getAPInt(); const APInt &RA = RC->getAPInt(); if (LA.srem(RA) != 0) return nullptr; return SE.getConstant(LA.sdiv(RA)); } // Distribute the sdiv over addrec operands, if the addrec doesn't overflow. if (const SCEVAddRecExpr *AR = dyn_cast(LHS)) { if (IgnoreSignificantBits || isAddRecSExtable(AR, SE)) { const SCEV *Step = getExactSDiv(AR->getStepRecurrence(SE), RHS, SE, IgnoreSignificantBits); if (!Step) return nullptr; const SCEV *Start = getExactSDiv(AR->getStart(), RHS, SE, IgnoreSignificantBits); if (!Start) return nullptr; // FlagNW is independent of the start value, step direction, and is // preserved with smaller magnitude steps. // FIXME: AR->getNoWrapFlags(SCEV::FlagNW) return SE.getAddRecExpr(Start, Step, AR->getLoop(), SCEV::FlagAnyWrap); } return nullptr; } // Distribute the sdiv over add operands, if the add doesn't overflow. if (const SCEVAddExpr *Add = dyn_cast(LHS)) { if (IgnoreSignificantBits || isAddSExtable(Add, SE)) { SmallVector Ops; for (const SCEV *S : Add->operands()) { const SCEV *Op = getExactSDiv(S, RHS, SE, IgnoreSignificantBits); if (!Op) return nullptr; Ops.push_back(Op); } return SE.getAddExpr(Ops); } return nullptr; } // Check for a multiply operand that we can pull RHS out of. if (const SCEVMulExpr *Mul = dyn_cast(LHS)) { if (IgnoreSignificantBits || isMulSExtable(Mul, SE)) { SmallVector Ops; bool Found = false; for (const SCEV *S : Mul->operands()) { if (!Found) if (const SCEV *Q = getExactSDiv(S, RHS, SE, IgnoreSignificantBits)) { S = Q; Found = true; } Ops.push_back(S); } return Found ? SE.getMulExpr(Ops) : nullptr; } return nullptr; } // Otherwise we don't know. return nullptr; } /// If S involves the addition of a constant integer value, return that integer /// value, and mutate S to point to a new SCEV with that value excluded. static int64_t ExtractImmediate(const SCEV *&S, ScalarEvolution &SE) { if (const SCEVConstant *C = dyn_cast(S)) { if (C->getAPInt().getMinSignedBits() <= 64) { S = SE.getConstant(C->getType(), 0); return C->getValue()->getSExtValue(); } } else if (const SCEVAddExpr *Add = dyn_cast(S)) { SmallVector NewOps(Add->op_begin(), Add->op_end()); int64_t Result = ExtractImmediate(NewOps.front(), SE); if (Result != 0) S = SE.getAddExpr(NewOps); return Result; } else if (const SCEVAddRecExpr *AR = dyn_cast(S)) { SmallVector NewOps(AR->op_begin(), AR->op_end()); int64_t Result = ExtractImmediate(NewOps.front(), SE); if (Result != 0) S = SE.getAddRecExpr(NewOps, AR->getLoop(), // FIXME: AR->getNoWrapFlags(SCEV::FlagNW) SCEV::FlagAnyWrap); return Result; } return 0; } /// If S involves the addition of a GlobalValue address, return that symbol, and /// mutate S to point to a new SCEV with that value excluded. static GlobalValue *ExtractSymbol(const SCEV *&S, ScalarEvolution &SE) { if (const SCEVUnknown *U = dyn_cast(S)) { if (GlobalValue *GV = dyn_cast(U->getValue())) { S = SE.getConstant(GV->getType(), 0); return GV; } } else if (const SCEVAddExpr *Add = dyn_cast(S)) { SmallVector NewOps(Add->op_begin(), Add->op_end()); GlobalValue *Result = ExtractSymbol(NewOps.back(), SE); if (Result) S = SE.getAddExpr(NewOps); return Result; } else if (const SCEVAddRecExpr *AR = dyn_cast(S)) { SmallVector NewOps(AR->op_begin(), AR->op_end()); GlobalValue *Result = ExtractSymbol(NewOps.front(), SE); if (Result) S = SE.getAddRecExpr(NewOps, AR->getLoop(), // FIXME: AR->getNoWrapFlags(SCEV::FlagNW) SCEV::FlagAnyWrap); return Result; } return nullptr; } /// Returns true if the specified instruction is using the specified value as an /// address. static bool isAddressUse(Instruction *Inst, Value *OperandVal) { bool isAddress = isa(Inst); if (StoreInst *SI = dyn_cast(Inst)) { if (SI->getOperand(1) == OperandVal) isAddress = true; } else if (IntrinsicInst *II = dyn_cast(Inst)) { // Addressing modes can also be folded into prefetches and a variety // of intrinsics. switch (II->getIntrinsicID()) { default: break; case Intrinsic::prefetch: case Intrinsic::x86_sse_storeu_ps: case Intrinsic::x86_sse2_storeu_pd: case Intrinsic::x86_sse2_storeu_dq: case Intrinsic::x86_sse2_storel_dq: if (II->getArgOperand(0) == OperandVal) isAddress = true; break; } } return isAddress; } /// Return the type of the memory being accessed. static MemAccessTy getAccessType(const Instruction *Inst) { MemAccessTy AccessTy(Inst->getType(), MemAccessTy::UnknownAddressSpace); if (const StoreInst *SI = dyn_cast(Inst)) { AccessTy.MemTy = SI->getOperand(0)->getType(); AccessTy.AddrSpace = SI->getPointerAddressSpace(); } else if (const LoadInst *LI = dyn_cast(Inst)) { AccessTy.AddrSpace = LI->getPointerAddressSpace(); } else if (const IntrinsicInst *II = dyn_cast(Inst)) { // Addressing modes can also be folded into prefetches and a variety // of intrinsics. switch (II->getIntrinsicID()) { default: break; case Intrinsic::x86_sse_storeu_ps: case Intrinsic::x86_sse2_storeu_pd: case Intrinsic::x86_sse2_storeu_dq: case Intrinsic::x86_sse2_storel_dq: AccessTy.MemTy = II->getArgOperand(0)->getType(); break; } } // All pointers have the same requirements, so canonicalize them to an // arbitrary pointer type to minimize variation. if (PointerType *PTy = dyn_cast(AccessTy.MemTy)) AccessTy.MemTy = PointerType::get(IntegerType::get(PTy->getContext(), 1), PTy->getAddressSpace()); return AccessTy; } /// Return true if this AddRec is already a phi in its loop. static bool isExistingPhi(const SCEVAddRecExpr *AR, ScalarEvolution &SE) { for (BasicBlock::iterator I = AR->getLoop()->getHeader()->begin(); PHINode *PN = dyn_cast(I); ++I) { if (SE.isSCEVable(PN->getType()) && (SE.getEffectiveSCEVType(PN->getType()) == SE.getEffectiveSCEVType(AR->getType())) && SE.getSCEV(PN) == AR) return true; } return false; } /// Check if expanding this expression is likely to incur significant cost. This /// is tricky because SCEV doesn't track which expressions are actually computed /// by the current IR. /// /// We currently allow expansion of IV increments that involve adds, /// multiplication by constants, and AddRecs from existing phis. /// /// TODO: Allow UDivExpr if we can find an existing IV increment that is an /// obvious multiple of the UDivExpr. static bool isHighCostExpansion(const SCEV *S, SmallPtrSetImpl &Processed, ScalarEvolution &SE) { // Zero/One operand expressions switch (S->getSCEVType()) { case scUnknown: case scConstant: return false; case scTruncate: return isHighCostExpansion(cast(S)->getOperand(), Processed, SE); case scZeroExtend: return isHighCostExpansion(cast(S)->getOperand(), Processed, SE); case scSignExtend: return isHighCostExpansion(cast(S)->getOperand(), Processed, SE); } if (!Processed.insert(S).second) return false; if (const SCEVAddExpr *Add = dyn_cast(S)) { for (const SCEV *S : Add->operands()) { if (isHighCostExpansion(S, Processed, SE)) return true; } return false; } if (const SCEVMulExpr *Mul = dyn_cast(S)) { if (Mul->getNumOperands() == 2) { // Multiplication by a constant is ok if (isa(Mul->getOperand(0))) return isHighCostExpansion(Mul->getOperand(1), Processed, SE); // If we have the value of one operand, check if an existing // multiplication already generates this expression. if (const SCEVUnknown *U = dyn_cast(Mul->getOperand(1))) { Value *UVal = U->getValue(); for (User *UR : UVal->users()) { // If U is a constant, it may be used by a ConstantExpr. Instruction *UI = dyn_cast(UR); if (UI && UI->getOpcode() == Instruction::Mul && SE.isSCEVable(UI->getType())) { return SE.getSCEV(UI) == Mul; } } } } } if (const SCEVAddRecExpr *AR = dyn_cast(S)) { if (isExistingPhi(AR, SE)) return false; } // Fow now, consider any other type of expression (div/mul/min/max) high cost. return true; } /// If any of the instructions is the specified set are trivially dead, delete /// them and see if this makes any of their operands subsequently dead. static bool DeleteTriviallyDeadInstructions(SmallVectorImpl &DeadInsts) { bool Changed = false; while (!DeadInsts.empty()) { Value *V = DeadInsts.pop_back_val(); Instruction *I = dyn_cast_or_null(V); if (!I || !isInstructionTriviallyDead(I)) continue; for (Use &O : I->operands()) if (Instruction *U = dyn_cast(O)) { O = nullptr; if (U->use_empty()) DeadInsts.emplace_back(U); } I->eraseFromParent(); Changed = true; } return Changed; } namespace { class LSRUse; } /// \brief Check if the addressing mode defined by \p F is completely /// folded in \p LU at isel time. /// This includes address-mode folding and special icmp tricks. /// This function returns true if \p LU can accommodate what \p F /// defines and up to 1 base + 1 scaled + offset. /// In other words, if \p F has several base registers, this function may /// still return true. Therefore, users still need to account for /// additional base registers and/or unfolded offsets to derive an /// accurate cost model. static bool isAMCompletelyFolded(const TargetTransformInfo &TTI, const LSRUse &LU, const Formula &F); // Get the cost of the scaling factor used in F for LU. static unsigned getScalingFactorCost(const TargetTransformInfo &TTI, const LSRUse &LU, const Formula &F); namespace { /// This class is used to measure and compare candidate formulae. class Cost { /// TODO: Some of these could be merged. Also, a lexical ordering /// isn't always optimal. unsigned NumRegs; unsigned AddRecCost; unsigned NumIVMuls; unsigned NumBaseAdds; unsigned ImmCost; unsigned SetupCost; unsigned ScaleCost; public: Cost() : NumRegs(0), AddRecCost(0), NumIVMuls(0), NumBaseAdds(0), ImmCost(0), SetupCost(0), ScaleCost(0) {} bool operator<(const Cost &Other) const; void Lose(); #ifndef NDEBUG // Once any of the metrics loses, they must all remain losers. bool isValid() { return ((NumRegs | AddRecCost | NumIVMuls | NumBaseAdds | ImmCost | SetupCost | ScaleCost) != ~0u) || ((NumRegs & AddRecCost & NumIVMuls & NumBaseAdds & ImmCost & SetupCost & ScaleCost) == ~0u); } #endif bool isLoser() { assert(isValid() && "invalid cost"); return NumRegs == ~0u; } void RateFormula(const TargetTransformInfo &TTI, const Formula &F, SmallPtrSetImpl &Regs, const DenseSet &VisitedRegs, const Loop *L, const SmallVectorImpl &Offsets, ScalarEvolution &SE, DominatorTree &DT, const LSRUse &LU, SmallPtrSetImpl *LoserRegs = nullptr); void print(raw_ostream &OS) const; void dump() const; private: void RateRegister(const SCEV *Reg, SmallPtrSetImpl &Regs, const Loop *L, ScalarEvolution &SE, DominatorTree &DT); void RatePrimaryRegister(const SCEV *Reg, SmallPtrSetImpl &Regs, const Loop *L, ScalarEvolution &SE, DominatorTree &DT, SmallPtrSetImpl *LoserRegs); }; } /// Tally up interesting quantities from the given register. void Cost::RateRegister(const SCEV *Reg, SmallPtrSetImpl &Regs, const Loop *L, ScalarEvolution &SE, DominatorTree &DT) { if (const SCEVAddRecExpr *AR = dyn_cast(Reg)) { // If this is an addrec for another loop, don't second-guess its addrec phi // nodes. LSR isn't currently smart enough to reason about more than one // loop at a time. LSR has already run on inner loops, will not run on outer // loops, and cannot be expected to change sibling loops. if (AR->getLoop() != L) { // If the AddRec exists, consider it's register free and leave it alone. if (isExistingPhi(AR, SE)) return; // Otherwise, do not consider this formula at all. Lose(); return; } AddRecCost += 1; /// TODO: This should be a function of the stride. // Add the step value register, if it needs one. // TODO: The non-affine case isn't precisely modeled here. if (!AR->isAffine() || !isa(AR->getOperand(1))) { if (!Regs.count(AR->getOperand(1))) { RateRegister(AR->getOperand(1), Regs, L, SE, DT); if (isLoser()) return; } } } ++NumRegs; // Rough heuristic; favor registers which don't require extra setup // instructions in the preheader. if (!isa(Reg) && !isa(Reg) && !(isa(Reg) && (isa(cast(Reg)->getStart()) || isa(cast(Reg)->getStart())))) ++SetupCost; NumIVMuls += isa(Reg) && SE.hasComputableLoopEvolution(Reg, L); } /// Record this register in the set. If we haven't seen it before, rate /// it. Optional LoserRegs provides a way to declare any formula that refers to /// one of those regs an instant loser. void Cost::RatePrimaryRegister(const SCEV *Reg, SmallPtrSetImpl &Regs, const Loop *L, ScalarEvolution &SE, DominatorTree &DT, SmallPtrSetImpl *LoserRegs) { if (LoserRegs && LoserRegs->count(Reg)) { Lose(); return; } if (Regs.insert(Reg).second) { RateRegister(Reg, Regs, L, SE, DT); if (LoserRegs && isLoser()) LoserRegs->insert(Reg); } } void Cost::RateFormula(const TargetTransformInfo &TTI, const Formula &F, SmallPtrSetImpl &Regs, const DenseSet &VisitedRegs, const Loop *L, const SmallVectorImpl &Offsets, ScalarEvolution &SE, DominatorTree &DT, const LSRUse &LU, SmallPtrSetImpl *LoserRegs) { assert(F.isCanonical() && "Cost is accurate only for canonical formula"); // Tally up the registers. if (const SCEV *ScaledReg = F.ScaledReg) { if (VisitedRegs.count(ScaledReg)) { Lose(); return; } RatePrimaryRegister(ScaledReg, Regs, L, SE, DT, LoserRegs); if (isLoser()) return; } for (const SCEV *BaseReg : F.BaseRegs) { if (VisitedRegs.count(BaseReg)) { Lose(); return; } RatePrimaryRegister(BaseReg, Regs, L, SE, DT, LoserRegs); if (isLoser()) return; } // Determine how many (unfolded) adds we'll need inside the loop. size_t NumBaseParts = F.getNumRegs(); if (NumBaseParts > 1) // Do not count the base and a possible second register if the target // allows to fold 2 registers. NumBaseAdds += NumBaseParts - (1 + (F.Scale && isAMCompletelyFolded(TTI, LU, F))); NumBaseAdds += (F.UnfoldedOffset != 0); // Accumulate non-free scaling amounts. ScaleCost += getScalingFactorCost(TTI, LU, F); // Tally up the non-zero immediates. for (int64_t O : Offsets) { int64_t Offset = (uint64_t)O + F.BaseOffset; if (F.BaseGV) ImmCost += 64; // Handle symbolic values conservatively. // TODO: This should probably be the pointer size. else if (Offset != 0) ImmCost += APInt(64, Offset, true).getMinSignedBits(); } assert(isValid() && "invalid cost"); } /// Set this cost to a losing value. void Cost::Lose() { NumRegs = ~0u; AddRecCost = ~0u; NumIVMuls = ~0u; NumBaseAdds = ~0u; ImmCost = ~0u; SetupCost = ~0u; ScaleCost = ~0u; } /// Choose the lower cost. bool Cost::operator<(const Cost &Other) const { return std::tie(NumRegs, AddRecCost, NumIVMuls, NumBaseAdds, ScaleCost, ImmCost, SetupCost) < std::tie(Other.NumRegs, Other.AddRecCost, Other.NumIVMuls, Other.NumBaseAdds, Other.ScaleCost, Other.ImmCost, Other.SetupCost); } void Cost::print(raw_ostream &OS) const { OS << NumRegs << " reg" << (NumRegs == 1 ? "" : "s"); if (AddRecCost != 0) OS << ", with addrec cost " << AddRecCost; if (NumIVMuls != 0) OS << ", plus " << NumIVMuls << " IV mul" << (NumIVMuls == 1 ? "" : "s"); if (NumBaseAdds != 0) OS << ", plus " << NumBaseAdds << " base add" << (NumBaseAdds == 1 ? "" : "s"); if (ScaleCost != 0) OS << ", plus " << ScaleCost << " scale cost"; if (ImmCost != 0) OS << ", plus " << ImmCost << " imm cost"; if (SetupCost != 0) OS << ", plus " << SetupCost << " setup cost"; } LLVM_DUMP_METHOD void Cost::dump() const { print(errs()); errs() << '\n'; } namespace { /// An operand value in an instruction which is to be replaced with some /// equivalent, possibly strength-reduced, replacement. struct LSRFixup { /// The instruction which will be updated. Instruction *UserInst; /// The operand of the instruction which will be replaced. The operand may be /// used more than once; every instance will be replaced. Value *OperandValToReplace; /// If this user is to use the post-incremented value of an induction /// variable, this variable is non-null and holds the loop associated with the /// induction variable. PostIncLoopSet PostIncLoops; /// The index of the LSRUse describing the expression which this fixup needs, /// minus an offset (below). size_t LUIdx; /// A constant offset to be added to the LSRUse expression. This allows /// multiple fixups to share the same LSRUse with different offsets, for /// example in an unrolled loop. int64_t Offset; bool isUseFullyOutsideLoop(const Loop *L) const; LSRFixup(); void print(raw_ostream &OS) const; void dump() const; }; } LSRFixup::LSRFixup() : UserInst(nullptr), OperandValToReplace(nullptr), LUIdx(~size_t(0)), Offset(0) {} /// Test whether this fixup always uses its value outside of the given loop. bool LSRFixup::isUseFullyOutsideLoop(const Loop *L) const { // PHI nodes use their value in their incoming blocks. if (const PHINode *PN = dyn_cast(UserInst)) { for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) if (PN->getIncomingValue(i) == OperandValToReplace && L->contains(PN->getIncomingBlock(i))) return false; return true; } return !L->contains(UserInst); } void LSRFixup::print(raw_ostream &OS) const { OS << "UserInst="; // Store is common and interesting enough to be worth special-casing. if (StoreInst *Store = dyn_cast(UserInst)) { OS << "store "; Store->getOperand(0)->printAsOperand(OS, /*PrintType=*/false); } else if (UserInst->getType()->isVoidTy()) OS << UserInst->getOpcodeName(); else UserInst->printAsOperand(OS, /*PrintType=*/false); OS << ", OperandValToReplace="; OperandValToReplace->printAsOperand(OS, /*PrintType=*/false); for (const Loop *PIL : PostIncLoops) { OS << ", PostIncLoop="; PIL->getHeader()->printAsOperand(OS, /*PrintType=*/false); } if (LUIdx != ~size_t(0)) OS << ", LUIdx=" << LUIdx; if (Offset != 0) OS << ", Offset=" << Offset; } LLVM_DUMP_METHOD void LSRFixup::dump() const { print(errs()); errs() << '\n'; } namespace { /// A DenseMapInfo implementation for holding DenseMaps and DenseSets of sorted /// SmallVectors of const SCEV*. struct UniquifierDenseMapInfo { static SmallVector getEmptyKey() { SmallVector V; V.push_back(reinterpret_cast(-1)); return V; } static SmallVector getTombstoneKey() { SmallVector V; V.push_back(reinterpret_cast(-2)); return V; } static unsigned getHashValue(const SmallVector &V) { return static_cast(hash_combine_range(V.begin(), V.end())); } static bool isEqual(const SmallVector &LHS, const SmallVector &RHS) { return LHS == RHS; } }; /// This class holds the state that LSR keeps for each use in IVUsers, as well /// as uses invented by LSR itself. It includes information about what kinds of /// things can be folded into the user, information about the user itself, and /// information about how the use may be satisfied. TODO: Represent multiple /// users of the same expression in common? class LSRUse { DenseSet, UniquifierDenseMapInfo> Uniquifier; public: /// An enum for a kind of use, indicating what types of scaled and immediate /// operands it might support. enum KindType { Basic, ///< A normal use, with no folding. Special, ///< A special case of basic, allowing -1 scales. Address, ///< An address use; folding according to TargetLowering ICmpZero ///< An equality icmp with both operands folded into one. // TODO: Add a generic icmp too? }; typedef PointerIntPair SCEVUseKindPair; KindType Kind; MemAccessTy AccessTy; SmallVector Offsets; int64_t MinOffset; int64_t MaxOffset; /// This records whether all of the fixups using this LSRUse are outside of /// the loop, in which case some special-case heuristics may be used. bool AllFixupsOutsideLoop; /// RigidFormula is set to true to guarantee that this use will be associated /// with a single formula--the one that initially matched. Some SCEV /// expressions cannot be expanded. This allows LSR to consider the registers /// used by those expressions without the need to expand them later after /// changing the formula. bool RigidFormula; /// This records the widest use type for any fixup using this /// LSRUse. FindUseWithSimilarFormula can't consider uses with different max /// fixup widths to be equivalent, because the narrower one may be relying on /// the implicit truncation to truncate away bogus bits. Type *WidestFixupType; /// A list of ways to build a value that can satisfy this user. After the /// list is populated, one of these is selected heuristically and used to /// formulate a replacement for OperandValToReplace in UserInst. SmallVector Formulae; /// The set of register candidates used by all formulae in this LSRUse. SmallPtrSet Regs; LSRUse(KindType K, MemAccessTy AT) : Kind(K), AccessTy(AT), MinOffset(INT64_MAX), MaxOffset(INT64_MIN), AllFixupsOutsideLoop(true), RigidFormula(false), WidestFixupType(nullptr) {} bool HasFormulaWithSameRegs(const Formula &F) const; bool InsertFormula(const Formula &F); void DeleteFormula(Formula &F); void RecomputeRegs(size_t LUIdx, RegUseTracker &Reguses); void print(raw_ostream &OS) const; void dump() const; }; } /// Test whether this use as a formula which has the same registers as the given /// formula. bool LSRUse::HasFormulaWithSameRegs(const Formula &F) const { SmallVector Key = F.BaseRegs; if (F.ScaledReg) Key.push_back(F.ScaledReg); // Unstable sort by host order ok, because this is only used for uniquifying. std::sort(Key.begin(), Key.end()); return Uniquifier.count(Key); } /// If the given formula has not yet been inserted, add it to the list, and /// return true. Return false otherwise. The formula must be in canonical form. bool LSRUse::InsertFormula(const Formula &F) { assert(F.isCanonical() && "Invalid canonical representation"); if (!Formulae.empty() && RigidFormula) return false; SmallVector Key = F.BaseRegs; if (F.ScaledReg) Key.push_back(F.ScaledReg); // Unstable sort by host order ok, because this is only used for uniquifying. std::sort(Key.begin(), Key.end()); if (!Uniquifier.insert(Key).second) return false; // Using a register to hold the value of 0 is not profitable. assert((!F.ScaledReg || !F.ScaledReg->isZero()) && "Zero allocated in a scaled register!"); #ifndef NDEBUG for (const SCEV *BaseReg : F.BaseRegs) assert(!BaseReg->isZero() && "Zero allocated in a base register!"); #endif // Add the formula to the list. Formulae.push_back(F); // Record registers now being used by this use. Regs.insert(F.BaseRegs.begin(), F.BaseRegs.end()); if (F.ScaledReg) Regs.insert(F.ScaledReg); return true; } /// Remove the given formula from this use's list. void LSRUse::DeleteFormula(Formula &F) { if (&F != &Formulae.back()) std::swap(F, Formulae.back()); Formulae.pop_back(); } /// Recompute the Regs field, and update RegUses. void LSRUse::RecomputeRegs(size_t LUIdx, RegUseTracker &RegUses) { // Now that we've filtered out some formulae, recompute the Regs set. SmallPtrSet OldRegs = std::move(Regs); Regs.clear(); for (const Formula &F : Formulae) { if (F.ScaledReg) Regs.insert(F.ScaledReg); Regs.insert(F.BaseRegs.begin(), F.BaseRegs.end()); } // Update the RegTracker. for (const SCEV *S : OldRegs) if (!Regs.count(S)) RegUses.dropRegister(S, LUIdx); } void LSRUse::print(raw_ostream &OS) const { OS << "LSR Use: Kind="; switch (Kind) { case Basic: OS << "Basic"; break; case Special: OS << "Special"; break; case ICmpZero: OS << "ICmpZero"; break; case Address: OS << "Address of "; if (AccessTy.MemTy->isPointerTy()) OS << "pointer"; // the full pointer type could be really verbose else { OS << *AccessTy.MemTy; } OS << " in addrspace(" << AccessTy.AddrSpace << ')'; } OS << ", Offsets={"; bool NeedComma = false; for (int64_t O : Offsets) { if (NeedComma) OS << ','; OS << O; NeedComma = true; } OS << '}'; if (AllFixupsOutsideLoop) OS << ", all-fixups-outside-loop"; if (WidestFixupType) OS << ", widest fixup type: " << *WidestFixupType; } LLVM_DUMP_METHOD void LSRUse::dump() const { print(errs()); errs() << '\n'; } static bool isAMCompletelyFolded(const TargetTransformInfo &TTI, LSRUse::KindType Kind, MemAccessTy AccessTy, GlobalValue *BaseGV, int64_t BaseOffset, bool HasBaseReg, int64_t Scale) { switch (Kind) { case LSRUse::Address: return TTI.isLegalAddressingMode(AccessTy.MemTy, BaseGV, BaseOffset, HasBaseReg, Scale, AccessTy.AddrSpace); case LSRUse::ICmpZero: // There's not even a target hook for querying whether it would be legal to // fold a GV into an ICmp. if (BaseGV) return false; // ICmp only has two operands; don't allow more than two non-trivial parts. if (Scale != 0 && HasBaseReg && BaseOffset != 0) return false; // ICmp only supports no scale or a -1 scale, as we can "fold" a -1 scale by // putting the scaled register in the other operand of the icmp. if (Scale != 0 && Scale != -1) return false; // If we have low-level target information, ask the target if it can fold an // integer immediate on an icmp. if (BaseOffset != 0) { // We have one of: // ICmpZero BaseReg + BaseOffset => ICmp BaseReg, -BaseOffset // ICmpZero -1*ScaleReg + BaseOffset => ICmp ScaleReg, BaseOffset // Offs is the ICmp immediate. if (Scale == 0) // The cast does the right thing with INT64_MIN. BaseOffset = -(uint64_t)BaseOffset; return TTI.isLegalICmpImmediate(BaseOffset); } // ICmpZero BaseReg + -1*ScaleReg => ICmp BaseReg, ScaleReg return true; case LSRUse::Basic: // Only handle single-register values. return !BaseGV && Scale == 0 && BaseOffset == 0; case LSRUse::Special: // Special case Basic to handle -1 scales. return !BaseGV && (Scale == 0 || Scale == -1) && BaseOffset == 0; } llvm_unreachable("Invalid LSRUse Kind!"); } static bool isAMCompletelyFolded(const TargetTransformInfo &TTI, int64_t MinOffset, int64_t MaxOffset, LSRUse::KindType Kind, MemAccessTy AccessTy, GlobalValue *BaseGV, int64_t BaseOffset, bool HasBaseReg, int64_t Scale) { // Check for overflow. if (((int64_t)((uint64_t)BaseOffset + MinOffset) > BaseOffset) != (MinOffset > 0)) return false; MinOffset = (uint64_t)BaseOffset + MinOffset; if (((int64_t)((uint64_t)BaseOffset + MaxOffset) > BaseOffset) != (MaxOffset > 0)) return false; MaxOffset = (uint64_t)BaseOffset + MaxOffset; return isAMCompletelyFolded(TTI, Kind, AccessTy, BaseGV, MinOffset, HasBaseReg, Scale) && isAMCompletelyFolded(TTI, Kind, AccessTy, BaseGV, MaxOffset, HasBaseReg, Scale); } static bool isAMCompletelyFolded(const TargetTransformInfo &TTI, int64_t MinOffset, int64_t MaxOffset, LSRUse::KindType Kind, MemAccessTy AccessTy, const Formula &F) { // For the purpose of isAMCompletelyFolded either having a canonical formula // or a scale not equal to zero is correct. // Problems may arise from non canonical formulae having a scale == 0. // Strictly speaking it would best to just rely on canonical formulae. // However, when we generate the scaled formulae, we first check that the // scaling factor is profitable before computing the actual ScaledReg for // compile time sake. assert((F.isCanonical() || F.Scale != 0)); return isAMCompletelyFolded(TTI, MinOffset, MaxOffset, Kind, AccessTy, F.BaseGV, F.BaseOffset, F.HasBaseReg, F.Scale); } /// Test whether we know how to expand the current formula. static bool isLegalUse(const TargetTransformInfo &TTI, int64_t MinOffset, int64_t MaxOffset, LSRUse::KindType Kind, MemAccessTy AccessTy, GlobalValue *BaseGV, int64_t BaseOffset, bool HasBaseReg, int64_t Scale) { // We know how to expand completely foldable formulae. return isAMCompletelyFolded(TTI, MinOffset, MaxOffset, Kind, AccessTy, BaseGV, BaseOffset, HasBaseReg, Scale) || // Or formulae that use a base register produced by a sum of base // registers. (Scale == 1 && isAMCompletelyFolded(TTI, MinOffset, MaxOffset, Kind, AccessTy, BaseGV, BaseOffset, true, 0)); } static bool isLegalUse(const TargetTransformInfo &TTI, int64_t MinOffset, int64_t MaxOffset, LSRUse::KindType Kind, MemAccessTy AccessTy, const Formula &F) { return isLegalUse(TTI, MinOffset, MaxOffset, Kind, AccessTy, F.BaseGV, F.BaseOffset, F.HasBaseReg, F.Scale); } static bool isAMCompletelyFolded(const TargetTransformInfo &TTI, const LSRUse &LU, const Formula &F) { return isAMCompletelyFolded(TTI, LU.MinOffset, LU.MaxOffset, LU.Kind, LU.AccessTy, F.BaseGV, F.BaseOffset, F.HasBaseReg, F.Scale); } static unsigned getScalingFactorCost(const TargetTransformInfo &TTI, const LSRUse &LU, const Formula &F) { if (!F.Scale) return 0; // If the use is not completely folded in that instruction, we will have to // pay an extra cost only for scale != 1. if (!isAMCompletelyFolded(TTI, LU.MinOffset, LU.MaxOffset, LU.Kind, LU.AccessTy, F)) return F.Scale != 1; switch (LU.Kind) { case LSRUse::Address: { // Check the scaling factor cost with both the min and max offsets. int ScaleCostMinOffset = TTI.getScalingFactorCost( LU.AccessTy.MemTy, F.BaseGV, F.BaseOffset + LU.MinOffset, F.HasBaseReg, F.Scale, LU.AccessTy.AddrSpace); int ScaleCostMaxOffset = TTI.getScalingFactorCost( LU.AccessTy.MemTy, F.BaseGV, F.BaseOffset + LU.MaxOffset, F.HasBaseReg, F.Scale, LU.AccessTy.AddrSpace); assert(ScaleCostMinOffset >= 0 && ScaleCostMaxOffset >= 0 && "Legal addressing mode has an illegal cost!"); return std::max(ScaleCostMinOffset, ScaleCostMaxOffset); } case LSRUse::ICmpZero: case LSRUse::Basic: case LSRUse::Special: // The use is completely folded, i.e., everything is folded into the // instruction. return 0; } llvm_unreachable("Invalid LSRUse Kind!"); } static bool isAlwaysFoldable(const TargetTransformInfo &TTI, LSRUse::KindType Kind, MemAccessTy AccessTy, GlobalValue *BaseGV, int64_t BaseOffset, bool HasBaseReg) { // Fast-path: zero is always foldable. if (BaseOffset == 0 && !BaseGV) return true; // Conservatively, create an address with an immediate and a // base and a scale. int64_t Scale = Kind == LSRUse::ICmpZero ? -1 : 1; // Canonicalize a scale of 1 to a base register if the formula doesn't // already have a base register. if (!HasBaseReg && Scale == 1) { Scale = 0; HasBaseReg = true; } return isAMCompletelyFolded(TTI, Kind, AccessTy, BaseGV, BaseOffset, HasBaseReg, Scale); } static bool isAlwaysFoldable(const TargetTransformInfo &TTI, ScalarEvolution &SE, int64_t MinOffset, int64_t MaxOffset, LSRUse::KindType Kind, MemAccessTy AccessTy, const SCEV *S, bool HasBaseReg) { // Fast-path: zero is always foldable. if (S->isZero()) return true; // Conservatively, create an address with an immediate and a // base and a scale. int64_t BaseOffset = ExtractImmediate(S, SE); GlobalValue *BaseGV = ExtractSymbol(S, SE); // If there's anything else involved, it's not foldable. if (!S->isZero()) return false; // Fast-path: zero is always foldable. if (BaseOffset == 0 && !BaseGV) return true; // Conservatively, create an address with an immediate and a // base and a scale. int64_t Scale = Kind == LSRUse::ICmpZero ? -1 : 1; return isAMCompletelyFolded(TTI, MinOffset, MaxOffset, Kind, AccessTy, BaseGV, BaseOffset, HasBaseReg, Scale); } namespace { /// An individual increment in a Chain of IV increments. Relate an IV user to /// an expression that computes the IV it uses from the IV used by the previous /// link in the Chain. /// /// For the head of a chain, IncExpr holds the absolute SCEV expression for the /// original IVOperand. The head of the chain's IVOperand is only valid during /// chain collection, before LSR replaces IV users. During chain generation, /// IncExpr can be used to find the new IVOperand that computes the same /// expression. struct IVInc { Instruction *UserInst; Value* IVOperand; const SCEV *IncExpr; IVInc(Instruction *U, Value *O, const SCEV *E): UserInst(U), IVOperand(O), IncExpr(E) {} }; // The list of IV increments in program order. We typically add the head of a // chain without finding subsequent links. struct IVChain { SmallVector Incs; const SCEV *ExprBase; IVChain() : ExprBase(nullptr) {} IVChain(const IVInc &Head, const SCEV *Base) : Incs(1, Head), ExprBase(Base) {} typedef SmallVectorImpl::const_iterator const_iterator; // Return the first increment in the chain. const_iterator begin() const { assert(!Incs.empty()); return std::next(Incs.begin()); } const_iterator end() const { return Incs.end(); } // Returns true if this chain contains any increments. bool hasIncs() const { return Incs.size() >= 2; } // Add an IVInc to the end of this chain. void add(const IVInc &X) { Incs.push_back(X); } // Returns the last UserInst in the chain. Instruction *tailUserInst() const { return Incs.back().UserInst; } // Returns true if IncExpr can be profitably added to this chain. bool isProfitableIncrement(const SCEV *OperExpr, const SCEV *IncExpr, ScalarEvolution&); }; /// Helper for CollectChains to track multiple IV increment uses. Distinguish /// between FarUsers that definitely cross IV increments and NearUsers that may /// be used between IV increments. struct ChainUsers { SmallPtrSet FarUsers; SmallPtrSet NearUsers; }; /// This class holds state for the main loop strength reduction logic. class LSRInstance { IVUsers &IU; ScalarEvolution &SE; DominatorTree &DT; LoopInfo &LI; const TargetTransformInfo &TTI; Loop *const L; bool Changed; /// This is the insert position that the current loop's induction variable /// increment should be placed. In simple loops, this is the latch block's /// terminator. But in more complicated cases, this is a position which will /// dominate all the in-loop post-increment users. Instruction *IVIncInsertPos; /// Interesting factors between use strides. SmallSetVector Factors; /// Interesting use types, to facilitate truncation reuse. SmallSetVector Types; /// The list of operands which are to be replaced. SmallVector Fixups; /// The list of interesting uses. SmallVector Uses; /// Track which uses use which register candidates. RegUseTracker RegUses; // Limit the number of chains to avoid quadratic behavior. We don't expect to // have more than a few IV increment chains in a loop. Missing a Chain falls // back to normal LSR behavior for those uses. static const unsigned MaxChains = 8; /// IV users can form a chain of IV increments. SmallVector IVChainVec; /// IV users that belong to profitable IVChains. SmallPtrSet IVIncSet; void OptimizeShadowIV(); bool FindIVUserForCond(ICmpInst *Cond, IVStrideUse *&CondUse); ICmpInst *OptimizeMax(ICmpInst *Cond, IVStrideUse* &CondUse); void OptimizeLoopTermCond(); void ChainInstruction(Instruction *UserInst, Instruction *IVOper, SmallVectorImpl &ChainUsersVec); void FinalizeChain(IVChain &Chain); void CollectChains(); void GenerateIVChain(const IVChain &Chain, SCEVExpander &Rewriter, SmallVectorImpl &DeadInsts); void CollectInterestingTypesAndFactors(); void CollectFixupsAndInitialFormulae(); LSRFixup &getNewFixup() { Fixups.push_back(LSRFixup()); return Fixups.back(); } // Support for sharing of LSRUses between LSRFixups. typedef DenseMap UseMapTy; UseMapTy UseMap; bool reconcileNewOffset(LSRUse &LU, int64_t NewOffset, bool HasBaseReg, LSRUse::KindType Kind, MemAccessTy AccessTy); std::pair getUse(const SCEV *&Expr, LSRUse::KindType Kind, MemAccessTy AccessTy); void DeleteUse(LSRUse &LU, size_t LUIdx); LSRUse *FindUseWithSimilarFormula(const Formula &F, const LSRUse &OrigLU); void InsertInitialFormula(const SCEV *S, LSRUse &LU, size_t LUIdx); void InsertSupplementalFormula(const SCEV *S, LSRUse &LU, size_t LUIdx); void CountRegisters(const Formula &F, size_t LUIdx); bool InsertFormula(LSRUse &LU, unsigned LUIdx, const Formula &F); void CollectLoopInvariantFixupsAndFormulae(); void GenerateReassociations(LSRUse &LU, unsigned LUIdx, Formula Base, unsigned Depth = 0); void GenerateReassociationsImpl(LSRUse &LU, unsigned LUIdx, const Formula &Base, unsigned Depth, size_t Idx, bool IsScaledReg = false); void GenerateCombinations(LSRUse &LU, unsigned LUIdx, Formula Base); void GenerateSymbolicOffsetsImpl(LSRUse &LU, unsigned LUIdx, const Formula &Base, size_t Idx, bool IsScaledReg = false); void GenerateSymbolicOffsets(LSRUse &LU, unsigned LUIdx, Formula Base); void GenerateConstantOffsetsImpl(LSRUse &LU, unsigned LUIdx, const Formula &Base, const SmallVectorImpl &Worklist, size_t Idx, bool IsScaledReg = false); void GenerateConstantOffsets(LSRUse &LU, unsigned LUIdx, Formula Base); void GenerateICmpZeroScales(LSRUse &LU, unsigned LUIdx, Formula Base); void GenerateScales(LSRUse &LU, unsigned LUIdx, Formula Base); void GenerateTruncates(LSRUse &LU, unsigned LUIdx, Formula Base); void GenerateCrossUseConstantOffsets(); void GenerateAllReuseFormulae(); void FilterOutUndesirableDedicatedRegisters(); size_t EstimateSearchSpaceComplexity() const; void NarrowSearchSpaceByDetectingSupersets(); void NarrowSearchSpaceByCollapsingUnrolledCode(); void NarrowSearchSpaceByRefilteringUndesirableDedicatedRegisters(); void NarrowSearchSpaceByPickingWinnerRegs(); void NarrowSearchSpaceUsingHeuristics(); void SolveRecurse(SmallVectorImpl &Solution, Cost &SolutionCost, SmallVectorImpl &Workspace, const Cost &CurCost, const SmallPtrSet &CurRegs, DenseSet &VisitedRegs) const; void Solve(SmallVectorImpl &Solution) const; BasicBlock::iterator HoistInsertPosition(BasicBlock::iterator IP, const SmallVectorImpl &Inputs) const; BasicBlock::iterator AdjustInsertPositionForExpand(BasicBlock::iterator IP, const LSRFixup &LF, const LSRUse &LU, SCEVExpander &Rewriter) const; Value *Expand(const LSRFixup &LF, const Formula &F, BasicBlock::iterator IP, SCEVExpander &Rewriter, SmallVectorImpl &DeadInsts) const; void RewriteForPHI(PHINode *PN, const LSRFixup &LF, const Formula &F, SCEVExpander &Rewriter, SmallVectorImpl &DeadInsts) const; void Rewrite(const LSRFixup &LF, const Formula &F, SCEVExpander &Rewriter, SmallVectorImpl &DeadInsts) const; void ImplementSolution(const SmallVectorImpl &Solution); public: LSRInstance(Loop *L, IVUsers &IU, ScalarEvolution &SE, DominatorTree &DT, LoopInfo &LI, const TargetTransformInfo &TTI); bool getChanged() const { return Changed; } void print_factors_and_types(raw_ostream &OS) const; void print_fixups(raw_ostream &OS) const; void print_uses(raw_ostream &OS) const; void print(raw_ostream &OS) const; void dump() const; }; } /// If IV is used in a int-to-float cast inside the loop then try to eliminate /// the cast operation. void LSRInstance::OptimizeShadowIV() { const SCEV *BackedgeTakenCount = SE.getBackedgeTakenCount(L); if (isa(BackedgeTakenCount)) return; for (IVUsers::const_iterator UI = IU.begin(), E = IU.end(); UI != E; /* empty */) { IVUsers::const_iterator CandidateUI = UI; ++UI; Instruction *ShadowUse = CandidateUI->getUser(); Type *DestTy = nullptr; bool IsSigned = false; /* If shadow use is a int->float cast then insert a second IV to eliminate this cast. for (unsigned i = 0; i < n; ++i) foo((double)i); is transformed into double d = 0.0; for (unsigned i = 0; i < n; ++i, ++d) foo(d); */ if (UIToFPInst *UCast = dyn_cast(CandidateUI->getUser())) { IsSigned = false; DestTy = UCast->getDestTy(); } else if (SIToFPInst *SCast = dyn_cast(CandidateUI->getUser())) { IsSigned = true; DestTy = SCast->getDestTy(); } if (!DestTy) continue; // If target does not support DestTy natively then do not apply // this transformation. if (!TTI.isTypeLegal(DestTy)) continue; PHINode *PH = dyn_cast(ShadowUse->getOperand(0)); if (!PH) continue; if (PH->getNumIncomingValues() != 2) continue; Type *SrcTy = PH->getType(); int Mantissa = DestTy->getFPMantissaWidth(); if (Mantissa == -1) continue; if ((int)SE.getTypeSizeInBits(SrcTy) > Mantissa) continue; unsigned Entry, Latch; if (PH->getIncomingBlock(0) == L->getLoopPreheader()) { Entry = 0; Latch = 1; } else { Entry = 1; Latch = 0; } ConstantInt *Init = dyn_cast(PH->getIncomingValue(Entry)); if (!Init) continue; Constant *NewInit = ConstantFP::get(DestTy, IsSigned ? (double)Init->getSExtValue() : (double)Init->getZExtValue()); BinaryOperator *Incr = dyn_cast(PH->getIncomingValue(Latch)); if (!Incr) continue; if (Incr->getOpcode() != Instruction::Add && Incr->getOpcode() != Instruction::Sub) continue; /* Initialize new IV, double d = 0.0 in above example. */ ConstantInt *C = nullptr; if (Incr->getOperand(0) == PH) C = dyn_cast(Incr->getOperand(1)); else if (Incr->getOperand(1) == PH) C = dyn_cast(Incr->getOperand(0)); else continue; if (!C) continue; // Ignore negative constants, as the code below doesn't handle them // correctly. TODO: Remove this restriction. if (!C->getValue().isStrictlyPositive()) continue; /* Add new PHINode. */ PHINode *NewPH = PHINode::Create(DestTy, 2, "IV.S.", PH); /* create new increment. '++d' in above example. */ Constant *CFP = ConstantFP::get(DestTy, C->getZExtValue()); BinaryOperator *NewIncr = BinaryOperator::Create(Incr->getOpcode() == Instruction::Add ? Instruction::FAdd : Instruction::FSub, NewPH, CFP, "IV.S.next.", Incr); NewPH->addIncoming(NewInit, PH->getIncomingBlock(Entry)); NewPH->addIncoming(NewIncr, PH->getIncomingBlock(Latch)); /* Remove cast operation */ ShadowUse->replaceAllUsesWith(NewPH); ShadowUse->eraseFromParent(); Changed = true; break; } } /// If Cond has an operand that is an expression of an IV, set the IV user and /// stride information and return true, otherwise return false. bool LSRInstance::FindIVUserForCond(ICmpInst *Cond, IVStrideUse *&CondUse) { for (IVStrideUse &U : IU) if (U.getUser() == Cond) { // NOTE: we could handle setcc instructions with multiple uses here, but // InstCombine does it as well for simple uses, it's not clear that it // occurs enough in real life to handle. CondUse = &U; return true; } return false; } /// Rewrite the loop's terminating condition if it uses a max computation. /// /// This is a narrow solution to a specific, but acute, problem. For loops /// like this: /// /// i = 0; /// do { /// p[i] = 0.0; /// } while (++i < n); /// /// the trip count isn't just 'n', because 'n' might not be positive. And /// unfortunately this can come up even for loops where the user didn't use /// a C do-while loop. For example, seemingly well-behaved top-test loops /// will commonly be lowered like this: // /// if (n > 0) { /// i = 0; /// do { /// p[i] = 0.0; /// } while (++i < n); /// } /// /// and then it's possible for subsequent optimization to obscure the if /// test in such a way that indvars can't find it. /// /// When indvars can't find the if test in loops like this, it creates a /// max expression, which allows it to give the loop a canonical /// induction variable: /// /// i = 0; /// max = n < 1 ? 1 : n; /// do { /// p[i] = 0.0; /// } while (++i != max); /// /// Canonical induction variables are necessary because the loop passes /// are designed around them. The most obvious example of this is the /// LoopInfo analysis, which doesn't remember trip count values. It /// expects to be able to rediscover the trip count each time it is /// needed, and it does this using a simple analysis that only succeeds if /// the loop has a canonical induction variable. /// /// However, when it comes time to generate code, the maximum operation /// can be quite costly, especially if it's inside of an outer loop. /// /// This function solves this problem by detecting this type of loop and /// rewriting their conditions from ICMP_NE back to ICMP_SLT, and deleting /// the instructions for the maximum computation. /// ICmpInst *LSRInstance::OptimizeMax(ICmpInst *Cond, IVStrideUse* &CondUse) { // Check that the loop matches the pattern we're looking for. if (Cond->getPredicate() != CmpInst::ICMP_EQ && Cond->getPredicate() != CmpInst::ICMP_NE) return Cond; SelectInst *Sel = dyn_cast(Cond->getOperand(1)); if (!Sel || !Sel->hasOneUse()) return Cond; const SCEV *BackedgeTakenCount = SE.getBackedgeTakenCount(L); if (isa(BackedgeTakenCount)) return Cond; const SCEV *One = SE.getConstant(BackedgeTakenCount->getType(), 1); // Add one to the backedge-taken count to get the trip count. const SCEV *IterationCount = SE.getAddExpr(One, BackedgeTakenCount); if (IterationCount != SE.getSCEV(Sel)) return Cond; // Check for a max calculation that matches the pattern. There's no check // for ICMP_ULE here because the comparison would be with zero, which // isn't interesting. CmpInst::Predicate Pred = ICmpInst::BAD_ICMP_PREDICATE; const SCEVNAryExpr *Max = nullptr; if (const SCEVSMaxExpr *S = dyn_cast(BackedgeTakenCount)) { Pred = ICmpInst::ICMP_SLE; Max = S; } else if (const SCEVSMaxExpr *S = dyn_cast(IterationCount)) { Pred = ICmpInst::ICMP_SLT; Max = S; } else if (const SCEVUMaxExpr *U = dyn_cast(IterationCount)) { Pred = ICmpInst::ICMP_ULT; Max = U; } else { // No match; bail. return Cond; } // To handle a max with more than two operands, this optimization would // require additional checking and setup. if (Max->getNumOperands() != 2) return Cond; const SCEV *MaxLHS = Max->getOperand(0); const SCEV *MaxRHS = Max->getOperand(1); // ScalarEvolution canonicalizes constants to the left. For < and >, look // for a comparison with 1. For <= and >=, a comparison with zero. if (!MaxLHS || (ICmpInst::isTrueWhenEqual(Pred) ? !MaxLHS->isZero() : (MaxLHS != One))) return Cond; // Check the relevant induction variable for conformance to // the pattern. const SCEV *IV = SE.getSCEV(Cond->getOperand(0)); const SCEVAddRecExpr *AR = dyn_cast(IV); if (!AR || !AR->isAffine() || AR->getStart() != One || AR->getStepRecurrence(SE) != One) return Cond; assert(AR->getLoop() == L && "Loop condition operand is an addrec in a different loop!"); // Check the right operand of the select, and remember it, as it will // be used in the new comparison instruction. Value *NewRHS = nullptr; if (ICmpInst::isTrueWhenEqual(Pred)) { // Look for n+1, and grab n. if (AddOperator *BO = dyn_cast(Sel->getOperand(1))) if (ConstantInt *BO1 = dyn_cast(BO->getOperand(1))) if (BO1->isOne() && SE.getSCEV(BO->getOperand(0)) == MaxRHS) NewRHS = BO->getOperand(0); if (AddOperator *BO = dyn_cast(Sel->getOperand(2))) if (ConstantInt *BO1 = dyn_cast(BO->getOperand(1))) if (BO1->isOne() && SE.getSCEV(BO->getOperand(0)) == MaxRHS) NewRHS = BO->getOperand(0); if (!NewRHS) return Cond; } else if (SE.getSCEV(Sel->getOperand(1)) == MaxRHS) NewRHS = Sel->getOperand(1); else if (SE.getSCEV(Sel->getOperand(2)) == MaxRHS) NewRHS = Sel->getOperand(2); else if (const SCEVUnknown *SU = dyn_cast(MaxRHS)) NewRHS = SU->getValue(); else // Max doesn't match expected pattern. return Cond; // Determine the new comparison opcode. It may be signed or unsigned, // and the original comparison may be either equality or inequality. if (Cond->getPredicate() == CmpInst::ICMP_EQ) Pred = CmpInst::getInversePredicate(Pred); // Ok, everything looks ok to change the condition into an SLT or SGE and // delete the max calculation. ICmpInst *NewCond = new ICmpInst(Cond, Pred, Cond->getOperand(0), NewRHS, "scmp"); // Delete the max calculation instructions. Cond->replaceAllUsesWith(NewCond); CondUse->setUser(NewCond); Instruction *Cmp = cast(Sel->getOperand(0)); Cond->eraseFromParent(); Sel->eraseFromParent(); if (Cmp->use_empty()) Cmp->eraseFromParent(); return NewCond; } /// Change loop terminating condition to use the postinc iv when possible. void LSRInstance::OptimizeLoopTermCond() { SmallPtrSet PostIncs; BasicBlock *LatchBlock = L->getLoopLatch(); SmallVector ExitingBlocks; L->getExitingBlocks(ExitingBlocks); for (BasicBlock *ExitingBlock : ExitingBlocks) { // Get the terminating condition for the loop if possible. If we // can, we want to change it to use a post-incremented version of its // induction variable, to allow coalescing the live ranges for the IV into // one register value. BranchInst *TermBr = dyn_cast(ExitingBlock->getTerminator()); if (!TermBr) continue; // FIXME: Overly conservative, termination condition could be an 'or' etc.. if (TermBr->isUnconditional() || !isa(TermBr->getCondition())) continue; // Search IVUsesByStride to find Cond's IVUse if there is one. IVStrideUse *CondUse = nullptr; ICmpInst *Cond = cast(TermBr->getCondition()); if (!FindIVUserForCond(Cond, CondUse)) continue; // If the trip count is computed in terms of a max (due to ScalarEvolution // being unable to find a sufficient guard, for example), change the loop // comparison to use SLT or ULT instead of NE. // One consequence of doing this now is that it disrupts the count-down // optimization. That's not always a bad thing though, because in such // cases it may still be worthwhile to avoid a max. Cond = OptimizeMax(Cond, CondUse); // If this exiting block dominates the latch block, it may also use // the post-inc value if it won't be shared with other uses. // Check for dominance. if (!DT.dominates(ExitingBlock, LatchBlock)) continue; // Conservatively avoid trying to use the post-inc value in non-latch // exits if there may be pre-inc users in intervening blocks. if (LatchBlock != ExitingBlock) for (IVUsers::const_iterator UI = IU.begin(), E = IU.end(); UI != E; ++UI) // Test if the use is reachable from the exiting block. This dominator // query is a conservative approximation of reachability. if (&*UI != CondUse && !DT.properlyDominates(UI->getUser()->getParent(), ExitingBlock)) { // Conservatively assume there may be reuse if the quotient of their // strides could be a legal scale. const SCEV *A = IU.getStride(*CondUse, L); const SCEV *B = IU.getStride(*UI, L); if (!A || !B) continue; if (SE.getTypeSizeInBits(A->getType()) != SE.getTypeSizeInBits(B->getType())) { if (SE.getTypeSizeInBits(A->getType()) > SE.getTypeSizeInBits(B->getType())) B = SE.getSignExtendExpr(B, A->getType()); else A = SE.getSignExtendExpr(A, B->getType()); } if (const SCEVConstant *D = dyn_cast_or_null(getExactSDiv(B, A, SE))) { const ConstantInt *C = D->getValue(); // Stride of one or negative one can have reuse with non-addresses. if (C->isOne() || C->isAllOnesValue()) goto decline_post_inc; // Avoid weird situations. if (C->getValue().getMinSignedBits() >= 64 || C->getValue().isMinSignedValue()) goto decline_post_inc; // Check for possible scaled-address reuse. MemAccessTy AccessTy = getAccessType(UI->getUser()); int64_t Scale = C->getSExtValue(); if (TTI.isLegalAddressingMode(AccessTy.MemTy, /*BaseGV=*/nullptr, /*BaseOffset=*/0, /*HasBaseReg=*/false, Scale, AccessTy.AddrSpace)) goto decline_post_inc; Scale = -Scale; if (TTI.isLegalAddressingMode(AccessTy.MemTy, /*BaseGV=*/nullptr, /*BaseOffset=*/0, /*HasBaseReg=*/false, Scale, AccessTy.AddrSpace)) goto decline_post_inc; } } DEBUG(dbgs() << " Change loop exiting icmp to use postinc iv: " << *Cond << '\n'); // It's possible for the setcc instruction to be anywhere in the loop, and // possible for it to have multiple users. If it is not immediately before // the exiting block branch, move it. if (&*++BasicBlock::iterator(Cond) != TermBr) { if (Cond->hasOneUse()) { Cond->moveBefore(TermBr); } else { // Clone the terminating condition and insert into the loopend. ICmpInst *OldCond = Cond; Cond = cast(Cond->clone()); Cond->setName(L->getHeader()->getName() + ".termcond"); ExitingBlock->getInstList().insert(TermBr->getIterator(), Cond); // Clone the IVUse, as the old use still exists! CondUse = &IU.AddUser(Cond, CondUse->getOperandValToReplace()); TermBr->replaceUsesOfWith(OldCond, Cond); } } // If we get to here, we know that we can transform the setcc instruction to // use the post-incremented version of the IV, allowing us to coalesce the // live ranges for the IV correctly. CondUse->transformToPostInc(L); Changed = true; PostIncs.insert(Cond); decline_post_inc:; } // Determine an insertion point for the loop induction variable increment. It // must dominate all the post-inc comparisons we just set up, and it must // dominate the loop latch edge. IVIncInsertPos = L->getLoopLatch()->getTerminator(); for (Instruction *Inst : PostIncs) { BasicBlock *BB = DT.findNearestCommonDominator(IVIncInsertPos->getParent(), Inst->getParent()); if (BB == Inst->getParent()) IVIncInsertPos = Inst; else if (BB != IVIncInsertPos->getParent()) IVIncInsertPos = BB->getTerminator(); } } /// Determine if the given use can accommodate a fixup at the given offset and /// other details. If so, update the use and return true. bool LSRInstance::reconcileNewOffset(LSRUse &LU, int64_t NewOffset, bool HasBaseReg, LSRUse::KindType Kind, MemAccessTy AccessTy) { int64_t NewMinOffset = LU.MinOffset; int64_t NewMaxOffset = LU.MaxOffset; MemAccessTy NewAccessTy = AccessTy; // Check for a mismatched kind. It's tempting to collapse mismatched kinds to // something conservative, however this can pessimize in the case that one of // the uses will have all its uses outside the loop, for example. if (LU.Kind != Kind) return false; // Check for a mismatched access type, and fall back conservatively as needed. // TODO: Be less conservative when the type is similar and can use the same // addressing modes. if (Kind == LSRUse::Address) { if (AccessTy != LU.AccessTy) NewAccessTy = MemAccessTy::getUnknown(AccessTy.MemTy->getContext()); } // Conservatively assume HasBaseReg is true for now. if (NewOffset < LU.MinOffset) { if (!isAlwaysFoldable(TTI, Kind, NewAccessTy, /*BaseGV=*/nullptr, LU.MaxOffset - NewOffset, HasBaseReg)) return false; NewMinOffset = NewOffset; } else if (NewOffset > LU.MaxOffset) { if (!isAlwaysFoldable(TTI, Kind, NewAccessTy, /*BaseGV=*/nullptr, NewOffset - LU.MinOffset, HasBaseReg)) return false; NewMaxOffset = NewOffset; } // Update the use. LU.MinOffset = NewMinOffset; LU.MaxOffset = NewMaxOffset; LU.AccessTy = NewAccessTy; if (NewOffset != LU.Offsets.back()) LU.Offsets.push_back(NewOffset); return true; } /// Return an LSRUse index and an offset value for a fixup which needs the given /// expression, with the given kind and optional access type. Either reuse an /// existing use or create a new one, as needed. std::pair LSRInstance::getUse(const SCEV *&Expr, LSRUse::KindType Kind, MemAccessTy AccessTy) { const SCEV *Copy = Expr; int64_t Offset = ExtractImmediate(Expr, SE); // Basic uses can't accept any offset, for example. if (!isAlwaysFoldable(TTI, Kind, AccessTy, /*BaseGV=*/ nullptr, Offset, /*HasBaseReg=*/ true)) { Expr = Copy; Offset = 0; } std::pair P = UseMap.insert(std::make_pair(LSRUse::SCEVUseKindPair(Expr, Kind), 0)); if (!P.second) { // A use already existed with this base. size_t LUIdx = P.first->second; LSRUse &LU = Uses[LUIdx]; if (reconcileNewOffset(LU, Offset, /*HasBaseReg=*/true, Kind, AccessTy)) // Reuse this use. return std::make_pair(LUIdx, Offset); } // Create a new use. size_t LUIdx = Uses.size(); P.first->second = LUIdx; Uses.push_back(LSRUse(Kind, AccessTy)); LSRUse &LU = Uses[LUIdx]; // We don't need to track redundant offsets, but we don't need to go out // of our way here to avoid them. if (LU.Offsets.empty() || Offset != LU.Offsets.back()) LU.Offsets.push_back(Offset); LU.MinOffset = Offset; LU.MaxOffset = Offset; return std::make_pair(LUIdx, Offset); } /// Delete the given use from the Uses list. void LSRInstance::DeleteUse(LSRUse &LU, size_t LUIdx) { if (&LU != &Uses.back()) std::swap(LU, Uses.back()); Uses.pop_back(); // Update RegUses. RegUses.swapAndDropUse(LUIdx, Uses.size()); } /// Look for a use distinct from OrigLU which is has a formula that has the same /// registers as the given formula. LSRUse * LSRInstance::FindUseWithSimilarFormula(const Formula &OrigF, const LSRUse &OrigLU) { // Search all uses for the formula. This could be more clever. for (size_t LUIdx = 0, NumUses = Uses.size(); LUIdx != NumUses; ++LUIdx) { LSRUse &LU = Uses[LUIdx]; // Check whether this use is close enough to OrigLU, to see whether it's // worthwhile looking through its formulae. // Ignore ICmpZero uses because they may contain formulae generated by // GenerateICmpZeroScales, in which case adding fixup offsets may // be invalid. if (&LU != &OrigLU && LU.Kind != LSRUse::ICmpZero && LU.Kind == OrigLU.Kind && OrigLU.AccessTy == LU.AccessTy && LU.WidestFixupType == OrigLU.WidestFixupType && LU.HasFormulaWithSameRegs(OrigF)) { // Scan through this use's formulae. for (const Formula &F : LU.Formulae) { // Check to see if this formula has the same registers and symbols // as OrigF. if (F.BaseRegs == OrigF.BaseRegs && F.ScaledReg == OrigF.ScaledReg && F.BaseGV == OrigF.BaseGV && F.Scale == OrigF.Scale && F.UnfoldedOffset == OrigF.UnfoldedOffset) { if (F.BaseOffset == 0) return &LU; // This is the formula where all the registers and symbols matched; // there aren't going to be any others. Since we declined it, we // can skip the rest of the formulae and proceed to the next LSRUse. break; } } } } // Nothing looked good. return nullptr; } void LSRInstance::CollectInterestingTypesAndFactors() { SmallSetVector Strides; // Collect interesting types and strides. SmallVector Worklist; for (const IVStrideUse &U : IU) { const SCEV *Expr = IU.getExpr(U); // Collect interesting types. Types.insert(SE.getEffectiveSCEVType(Expr->getType())); // Add strides for mentioned loops. Worklist.push_back(Expr); do { const SCEV *S = Worklist.pop_back_val(); if (const SCEVAddRecExpr *AR = dyn_cast(S)) { if (AR->getLoop() == L) Strides.insert(AR->getStepRecurrence(SE)); Worklist.push_back(AR->getStart()); } else if (const SCEVAddExpr *Add = dyn_cast(S)) { Worklist.append(Add->op_begin(), Add->op_end()); } } while (!Worklist.empty()); } // Compute interesting factors from the set of interesting strides. for (SmallSetVector::const_iterator I = Strides.begin(), E = Strides.end(); I != E; ++I) for (SmallSetVector::const_iterator NewStrideIter = std::next(I); NewStrideIter != E; ++NewStrideIter) { const SCEV *OldStride = *I; const SCEV *NewStride = *NewStrideIter; if (SE.getTypeSizeInBits(OldStride->getType()) != SE.getTypeSizeInBits(NewStride->getType())) { if (SE.getTypeSizeInBits(OldStride->getType()) > SE.getTypeSizeInBits(NewStride->getType())) NewStride = SE.getSignExtendExpr(NewStride, OldStride->getType()); else OldStride = SE.getSignExtendExpr(OldStride, NewStride->getType()); } if (const SCEVConstant *Factor = dyn_cast_or_null(getExactSDiv(NewStride, OldStride, SE, true))) { if (Factor->getAPInt().getMinSignedBits() <= 64) Factors.insert(Factor->getAPInt().getSExtValue()); } else if (const SCEVConstant *Factor = dyn_cast_or_null(getExactSDiv(OldStride, NewStride, SE, true))) { if (Factor->getAPInt().getMinSignedBits() <= 64) Factors.insert(Factor->getAPInt().getSExtValue()); } } // If all uses use the same type, don't bother looking for truncation-based // reuse. if (Types.size() == 1) Types.clear(); DEBUG(print_factors_and_types(dbgs())); } /// Helper for CollectChains that finds an IV operand (computed by an AddRec in /// this loop) within [OI,OE) or returns OE. If IVUsers mapped Instructions to /// IVStrideUses, we could partially skip this. static User::op_iterator findIVOperand(User::op_iterator OI, User::op_iterator OE, Loop *L, ScalarEvolution &SE) { for(; OI != OE; ++OI) { if (Instruction *Oper = dyn_cast(*OI)) { if (!SE.isSCEVable(Oper->getType())) continue; if (const SCEVAddRecExpr *AR = dyn_cast(SE.getSCEV(Oper))) { if (AR->getLoop() == L) break; } } } return OI; } /// IVChain logic must consistenctly peek base TruncInst operands, so wrap it in /// a convenient helper. static Value *getWideOperand(Value *Oper) { if (TruncInst *Trunc = dyn_cast(Oper)) return Trunc->getOperand(0); return Oper; } /// Return true if we allow an IV chain to include both types. static bool isCompatibleIVType(Value *LVal, Value *RVal) { Type *LType = LVal->getType(); Type *RType = RVal->getType(); return (LType == RType) || (LType->isPointerTy() && RType->isPointerTy()); } /// Return an approximation of this SCEV expression's "base", or NULL for any /// constant. Returning the expression itself is conservative. Returning a /// deeper subexpression is more precise and valid as long as it isn't less /// complex than another subexpression. For expressions involving multiple /// unscaled values, we need to return the pointer-type SCEVUnknown. This avoids /// forming chains across objects, such as: PrevOper==a[i], IVOper==b[i], /// IVInc==b-a. /// /// Since SCEVUnknown is the rightmost type, and pointers are the rightmost /// SCEVUnknown, we simply return the rightmost SCEV operand. static const SCEV *getExprBase(const SCEV *S) { switch (S->getSCEVType()) { default: // uncluding scUnknown. return S; case scConstant: return nullptr; case scTruncate: return getExprBase(cast(S)->getOperand()); case scZeroExtend: return getExprBase(cast(S)->getOperand()); case scSignExtend: return getExprBase(cast(S)->getOperand()); case scAddExpr: { // Skip over scaled operands (scMulExpr) to follow add operands as long as // there's nothing more complex. // FIXME: not sure if we want to recognize negation. const SCEVAddExpr *Add = cast(S); for (std::reverse_iterator I(Add->op_end()), E(Add->op_begin()); I != E; ++I) { const SCEV *SubExpr = *I; if (SubExpr->getSCEVType() == scAddExpr) return getExprBase(SubExpr); if (SubExpr->getSCEVType() != scMulExpr) return SubExpr; } return S; // all operands are scaled, be conservative. } case scAddRecExpr: return getExprBase(cast(S)->getStart()); } } /// Return true if the chain increment is profitable to expand into a loop /// invariant value, which may require its own register. A profitable chain /// increment will be an offset relative to the same base. We allow such offsets /// to potentially be used as chain increment as long as it's not obviously /// expensive to expand using real instructions. bool IVChain::isProfitableIncrement(const SCEV *OperExpr, const SCEV *IncExpr, ScalarEvolution &SE) { // Aggressively form chains when -stress-ivchain. if (StressIVChain) return true; // Do not replace a constant offset from IV head with a nonconstant IV // increment. if (!isa(IncExpr)) { const SCEV *HeadExpr = SE.getSCEV(getWideOperand(Incs[0].IVOperand)); if (isa(SE.getMinusSCEV(OperExpr, HeadExpr))) return 0; } SmallPtrSet Processed; return !isHighCostExpansion(IncExpr, Processed, SE); } /// Return true if the number of registers needed for the chain is estimated to /// be less than the number required for the individual IV users. First prohibit /// any IV users that keep the IV live across increments (the Users set should /// be empty). Next count the number and type of increments in the chain. /// /// Chaining IVs can lead to considerable code bloat if ISEL doesn't /// effectively use postinc addressing modes. Only consider it profitable it the /// increments can be computed in fewer registers when chained. /// /// TODO: Consider IVInc free if it's already used in another chains. static bool isProfitableChain(IVChain &Chain, SmallPtrSetImpl &Users, ScalarEvolution &SE, const TargetTransformInfo &TTI) { if (StressIVChain) return true; if (!Chain.hasIncs()) return false; if (!Users.empty()) { DEBUG(dbgs() << "Chain: " << *Chain.Incs[0].UserInst << " users:\n"; for (Instruction *Inst : Users) { dbgs() << " " << *Inst << "\n"; }); return false; } assert(!Chain.Incs.empty() && "empty IV chains are not allowed"); // The chain itself may require a register, so intialize cost to 1. int cost = 1; // A complete chain likely eliminates the need for keeping the original IV in // a register. LSR does not currently know how to form a complete chain unless // the header phi already exists. if (isa(Chain.tailUserInst()) && SE.getSCEV(Chain.tailUserInst()) == Chain.Incs[0].IncExpr) { --cost; } const SCEV *LastIncExpr = nullptr; unsigned NumConstIncrements = 0; unsigned NumVarIncrements = 0; unsigned NumReusedIncrements = 0; for (const IVInc &Inc : Chain) { if (Inc.IncExpr->isZero()) continue; // Incrementing by zero or some constant is neutral. We assume constants can // be folded into an addressing mode or an add's immediate operand. if (isa(Inc.IncExpr)) { ++NumConstIncrements; continue; } if (Inc.IncExpr == LastIncExpr) ++NumReusedIncrements; else ++NumVarIncrements; LastIncExpr = Inc.IncExpr; } // An IV chain with a single increment is handled by LSR's postinc // uses. However, a chain with multiple increments requires keeping the IV's // value live longer than it needs to be if chained. if (NumConstIncrements > 1) --cost; // Materializing increment expressions in the preheader that didn't exist in // the original code may cost a register. For example, sign-extended array // indices can produce ridiculous increments like this: // IV + ((sext i32 (2 * %s) to i64) + (-1 * (sext i32 %s to i64))) cost += NumVarIncrements; // Reusing variable increments likely saves a register to hold the multiple of // the stride. cost -= NumReusedIncrements; DEBUG(dbgs() << "Chain: " << *Chain.Incs[0].UserInst << " Cost: " << cost << "\n"); return cost < 0; } /// Add this IV user to an existing chain or make it the head of a new chain. void LSRInstance::ChainInstruction(Instruction *UserInst, Instruction *IVOper, SmallVectorImpl &ChainUsersVec) { // When IVs are used as types of varying widths, they are generally converted // to a wider type with some uses remaining narrow under a (free) trunc. Value *const NextIV = getWideOperand(IVOper); const SCEV *const OperExpr = SE.getSCEV(NextIV); const SCEV *const OperExprBase = getExprBase(OperExpr); // Visit all existing chains. Check if its IVOper can be computed as a // profitable loop invariant increment from the last link in the Chain. unsigned ChainIdx = 0, NChains = IVChainVec.size(); const SCEV *LastIncExpr = nullptr; for (; ChainIdx < NChains; ++ChainIdx) { IVChain &Chain = IVChainVec[ChainIdx]; // Prune the solution space aggressively by checking that both IV operands // are expressions that operate on the same unscaled SCEVUnknown. This // "base" will be canceled by the subsequent getMinusSCEV call. Checking // first avoids creating extra SCEV expressions. if (!StressIVChain && Chain.ExprBase != OperExprBase) continue; Value *PrevIV = getWideOperand(Chain.Incs.back().IVOperand); if (!isCompatibleIVType(PrevIV, NextIV)) continue; // A phi node terminates a chain. if (isa(UserInst) && isa(Chain.tailUserInst())) continue; // The increment must be loop-invariant so it can be kept in a register. const SCEV *PrevExpr = SE.getSCEV(PrevIV); const SCEV *IncExpr = SE.getMinusSCEV(OperExpr, PrevExpr); if (!SE.isLoopInvariant(IncExpr, L)) continue; if (Chain.isProfitableIncrement(OperExpr, IncExpr, SE)) { LastIncExpr = IncExpr; break; } } // If we haven't found a chain, create a new one, unless we hit the max. Don't // bother for phi nodes, because they must be last in the chain. if (ChainIdx == NChains) { if (isa(UserInst)) return; if (NChains >= MaxChains && !StressIVChain) { DEBUG(dbgs() << "IV Chain Limit\n"); return; } LastIncExpr = OperExpr; // IVUsers may have skipped over sign/zero extensions. We don't currently // attempt to form chains involving extensions unless they can be hoisted // into this loop's AddRec. if (!isa(LastIncExpr)) return; ++NChains; IVChainVec.push_back(IVChain(IVInc(UserInst, IVOper, LastIncExpr), OperExprBase)); ChainUsersVec.resize(NChains); DEBUG(dbgs() << "IV Chain#" << ChainIdx << " Head: (" << *UserInst << ") IV=" << *LastIncExpr << "\n"); } else { DEBUG(dbgs() << "IV Chain#" << ChainIdx << " Inc: (" << *UserInst << ") IV+" << *LastIncExpr << "\n"); // Add this IV user to the end of the chain. IVChainVec[ChainIdx].add(IVInc(UserInst, IVOper, LastIncExpr)); } IVChain &Chain = IVChainVec[ChainIdx]; SmallPtrSet &NearUsers = ChainUsersVec[ChainIdx].NearUsers; // This chain's NearUsers become FarUsers. if (!LastIncExpr->isZero()) { ChainUsersVec[ChainIdx].FarUsers.insert(NearUsers.begin(), NearUsers.end()); NearUsers.clear(); } // All other uses of IVOperand become near uses of the chain. // We currently ignore intermediate values within SCEV expressions, assuming // they will eventually be used be the current chain, or can be computed // from one of the chain increments. To be more precise we could // transitively follow its user and only add leaf IV users to the set. for (User *U : IVOper->users()) { Instruction *OtherUse = dyn_cast(U); if (!OtherUse) continue; // Uses in the chain will no longer be uses if the chain is formed. // Include the head of the chain in this iteration (not Chain.begin()). IVChain::const_iterator IncIter = Chain.Incs.begin(); IVChain::const_iterator IncEnd = Chain.Incs.end(); for( ; IncIter != IncEnd; ++IncIter) { if (IncIter->UserInst == OtherUse) break; } if (IncIter != IncEnd) continue; if (SE.isSCEVable(OtherUse->getType()) && !isa(SE.getSCEV(OtherUse)) && IU.isIVUserOrOperand(OtherUse)) { continue; } NearUsers.insert(OtherUse); } // Since this user is part of the chain, it's no longer considered a use // of the chain. ChainUsersVec[ChainIdx].FarUsers.erase(UserInst); } /// Populate the vector of Chains. /// /// This decreases ILP at the architecture level. Targets with ample registers, /// multiple memory ports, and no register renaming probably don't want /// this. However, such targets should probably disable LSR altogether. /// /// The job of LSR is to make a reasonable choice of induction variables across /// the loop. Subsequent passes can easily "unchain" computation exposing more /// ILP *within the loop* if the target wants it. /// /// Finding the best IV chain is potentially a scheduling problem. Since LSR /// will not reorder memory operations, it will recognize this as a chain, but /// will generate redundant IV increments. Ideally this would be corrected later /// by a smart scheduler: /// = A[i] /// = A[i+x] /// A[i] = /// A[i+x] = /// /// TODO: Walk the entire domtree within this loop, not just the path to the /// loop latch. This will discover chains on side paths, but requires /// maintaining multiple copies of the Chains state. void LSRInstance::CollectChains() { DEBUG(dbgs() << "Collecting IV Chains.\n"); SmallVector ChainUsersVec; SmallVector LatchPath; BasicBlock *LoopHeader = L->getHeader(); for (DomTreeNode *Rung = DT.getNode(L->getLoopLatch()); Rung->getBlock() != LoopHeader; Rung = Rung->getIDom()) { LatchPath.push_back(Rung->getBlock()); } LatchPath.push_back(LoopHeader); // Walk the instruction stream from the loop header to the loop latch. for (SmallVectorImpl::reverse_iterator BBIter = LatchPath.rbegin(), BBEnd = LatchPath.rend(); BBIter != BBEnd; ++BBIter) { for (BasicBlock::iterator I = (*BBIter)->begin(), E = (*BBIter)->end(); I != E; ++I) { // Skip instructions that weren't seen by IVUsers analysis. if (isa(I) || !IU.isIVUserOrOperand(&*I)) continue; // Ignore users that are part of a SCEV expression. This way we only // consider leaf IV Users. This effectively rediscovers a portion of // IVUsers analysis but in program order this time. if (SE.isSCEVable(I->getType()) && !isa(SE.getSCEV(&*I))) continue; // Remove this instruction from any NearUsers set it may be in. for (unsigned ChainIdx = 0, NChains = IVChainVec.size(); ChainIdx < NChains; ++ChainIdx) { ChainUsersVec[ChainIdx].NearUsers.erase(&*I); } // Search for operands that can be chained. SmallPtrSet UniqueOperands; User::op_iterator IVOpEnd = I->op_end(); User::op_iterator IVOpIter = findIVOperand(I->op_begin(), IVOpEnd, L, SE); while (IVOpIter != IVOpEnd) { Instruction *IVOpInst = cast(*IVOpIter); if (UniqueOperands.insert(IVOpInst).second) ChainInstruction(&*I, IVOpInst, ChainUsersVec); IVOpIter = findIVOperand(std::next(IVOpIter), IVOpEnd, L, SE); } } // Continue walking down the instructions. } // Continue walking down the domtree. // Visit phi backedges to determine if the chain can generate the IV postinc. for (BasicBlock::iterator I = L->getHeader()->begin(); PHINode *PN = dyn_cast(I); ++I) { if (!SE.isSCEVable(PN->getType())) continue; Instruction *IncV = dyn_cast(PN->getIncomingValueForBlock(L->getLoopLatch())); if (IncV) ChainInstruction(PN, IncV, ChainUsersVec); } // Remove any unprofitable chains. unsigned ChainIdx = 0; for (unsigned UsersIdx = 0, NChains = IVChainVec.size(); UsersIdx < NChains; ++UsersIdx) { if (!isProfitableChain(IVChainVec[UsersIdx], ChainUsersVec[UsersIdx].FarUsers, SE, TTI)) continue; // Preserve the chain at UsesIdx. if (ChainIdx != UsersIdx) IVChainVec[ChainIdx] = IVChainVec[UsersIdx]; FinalizeChain(IVChainVec[ChainIdx]); ++ChainIdx; } IVChainVec.resize(ChainIdx); } void LSRInstance::FinalizeChain(IVChain &Chain) { assert(!Chain.Incs.empty() && "empty IV chains are not allowed"); DEBUG(dbgs() << "Final Chain: " << *Chain.Incs[0].UserInst << "\n"); for (const IVInc &Inc : Chain) { DEBUG(dbgs() << " Inc: " << Inc.UserInst << "\n"); auto UseI = std::find(Inc.UserInst->op_begin(), Inc.UserInst->op_end(), Inc.IVOperand); assert(UseI != Inc.UserInst->op_end() && "cannot find IV operand"); IVIncSet.insert(UseI); } } /// Return true if the IVInc can be folded into an addressing mode. static bool canFoldIVIncExpr(const SCEV *IncExpr, Instruction *UserInst, Value *Operand, const TargetTransformInfo &TTI) { const SCEVConstant *IncConst = dyn_cast(IncExpr); if (!IncConst || !isAddressUse(UserInst, Operand)) return false; if (IncConst->getAPInt().getMinSignedBits() > 64) return false; MemAccessTy AccessTy = getAccessType(UserInst); int64_t IncOffset = IncConst->getValue()->getSExtValue(); if (!isAlwaysFoldable(TTI, LSRUse::Address, AccessTy, /*BaseGV=*/nullptr, IncOffset, /*HaseBaseReg=*/false)) return false; return true; } /// Generate an add or subtract for each IVInc in a chain to materialize the IV /// user's operand from the previous IV user's operand. void LSRInstance::GenerateIVChain(const IVChain &Chain, SCEVExpander &Rewriter, SmallVectorImpl &DeadInsts) { // Find the new IVOperand for the head of the chain. It may have been replaced // by LSR. const IVInc &Head = Chain.Incs[0]; User::op_iterator IVOpEnd = Head.UserInst->op_end(); // findIVOperand returns IVOpEnd if it can no longer find a valid IV user. User::op_iterator IVOpIter = findIVOperand(Head.UserInst->op_begin(), IVOpEnd, L, SE); Value *IVSrc = nullptr; while (IVOpIter != IVOpEnd) { IVSrc = getWideOperand(*IVOpIter); // If this operand computes the expression that the chain needs, we may use // it. (Check this after setting IVSrc which is used below.) // // Note that if Head.IncExpr is wider than IVSrc, then this phi is too // narrow for the chain, so we can no longer use it. We do allow using a // wider phi, assuming the LSR checked for free truncation. In that case we // should already have a truncate on this operand such that // getSCEV(IVSrc) == IncExpr. if (SE.getSCEV(*IVOpIter) == Head.IncExpr || SE.getSCEV(IVSrc) == Head.IncExpr) { break; } IVOpIter = findIVOperand(std::next(IVOpIter), IVOpEnd, L, SE); } if (IVOpIter == IVOpEnd) { // Gracefully give up on this chain. DEBUG(dbgs() << "Concealed chain head: " << *Head.UserInst << "\n"); return; } DEBUG(dbgs() << "Generate chain at: " << *IVSrc << "\n"); Type *IVTy = IVSrc->getType(); Type *IntTy = SE.getEffectiveSCEVType(IVTy); const SCEV *LeftOverExpr = nullptr; for (const IVInc &Inc : Chain) { Instruction *InsertPt = Inc.UserInst; if (isa(InsertPt)) InsertPt = L->getLoopLatch()->getTerminator(); // IVOper will replace the current IV User's operand. IVSrc is the IV // value currently held in a register. Value *IVOper = IVSrc; if (!Inc.IncExpr->isZero()) { // IncExpr was the result of subtraction of two narrow values, so must // be signed. const SCEV *IncExpr = SE.getNoopOrSignExtend(Inc.IncExpr, IntTy); LeftOverExpr = LeftOverExpr ? SE.getAddExpr(LeftOverExpr, IncExpr) : IncExpr; } if (LeftOverExpr && !LeftOverExpr->isZero()) { // Expand the IV increment. Rewriter.clearPostInc(); Value *IncV = Rewriter.expandCodeFor(LeftOverExpr, IntTy, InsertPt); const SCEV *IVOperExpr = SE.getAddExpr(SE.getUnknown(IVSrc), SE.getUnknown(IncV)); IVOper = Rewriter.expandCodeFor(IVOperExpr, IVTy, InsertPt); // If an IV increment can't be folded, use it as the next IV value. if (!canFoldIVIncExpr(LeftOverExpr, Inc.UserInst, Inc.IVOperand, TTI)) { assert(IVTy == IVOper->getType() && "inconsistent IV increment type"); IVSrc = IVOper; LeftOverExpr = nullptr; } } Type *OperTy = Inc.IVOperand->getType(); if (IVTy != OperTy) { assert(SE.getTypeSizeInBits(IVTy) >= SE.getTypeSizeInBits(OperTy) && "cannot extend a chained IV"); IRBuilder<> Builder(InsertPt); IVOper = Builder.CreateTruncOrBitCast(IVOper, OperTy, "lsr.chain"); } Inc.UserInst->replaceUsesOfWith(Inc.IVOperand, IVOper); DeadInsts.emplace_back(Inc.IVOperand); } // If LSR created a new, wider phi, we may also replace its postinc. We only // do this if we also found a wide value for the head of the chain. if (isa(Chain.tailUserInst())) { for (BasicBlock::iterator I = L->getHeader()->begin(); PHINode *Phi = dyn_cast(I); ++I) { if (!isCompatibleIVType(Phi, IVSrc)) continue; Instruction *PostIncV = dyn_cast( Phi->getIncomingValueForBlock(L->getLoopLatch())); if (!PostIncV || (SE.getSCEV(PostIncV) != SE.getSCEV(IVSrc))) continue; Value *IVOper = IVSrc; Type *PostIncTy = PostIncV->getType(); if (IVTy != PostIncTy) { assert(PostIncTy->isPointerTy() && "mixing int/ptr IV types"); IRBuilder<> Builder(L->getLoopLatch()->getTerminator()); Builder.SetCurrentDebugLocation(PostIncV->getDebugLoc()); IVOper = Builder.CreatePointerCast(IVSrc, PostIncTy, "lsr.chain"); } Phi->replaceUsesOfWith(PostIncV, IVOper); DeadInsts.emplace_back(PostIncV); } } } void LSRInstance::CollectFixupsAndInitialFormulae() { for (const IVStrideUse &U : IU) { Instruction *UserInst = U.getUser(); // Skip IV users that are part of profitable IV Chains. User::op_iterator UseI = std::find(UserInst->op_begin(), UserInst->op_end(), U.getOperandValToReplace()); assert(UseI != UserInst->op_end() && "cannot find IV operand"); if (IVIncSet.count(UseI)) continue; // Record the uses. LSRFixup &LF = getNewFixup(); LF.UserInst = UserInst; LF.OperandValToReplace = U.getOperandValToReplace(); LF.PostIncLoops = U.getPostIncLoops(); LSRUse::KindType Kind = LSRUse::Basic; MemAccessTy AccessTy; if (isAddressUse(LF.UserInst, LF.OperandValToReplace)) { Kind = LSRUse::Address; AccessTy = getAccessType(LF.UserInst); } const SCEV *S = IU.getExpr(U); // Equality (== and !=) ICmps are special. We can rewrite (i == N) as // (N - i == 0), and this allows (N - i) to be the expression that we work // with rather than just N or i, so we can consider the register // requirements for both N and i at the same time. Limiting this code to // equality icmps is not a problem because all interesting loops use // equality icmps, thanks to IndVarSimplify. if (ICmpInst *CI = dyn_cast(LF.UserInst)) if (CI->isEquality()) { // Swap the operands if needed to put the OperandValToReplace on the // left, for consistency. Value *NV = CI->getOperand(1); if (NV == LF.OperandValToReplace) { CI->setOperand(1, CI->getOperand(0)); CI->setOperand(0, NV); NV = CI->getOperand(1); Changed = true; } // x == y --> x - y == 0 const SCEV *N = SE.getSCEV(NV); if (SE.isLoopInvariant(N, L) && isSafeToExpand(N, SE)) { // S is normalized, so normalize N before folding it into S // to keep the result normalized. N = TransformForPostIncUse(Normalize, N, CI, nullptr, LF.PostIncLoops, SE, DT); Kind = LSRUse::ICmpZero; S = SE.getMinusSCEV(N, S); } // -1 and the negations of all interesting strides (except the negation // of -1) are now also interesting. for (size_t i = 0, e = Factors.size(); i != e; ++i) if (Factors[i] != -1) Factors.insert(-(uint64_t)Factors[i]); Factors.insert(-1); } // Set up the initial formula for this use. std::pair P = getUse(S, Kind, AccessTy); LF.LUIdx = P.first; LF.Offset = P.second; LSRUse &LU = Uses[LF.LUIdx]; LU.AllFixupsOutsideLoop &= LF.isUseFullyOutsideLoop(L); if (!LU.WidestFixupType || SE.getTypeSizeInBits(LU.WidestFixupType) < SE.getTypeSizeInBits(LF.OperandValToReplace->getType())) LU.WidestFixupType = LF.OperandValToReplace->getType(); // If this is the first use of this LSRUse, give it a formula. if (LU.Formulae.empty()) { InsertInitialFormula(S, LU, LF.LUIdx); CountRegisters(LU.Formulae.back(), LF.LUIdx); } } DEBUG(print_fixups(dbgs())); } /// Insert a formula for the given expression into the given use, separating out /// loop-variant portions from loop-invariant and loop-computable portions. void LSRInstance::InsertInitialFormula(const SCEV *S, LSRUse &LU, size_t LUIdx) { // Mark uses whose expressions cannot be expanded. if (!isSafeToExpand(S, SE)) LU.RigidFormula = true; Formula F; F.initialMatch(S, L, SE); bool Inserted = InsertFormula(LU, LUIdx, F); assert(Inserted && "Initial formula already exists!"); (void)Inserted; } /// Insert a simple single-register formula for the given expression into the /// given use. void LSRInstance::InsertSupplementalFormula(const SCEV *S, LSRUse &LU, size_t LUIdx) { Formula F; F.BaseRegs.push_back(S); F.HasBaseReg = true; bool Inserted = InsertFormula(LU, LUIdx, F); assert(Inserted && "Supplemental formula already exists!"); (void)Inserted; } /// Note which registers are used by the given formula, updating RegUses. void LSRInstance::CountRegisters(const Formula &F, size_t LUIdx) { if (F.ScaledReg) RegUses.countRegister(F.ScaledReg, LUIdx); for (const SCEV *BaseReg : F.BaseRegs) RegUses.countRegister(BaseReg, LUIdx); } /// If the given formula has not yet been inserted, add it to the list, and /// return true. Return false otherwise. bool LSRInstance::InsertFormula(LSRUse &LU, unsigned LUIdx, const Formula &F) { // Do not insert formula that we will not be able to expand. assert(isLegalUse(TTI, LU.MinOffset, LU.MaxOffset, LU.Kind, LU.AccessTy, F) && "Formula is illegal"); if (!LU.InsertFormula(F)) return false; CountRegisters(F, LUIdx); return true; } /// Check for other uses of loop-invariant values which we're tracking. These /// other uses will pin these values in registers, making them less profitable /// for elimination. /// TODO: This currently misses non-constant addrec step registers. /// TODO: Should this give more weight to users inside the loop? void LSRInstance::CollectLoopInvariantFixupsAndFormulae() { SmallVector Worklist(RegUses.begin(), RegUses.end()); SmallPtrSet Visited; while (!Worklist.empty()) { const SCEV *S = Worklist.pop_back_val(); // Don't process the same SCEV twice if (!Visited.insert(S).second) continue; if (const SCEVNAryExpr *N = dyn_cast(S)) Worklist.append(N->op_begin(), N->op_end()); else if (const SCEVCastExpr *C = dyn_cast(S)) Worklist.push_back(C->getOperand()); else if (const SCEVUDivExpr *D = dyn_cast(S)) { Worklist.push_back(D->getLHS()); Worklist.push_back(D->getRHS()); } else if (const SCEVUnknown *US = dyn_cast(S)) { const Value *V = US->getValue(); if (const Instruction *Inst = dyn_cast(V)) { // Look for instructions defined outside the loop. if (L->contains(Inst)) continue; } else if (isa(V)) // Undef doesn't have a live range, so it doesn't matter. continue; for (const Use &U : V->uses()) { const Instruction *UserInst = dyn_cast(U.getUser()); // Ignore non-instructions. if (!UserInst) continue; // Ignore instructions in other functions (as can happen with // Constants). if (UserInst->getParent()->getParent() != L->getHeader()->getParent()) continue; // Ignore instructions not dominated by the loop. const BasicBlock *UseBB = !isa(UserInst) ? UserInst->getParent() : cast(UserInst)->getIncomingBlock( PHINode::getIncomingValueNumForOperand(U.getOperandNo())); if (!DT.dominates(L->getHeader(), UseBB)) continue; // Don't bother if the instruction is in a BB which ends in an EHPad. if (UseBB->getTerminator()->isEHPad()) continue; // Ignore uses which are part of other SCEV expressions, to avoid // analyzing them multiple times. if (SE.isSCEVable(UserInst->getType())) { const SCEV *UserS = SE.getSCEV(const_cast(UserInst)); // If the user is a no-op, look through to its uses. if (!isa(UserS)) continue; if (UserS == US) { Worklist.push_back( SE.getUnknown(const_cast(UserInst))); continue; } } // Ignore icmp instructions which are already being analyzed. if (const ICmpInst *ICI = dyn_cast(UserInst)) { unsigned OtherIdx = !U.getOperandNo(); Value *OtherOp = const_cast(ICI->getOperand(OtherIdx)); if (SE.hasComputableLoopEvolution(SE.getSCEV(OtherOp), L)) continue; } LSRFixup &LF = getNewFixup(); LF.UserInst = const_cast(UserInst); LF.OperandValToReplace = U; std::pair P = getUse( S, LSRUse::Basic, MemAccessTy()); LF.LUIdx = P.first; LF.Offset = P.second; LSRUse &LU = Uses[LF.LUIdx]; LU.AllFixupsOutsideLoop &= LF.isUseFullyOutsideLoop(L); if (!LU.WidestFixupType || SE.getTypeSizeInBits(LU.WidestFixupType) < SE.getTypeSizeInBits(LF.OperandValToReplace->getType())) LU.WidestFixupType = LF.OperandValToReplace->getType(); InsertSupplementalFormula(US, LU, LF.LUIdx); CountRegisters(LU.Formulae.back(), Uses.size() - 1); break; } } } } /// Split S into subexpressions which can be pulled out into separate /// registers. If C is non-null, multiply each subexpression by C. /// /// Return remainder expression after factoring the subexpressions captured by /// Ops. If Ops is complete, return NULL. static const SCEV *CollectSubexprs(const SCEV *S, const SCEVConstant *C, SmallVectorImpl &Ops, const Loop *L, ScalarEvolution &SE, unsigned Depth = 0) { // Arbitrarily cap recursion to protect compile time. if (Depth >= 3) return S; if (const SCEVAddExpr *Add = dyn_cast(S)) { // Break out add operands. for (const SCEV *S : Add->operands()) { const SCEV *Remainder = CollectSubexprs(S, C, Ops, L, SE, Depth+1); if (Remainder) Ops.push_back(C ? SE.getMulExpr(C, Remainder) : Remainder); } return nullptr; } else if (const SCEVAddRecExpr *AR = dyn_cast(S)) { // Split a non-zero base out of an addrec. if (AR->getStart()->isZero()) return S; const SCEV *Remainder = CollectSubexprs(AR->getStart(), C, Ops, L, SE, Depth+1); // Split the non-zero AddRec unless it is part of a nested recurrence that // does not pertain to this loop. if (Remainder && (AR->getLoop() == L || !isa(Remainder))) { Ops.push_back(C ? SE.getMulExpr(C, Remainder) : Remainder); Remainder = nullptr; } if (Remainder != AR->getStart()) { if (!Remainder) Remainder = SE.getConstant(AR->getType(), 0); return SE.getAddRecExpr(Remainder, AR->getStepRecurrence(SE), AR->getLoop(), //FIXME: AR->getNoWrapFlags(SCEV::FlagNW) SCEV::FlagAnyWrap); } } else if (const SCEVMulExpr *Mul = dyn_cast(S)) { // Break (C * (a + b + c)) into C*a + C*b + C*c. if (Mul->getNumOperands() != 2) return S; if (const SCEVConstant *Op0 = dyn_cast(Mul->getOperand(0))) { C = C ? cast(SE.getMulExpr(C, Op0)) : Op0; const SCEV *Remainder = CollectSubexprs(Mul->getOperand(1), C, Ops, L, SE, Depth+1); if (Remainder) Ops.push_back(SE.getMulExpr(C, Remainder)); return nullptr; } } return S; } /// \brief Helper function for LSRInstance::GenerateReassociations. void LSRInstance::GenerateReassociationsImpl(LSRUse &LU, unsigned LUIdx, const Formula &Base, unsigned Depth, size_t Idx, bool IsScaledReg) { const SCEV *BaseReg = IsScaledReg ? Base.ScaledReg : Base.BaseRegs[Idx]; SmallVector AddOps; const SCEV *Remainder = CollectSubexprs(BaseReg, nullptr, AddOps, L, SE); if (Remainder) AddOps.push_back(Remainder); if (AddOps.size() == 1) return; for (SmallVectorImpl::const_iterator J = AddOps.begin(), JE = AddOps.end(); J != JE; ++J) { // Loop-variant "unknown" values are uninteresting; we won't be able to // do anything meaningful with them. if (isa(*J) && !SE.isLoopInvariant(*J, L)) continue; // Don't pull a constant into a register if the constant could be folded // into an immediate field. if (isAlwaysFoldable(TTI, SE, LU.MinOffset, LU.MaxOffset, LU.Kind, LU.AccessTy, *J, Base.getNumRegs() > 1)) continue; // Collect all operands except *J. SmallVector InnerAddOps( ((const SmallVector &)AddOps).begin(), J); InnerAddOps.append(std::next(J), ((const SmallVector &)AddOps).end()); // Don't leave just a constant behind in a register if the constant could // be folded into an immediate field. if (InnerAddOps.size() == 1 && isAlwaysFoldable(TTI, SE, LU.MinOffset, LU.MaxOffset, LU.Kind, LU.AccessTy, InnerAddOps[0], Base.getNumRegs() > 1)) continue; const SCEV *InnerSum = SE.getAddExpr(InnerAddOps); if (InnerSum->isZero()) continue; Formula F = Base; // Add the remaining pieces of the add back into the new formula. const SCEVConstant *InnerSumSC = dyn_cast(InnerSum); if (InnerSumSC && SE.getTypeSizeInBits(InnerSumSC->getType()) <= 64 && TTI.isLegalAddImmediate((uint64_t)F.UnfoldedOffset + InnerSumSC->getValue()->getZExtValue())) { F.UnfoldedOffset = (uint64_t)F.UnfoldedOffset + InnerSumSC->getValue()->getZExtValue(); if (IsScaledReg) F.ScaledReg = nullptr; else F.BaseRegs.erase(F.BaseRegs.begin() + Idx); } else if (IsScaledReg) F.ScaledReg = InnerSum; else F.BaseRegs[Idx] = InnerSum; // Add J as its own register, or an unfolded immediate. const SCEVConstant *SC = dyn_cast(*J); if (SC && SE.getTypeSizeInBits(SC->getType()) <= 64 && TTI.isLegalAddImmediate((uint64_t)F.UnfoldedOffset + SC->getValue()->getZExtValue())) F.UnfoldedOffset = (uint64_t)F.UnfoldedOffset + SC->getValue()->getZExtValue(); else F.BaseRegs.push_back(*J); // We may have changed the number of register in base regs, adjust the // formula accordingly. F.canonicalize(); if (InsertFormula(LU, LUIdx, F)) // If that formula hadn't been seen before, recurse to find more like // it. GenerateReassociations(LU, LUIdx, LU.Formulae.back(), Depth + 1); } } /// Split out subexpressions from adds and the bases of addrecs. void LSRInstance::GenerateReassociations(LSRUse &LU, unsigned LUIdx, Formula Base, unsigned Depth) { assert(Base.isCanonical() && "Input must be in the canonical form"); // Arbitrarily cap recursion to protect compile time. if (Depth >= 3) return; for (size_t i = 0, e = Base.BaseRegs.size(); i != e; ++i) GenerateReassociationsImpl(LU, LUIdx, Base, Depth, i); if (Base.Scale == 1) GenerateReassociationsImpl(LU, LUIdx, Base, Depth, /* Idx */ -1, /* IsScaledReg */ true); } /// Generate a formula consisting of all of the loop-dominating registers added /// into a single register. void LSRInstance::GenerateCombinations(LSRUse &LU, unsigned LUIdx, Formula Base) { // This method is only interesting on a plurality of registers. if (Base.BaseRegs.size() + (Base.Scale == 1) <= 1) return; // Flatten the representation, i.e., reg1 + 1*reg2 => reg1 + reg2, before // processing the formula. Base.unscale(); Formula F = Base; F.BaseRegs.clear(); SmallVector Ops; for (const SCEV *BaseReg : Base.BaseRegs) { if (SE.properlyDominates(BaseReg, L->getHeader()) && !SE.hasComputableLoopEvolution(BaseReg, L)) Ops.push_back(BaseReg); else F.BaseRegs.push_back(BaseReg); } if (Ops.size() > 1) { const SCEV *Sum = SE.getAddExpr(Ops); // TODO: If Sum is zero, it probably means ScalarEvolution missed an // opportunity to fold something. For now, just ignore such cases // rather than proceed with zero in a register. if (!Sum->isZero()) { F.BaseRegs.push_back(Sum); F.canonicalize(); (void)InsertFormula(LU, LUIdx, F); } } } /// \brief Helper function for LSRInstance::GenerateSymbolicOffsets. void LSRInstance::GenerateSymbolicOffsetsImpl(LSRUse &LU, unsigned LUIdx, const Formula &Base, size_t Idx, bool IsScaledReg) { const SCEV *G = IsScaledReg ? Base.ScaledReg : Base.BaseRegs[Idx]; GlobalValue *GV = ExtractSymbol(G, SE); if (G->isZero() || !GV) return; Formula F = Base; F.BaseGV = GV; if (!isLegalUse(TTI, LU.MinOffset, LU.MaxOffset, LU.Kind, LU.AccessTy, F)) return; if (IsScaledReg) F.ScaledReg = G; else F.BaseRegs[Idx] = G; (void)InsertFormula(LU, LUIdx, F); } /// Generate reuse formulae using symbolic offsets. void LSRInstance::GenerateSymbolicOffsets(LSRUse &LU, unsigned LUIdx, Formula Base) { // We can't add a symbolic offset if the address already contains one. if (Base.BaseGV) return; for (size_t i = 0, e = Base.BaseRegs.size(); i != e; ++i) GenerateSymbolicOffsetsImpl(LU, LUIdx, Base, i); if (Base.Scale == 1) GenerateSymbolicOffsetsImpl(LU, LUIdx, Base, /* Idx */ -1, /* IsScaledReg */ true); } /// \brief Helper function for LSRInstance::GenerateConstantOffsets. void LSRInstance::GenerateConstantOffsetsImpl( LSRUse &LU, unsigned LUIdx, const Formula &Base, const SmallVectorImpl &Worklist, size_t Idx, bool IsScaledReg) { const SCEV *G = IsScaledReg ? Base.ScaledReg : Base.BaseRegs[Idx]; for (int64_t Offset : Worklist) { Formula F = Base; F.BaseOffset = (uint64_t)Base.BaseOffset - Offset; if (isLegalUse(TTI, LU.MinOffset - Offset, LU.MaxOffset - Offset, LU.Kind, LU.AccessTy, F)) { // Add the offset to the base register. const SCEV *NewG = SE.getAddExpr(SE.getConstant(G->getType(), Offset), G); // If it cancelled out, drop the base register, otherwise update it. if (NewG->isZero()) { if (IsScaledReg) { F.Scale = 0; F.ScaledReg = nullptr; } else F.deleteBaseReg(F.BaseRegs[Idx]); F.canonicalize(); } else if (IsScaledReg) F.ScaledReg = NewG; else F.BaseRegs[Idx] = NewG; (void)InsertFormula(LU, LUIdx, F); } } int64_t Imm = ExtractImmediate(G, SE); if (G->isZero() || Imm == 0) return; Formula F = Base; F.BaseOffset = (uint64_t)F.BaseOffset + Imm; if (!isLegalUse(TTI, LU.MinOffset, LU.MaxOffset, LU.Kind, LU.AccessTy, F)) return; if (IsScaledReg) F.ScaledReg = G; else F.BaseRegs[Idx] = G; (void)InsertFormula(LU, LUIdx, F); } /// GenerateConstantOffsets - Generate reuse formulae using symbolic offsets. void LSRInstance::GenerateConstantOffsets(LSRUse &LU, unsigned LUIdx, Formula Base) { // TODO: For now, just add the min and max offset, because it usually isn't // worthwhile looking at everything inbetween. SmallVector Worklist; Worklist.push_back(LU.MinOffset); if (LU.MaxOffset != LU.MinOffset) Worklist.push_back(LU.MaxOffset); for (size_t i = 0, e = Base.BaseRegs.size(); i != e; ++i) GenerateConstantOffsetsImpl(LU, LUIdx, Base, Worklist, i); if (Base.Scale == 1) GenerateConstantOffsetsImpl(LU, LUIdx, Base, Worklist, /* Idx */ -1, /* IsScaledReg */ true); } /// For ICmpZero, check to see if we can scale up the comparison. For example, x /// == y -> x*c == y*c. void LSRInstance::GenerateICmpZeroScales(LSRUse &LU, unsigned LUIdx, Formula Base) { if (LU.Kind != LSRUse::ICmpZero) return; // Determine the integer type for the base formula. Type *IntTy = Base.getType(); if (!IntTy) return; if (SE.getTypeSizeInBits(IntTy) > 64) return; // Don't do this if there is more than one offset. if (LU.MinOffset != LU.MaxOffset) return; assert(!Base.BaseGV && "ICmpZero use is not legal!"); // Check each interesting stride. for (int64_t Factor : Factors) { // Check that the multiplication doesn't overflow. if (Base.BaseOffset == INT64_MIN && Factor == -1) continue; int64_t NewBaseOffset = (uint64_t)Base.BaseOffset * Factor; if (NewBaseOffset / Factor != Base.BaseOffset) continue; // If the offset will be truncated at this use, check that it is in bounds. if (!IntTy->isPointerTy() && !ConstantInt::isValueValidForType(IntTy, NewBaseOffset)) continue; // Check that multiplying with the use offset doesn't overflow. int64_t Offset = LU.MinOffset; if (Offset == INT64_MIN && Factor == -1) continue; Offset = (uint64_t)Offset * Factor; if (Offset / Factor != LU.MinOffset) continue; // If the offset will be truncated at this use, check that it is in bounds. if (!IntTy->isPointerTy() && !ConstantInt::isValueValidForType(IntTy, Offset)) continue; Formula F = Base; F.BaseOffset = NewBaseOffset; // Check that this scale is legal. if (!isLegalUse(TTI, Offset, Offset, LU.Kind, LU.AccessTy, F)) continue; // Compensate for the use having MinOffset built into it. F.BaseOffset = (uint64_t)F.BaseOffset + Offset - LU.MinOffset; const SCEV *FactorS = SE.getConstant(IntTy, Factor); // Check that multiplying with each base register doesn't overflow. for (size_t i = 0, e = F.BaseRegs.size(); i != e; ++i) { F.BaseRegs[i] = SE.getMulExpr(F.BaseRegs[i], FactorS); if (getExactSDiv(F.BaseRegs[i], FactorS, SE) != Base.BaseRegs[i]) goto next; } // Check that multiplying with the scaled register doesn't overflow. if (F.ScaledReg) { F.ScaledReg = SE.getMulExpr(F.ScaledReg, FactorS); if (getExactSDiv(F.ScaledReg, FactorS, SE) != Base.ScaledReg) continue; } // Check that multiplying with the unfolded offset doesn't overflow. if (F.UnfoldedOffset != 0) { if (F.UnfoldedOffset == INT64_MIN && Factor == -1) continue; F.UnfoldedOffset = (uint64_t)F.UnfoldedOffset * Factor; if (F.UnfoldedOffset / Factor != Base.UnfoldedOffset) continue; // If the offset will be truncated, check that it is in bounds. if (!IntTy->isPointerTy() && !ConstantInt::isValueValidForType(IntTy, F.UnfoldedOffset)) continue; } // If we make it here and it's legal, add it. (void)InsertFormula(LU, LUIdx, F); next:; } } /// Generate stride factor reuse formulae by making use of scaled-offset address /// modes, for example. void LSRInstance::GenerateScales(LSRUse &LU, unsigned LUIdx, Formula Base) { // Determine the integer type for the base formula. Type *IntTy = Base.getType(); if (!IntTy) return; // If this Formula already has a scaled register, we can't add another one. // Try to unscale the formula to generate a better scale. if (Base.Scale != 0 && !Base.unscale()) return; assert(Base.Scale == 0 && "unscale did not did its job!"); // Check each interesting stride. for (int64_t Factor : Factors) { Base.Scale = Factor; Base.HasBaseReg = Base.BaseRegs.size() > 1; // Check whether this scale is going to be legal. if (!isLegalUse(TTI, LU.MinOffset, LU.MaxOffset, LU.Kind, LU.AccessTy, Base)) { // As a special-case, handle special out-of-loop Basic users specially. // TODO: Reconsider this special case. if (LU.Kind == LSRUse::Basic && isLegalUse(TTI, LU.MinOffset, LU.MaxOffset, LSRUse::Special, LU.AccessTy, Base) && LU.AllFixupsOutsideLoop) LU.Kind = LSRUse::Special; else continue; } // For an ICmpZero, negating a solitary base register won't lead to // new solutions. if (LU.Kind == LSRUse::ICmpZero && !Base.HasBaseReg && Base.BaseOffset == 0 && !Base.BaseGV) continue; // For each addrec base reg, apply the scale, if possible. for (size_t i = 0, e = Base.BaseRegs.size(); i != e; ++i) if (const SCEVAddRecExpr *AR = dyn_cast(Base.BaseRegs[i])) { const SCEV *FactorS = SE.getConstant(IntTy, Factor); if (FactorS->isZero()) continue; // Divide out the factor, ignoring high bits, since we'll be // scaling the value back up in the end. if (const SCEV *Quotient = getExactSDiv(AR, FactorS, SE, true)) { // TODO: This could be optimized to avoid all the copying. Formula F = Base; F.ScaledReg = Quotient; F.deleteBaseReg(F.BaseRegs[i]); // The canonical representation of 1*reg is reg, which is already in // Base. In that case, do not try to insert the formula, it will be // rejected anyway. if (F.Scale == 1 && F.BaseRegs.empty()) continue; (void)InsertFormula(LU, LUIdx, F); } } } } /// Generate reuse formulae from different IV types. void LSRInstance::GenerateTruncates(LSRUse &LU, unsigned LUIdx, Formula Base) { // Don't bother truncating symbolic values. if (Base.BaseGV) return; // Determine the integer type for the base formula. Type *DstTy = Base.getType(); if (!DstTy) return; DstTy = SE.getEffectiveSCEVType(DstTy); for (Type *SrcTy : Types) { if (SrcTy != DstTy && TTI.isTruncateFree(SrcTy, DstTy)) { Formula F = Base; if (F.ScaledReg) F.ScaledReg = SE.getAnyExtendExpr(F.ScaledReg, SrcTy); for (const SCEV *&BaseReg : F.BaseRegs) BaseReg = SE.getAnyExtendExpr(BaseReg, SrcTy); // TODO: This assumes we've done basic processing on all uses and // have an idea what the register usage is. if (!F.hasRegsUsedByUsesOtherThan(LUIdx, RegUses)) continue; (void)InsertFormula(LU, LUIdx, F); } } } namespace { /// Helper class for GenerateCrossUseConstantOffsets. It's used to defer /// modifications so that the search phase doesn't have to worry about the data /// structures moving underneath it. struct WorkItem { size_t LUIdx; int64_t Imm; const SCEV *OrigReg; WorkItem(size_t LI, int64_t I, const SCEV *R) : LUIdx(LI), Imm(I), OrigReg(R) {} void print(raw_ostream &OS) const; void dump() const; }; } void WorkItem::print(raw_ostream &OS) const { OS << "in formulae referencing " << *OrigReg << " in use " << LUIdx << " , add offset " << Imm; } LLVM_DUMP_METHOD void WorkItem::dump() const { print(errs()); errs() << '\n'; } /// Look for registers which are a constant distance apart and try to form reuse /// opportunities between them. void LSRInstance::GenerateCrossUseConstantOffsets() { // Group the registers by their value without any added constant offset. typedef std::map ImmMapTy; DenseMap Map; DenseMap UsedByIndicesMap; SmallVector Sequence; for (const SCEV *Use : RegUses) { const SCEV *Reg = Use; // Make a copy for ExtractImmediate to modify. int64_t Imm = ExtractImmediate(Reg, SE); auto Pair = Map.insert(std::make_pair(Reg, ImmMapTy())); if (Pair.second) Sequence.push_back(Reg); Pair.first->second.insert(std::make_pair(Imm, Use)); UsedByIndicesMap[Reg] |= RegUses.getUsedByIndices(Use); } // Now examine each set of registers with the same base value. Build up // a list of work to do and do the work in a separate step so that we're // not adding formulae and register counts while we're searching. SmallVector WorkItems; SmallSet, 32> UniqueItems; for (const SCEV *Reg : Sequence) { const ImmMapTy &Imms = Map.find(Reg)->second; // It's not worthwhile looking for reuse if there's only one offset. if (Imms.size() == 1) continue; DEBUG(dbgs() << "Generating cross-use offsets for " << *Reg << ':'; for (const auto &Entry : Imms) dbgs() << ' ' << Entry.first; dbgs() << '\n'); // Examine each offset. for (ImmMapTy::const_iterator J = Imms.begin(), JE = Imms.end(); J != JE; ++J) { const SCEV *OrigReg = J->second; int64_t JImm = J->first; const SmallBitVector &UsedByIndices = RegUses.getUsedByIndices(OrigReg); if (!isa(OrigReg) && UsedByIndicesMap[Reg].count() == 1) { DEBUG(dbgs() << "Skipping cross-use reuse for " << *OrigReg << '\n'); continue; } // Conservatively examine offsets between this orig reg a few selected // other orig regs. ImmMapTy::const_iterator OtherImms[] = { Imms.begin(), std::prev(Imms.end()), Imms.lower_bound((Imms.begin()->first + std::prev(Imms.end())->first) / 2) }; for (size_t i = 0, e = array_lengthof(OtherImms); i != e; ++i) { ImmMapTy::const_iterator M = OtherImms[i]; if (M == J || M == JE) continue; // Compute the difference between the two. int64_t Imm = (uint64_t)JImm - M->first; for (int LUIdx = UsedByIndices.find_first(); LUIdx != -1; LUIdx = UsedByIndices.find_next(LUIdx)) // Make a memo of this use, offset, and register tuple. if (UniqueItems.insert(std::make_pair(LUIdx, Imm)).second) WorkItems.push_back(WorkItem(LUIdx, Imm, OrigReg)); } } } Map.clear(); Sequence.clear(); UsedByIndicesMap.clear(); UniqueItems.clear(); // Now iterate through the worklist and add new formulae. for (const WorkItem &WI : WorkItems) { size_t LUIdx = WI.LUIdx; LSRUse &LU = Uses[LUIdx]; int64_t Imm = WI.Imm; const SCEV *OrigReg = WI.OrigReg; Type *IntTy = SE.getEffectiveSCEVType(OrigReg->getType()); const SCEV *NegImmS = SE.getSCEV(ConstantInt::get(IntTy, -(uint64_t)Imm)); unsigned BitWidth = SE.getTypeSizeInBits(IntTy); // TODO: Use a more targeted data structure. for (size_t L = 0, LE = LU.Formulae.size(); L != LE; ++L) { Formula F = LU.Formulae[L]; // FIXME: The code for the scaled and unscaled registers looks // very similar but slightly different. Investigate if they // could be merged. That way, we would not have to unscale the // Formula. F.unscale(); // Use the immediate in the scaled register. if (F.ScaledReg == OrigReg) { int64_t Offset = (uint64_t)F.BaseOffset + Imm * (uint64_t)F.Scale; // Don't create 50 + reg(-50). if (F.referencesReg(SE.getSCEV( ConstantInt::get(IntTy, -(uint64_t)Offset)))) continue; Formula NewF = F; NewF.BaseOffset = Offset; if (!isLegalUse(TTI, LU.MinOffset, LU.MaxOffset, LU.Kind, LU.AccessTy, NewF)) continue; NewF.ScaledReg = SE.getAddExpr(NegImmS, NewF.ScaledReg); // If the new scale is a constant in a register, and adding the constant // value to the immediate would produce a value closer to zero than the // immediate itself, then the formula isn't worthwhile. if (const SCEVConstant *C = dyn_cast(NewF.ScaledReg)) if (C->getValue()->isNegative() != (NewF.BaseOffset < 0) && (C->getAPInt().abs() * APInt(BitWidth, F.Scale)) .ule(std::abs(NewF.BaseOffset))) continue; // OK, looks good. NewF.canonicalize(); (void)InsertFormula(LU, LUIdx, NewF); } else { // Use the immediate in a base register. for (size_t N = 0, NE = F.BaseRegs.size(); N != NE; ++N) { const SCEV *BaseReg = F.BaseRegs[N]; if (BaseReg != OrigReg) continue; Formula NewF = F; NewF.BaseOffset = (uint64_t)NewF.BaseOffset + Imm; if (!isLegalUse(TTI, LU.MinOffset, LU.MaxOffset, LU.Kind, LU.AccessTy, NewF)) { if (!TTI.isLegalAddImmediate((uint64_t)NewF.UnfoldedOffset + Imm)) continue; NewF = F; NewF.UnfoldedOffset = (uint64_t)NewF.UnfoldedOffset + Imm; } NewF.BaseRegs[N] = SE.getAddExpr(NegImmS, BaseReg); // If the new formula has a constant in a register, and adding the // constant value to the immediate would produce a value closer to // zero than the immediate itself, then the formula isn't worthwhile. for (const SCEV *NewReg : NewF.BaseRegs) if (const SCEVConstant *C = dyn_cast(NewReg)) if ((C->getAPInt() + NewF.BaseOffset) .abs() .slt(std::abs(NewF.BaseOffset)) && (C->getAPInt() + NewF.BaseOffset).countTrailingZeros() >= countTrailingZeros(NewF.BaseOffset)) goto skip_formula; // Ok, looks good. NewF.canonicalize(); (void)InsertFormula(LU, LUIdx, NewF); break; skip_formula:; } } } } } /// Generate formulae for each use. void LSRInstance::GenerateAllReuseFormulae() { // This is split into multiple loops so that hasRegsUsedByUsesOtherThan // queries are more precise. for (size_t LUIdx = 0, NumUses = Uses.size(); LUIdx != NumUses; ++LUIdx) { LSRUse &LU = Uses[LUIdx]; for (size_t i = 0, f = LU.Formulae.size(); i != f; ++i) GenerateReassociations(LU, LUIdx, LU.Formulae[i]); for (size_t i = 0, f = LU.Formulae.size(); i != f; ++i) GenerateCombinations(LU, LUIdx, LU.Formulae[i]); } for (size_t LUIdx = 0, NumUses = Uses.size(); LUIdx != NumUses; ++LUIdx) { LSRUse &LU = Uses[LUIdx]; for (size_t i = 0, f = LU.Formulae.size(); i != f; ++i) GenerateSymbolicOffsets(LU, LUIdx, LU.Formulae[i]); for (size_t i = 0, f = LU.Formulae.size(); i != f; ++i) GenerateConstantOffsets(LU, LUIdx, LU.Formulae[i]); for (size_t i = 0, f = LU.Formulae.size(); i != f; ++i) GenerateICmpZeroScales(LU, LUIdx, LU.Formulae[i]); for (size_t i = 0, f = LU.Formulae.size(); i != f; ++i) GenerateScales(LU, LUIdx, LU.Formulae[i]); } for (size_t LUIdx = 0, NumUses = Uses.size(); LUIdx != NumUses; ++LUIdx) { LSRUse &LU = Uses[LUIdx]; for (size_t i = 0, f = LU.Formulae.size(); i != f; ++i) GenerateTruncates(LU, LUIdx, LU.Formulae[i]); } GenerateCrossUseConstantOffsets(); DEBUG(dbgs() << "\n" "After generating reuse formulae:\n"; print_uses(dbgs())); } /// If there are multiple formulae with the same set of registers used /// by other uses, pick the best one and delete the others. void LSRInstance::FilterOutUndesirableDedicatedRegisters() { DenseSet VisitedRegs; SmallPtrSet Regs; SmallPtrSet LoserRegs; #ifndef NDEBUG bool ChangedFormulae = false; #endif // Collect the best formula for each unique set of shared registers. This // is reset for each use. typedef DenseMap, size_t, UniquifierDenseMapInfo> BestFormulaeTy; BestFormulaeTy BestFormulae; for (size_t LUIdx = 0, NumUses = Uses.size(); LUIdx != NumUses; ++LUIdx) { LSRUse &LU = Uses[LUIdx]; DEBUG(dbgs() << "Filtering for use "; LU.print(dbgs()); dbgs() << '\n'); bool Any = false; for (size_t FIdx = 0, NumForms = LU.Formulae.size(); FIdx != NumForms; ++FIdx) { Formula &F = LU.Formulae[FIdx]; // Some formulas are instant losers. For example, they may depend on // nonexistent AddRecs from other loops. These need to be filtered // immediately, otherwise heuristics could choose them over others leading // to an unsatisfactory solution. Passing LoserRegs into RateFormula here // avoids the need to recompute this information across formulae using the // same bad AddRec. Passing LoserRegs is also essential unless we remove // the corresponding bad register from the Regs set. Cost CostF; Regs.clear(); CostF.RateFormula(TTI, F, Regs, VisitedRegs, L, LU.Offsets, SE, DT, LU, &LoserRegs); if (CostF.isLoser()) { // During initial formula generation, undesirable formulae are generated // by uses within other loops that have some non-trivial address mode or // use the postinc form of the IV. LSR needs to provide these formulae // as the basis of rediscovering the desired formula that uses an AddRec // corresponding to the existing phi. Once all formulae have been // generated, these initial losers may be pruned. DEBUG(dbgs() << " Filtering loser "; F.print(dbgs()); dbgs() << "\n"); } else { SmallVector Key; for (const SCEV *Reg : F.BaseRegs) { if (RegUses.isRegUsedByUsesOtherThan(Reg, LUIdx)) Key.push_back(Reg); } if (F.ScaledReg && RegUses.isRegUsedByUsesOtherThan(F.ScaledReg, LUIdx)) Key.push_back(F.ScaledReg); // Unstable sort by host order ok, because this is only used for // uniquifying. std::sort(Key.begin(), Key.end()); std::pair P = BestFormulae.insert(std::make_pair(Key, FIdx)); if (P.second) continue; Formula &Best = LU.Formulae[P.first->second]; Cost CostBest; Regs.clear(); CostBest.RateFormula(TTI, Best, Regs, VisitedRegs, L, LU.Offsets, SE, DT, LU); if (CostF < CostBest) std::swap(F, Best); DEBUG(dbgs() << " Filtering out formula "; F.print(dbgs()); dbgs() << "\n" " in favor of formula "; Best.print(dbgs()); dbgs() << '\n'); } #ifndef NDEBUG ChangedFormulae = true; #endif LU.DeleteFormula(F); --FIdx; --NumForms; Any = true; } // Now that we've filtered out some formulae, recompute the Regs set. if (Any) LU.RecomputeRegs(LUIdx, RegUses); // Reset this to prepare for the next use. BestFormulae.clear(); } DEBUG(if (ChangedFormulae) { dbgs() << "\n" "After filtering out undesirable candidates:\n"; print_uses(dbgs()); }); } // This is a rough guess that seems to work fairly well. static const size_t ComplexityLimit = UINT16_MAX; /// Estimate the worst-case number of solutions the solver might have to /// consider. It almost never considers this many solutions because it prune the /// search space, but the pruning isn't always sufficient. size_t LSRInstance::EstimateSearchSpaceComplexity() const { size_t Power = 1; for (const LSRUse &LU : Uses) { size_t FSize = LU.Formulae.size(); if (FSize >= ComplexityLimit) { Power = ComplexityLimit; break; } Power *= FSize; if (Power >= ComplexityLimit) break; } return Power; } /// When one formula uses a superset of the registers of another formula, it /// won't help reduce register pressure (though it may not necessarily hurt /// register pressure); remove it to simplify the system. void LSRInstance::NarrowSearchSpaceByDetectingSupersets() { if (EstimateSearchSpaceComplexity() >= ComplexityLimit) { DEBUG(dbgs() << "The search space is too complex.\n"); DEBUG(dbgs() << "Narrowing the search space by eliminating formulae " "which use a superset of registers used by other " "formulae.\n"); for (size_t LUIdx = 0, NumUses = Uses.size(); LUIdx != NumUses; ++LUIdx) { LSRUse &LU = Uses[LUIdx]; bool Any = false; for (size_t i = 0, e = LU.Formulae.size(); i != e; ++i) { Formula &F = LU.Formulae[i]; // Look for a formula with a constant or GV in a register. If the use // also has a formula with that same value in an immediate field, // delete the one that uses a register. for (SmallVectorImpl::const_iterator I = F.BaseRegs.begin(), E = F.BaseRegs.end(); I != E; ++I) { if (const SCEVConstant *C = dyn_cast(*I)) { Formula NewF = F; NewF.BaseOffset += C->getValue()->getSExtValue(); NewF.BaseRegs.erase(NewF.BaseRegs.begin() + (I - F.BaseRegs.begin())); if (LU.HasFormulaWithSameRegs(NewF)) { DEBUG(dbgs() << " Deleting "; F.print(dbgs()); dbgs() << '\n'); LU.DeleteFormula(F); --i; --e; Any = true; break; } } else if (const SCEVUnknown *U = dyn_cast(*I)) { if (GlobalValue *GV = dyn_cast(U->getValue())) if (!F.BaseGV) { Formula NewF = F; NewF.BaseGV = GV; NewF.BaseRegs.erase(NewF.BaseRegs.begin() + (I - F.BaseRegs.begin())); if (LU.HasFormulaWithSameRegs(NewF)) { DEBUG(dbgs() << " Deleting "; F.print(dbgs()); dbgs() << '\n'); LU.DeleteFormula(F); --i; --e; Any = true; break; } } } } } if (Any) LU.RecomputeRegs(LUIdx, RegUses); } DEBUG(dbgs() << "After pre-selection:\n"; print_uses(dbgs())); } } /// When there are many registers for expressions like A, A+1, A+2, etc., /// allocate a single register for them. void LSRInstance::NarrowSearchSpaceByCollapsingUnrolledCode() { if (EstimateSearchSpaceComplexity() < ComplexityLimit) return; DEBUG(dbgs() << "The search space is too complex.\n" "Narrowing the search space by assuming that uses separated " "by a constant offset will use the same registers.\n"); // This is especially useful for unrolled loops. for (size_t LUIdx = 0, NumUses = Uses.size(); LUIdx != NumUses; ++LUIdx) { LSRUse &LU = Uses[LUIdx]; for (const Formula &F : LU.Formulae) { if (F.BaseOffset == 0 || (F.Scale != 0 && F.Scale != 1)) continue; LSRUse *LUThatHas = FindUseWithSimilarFormula(F, LU); if (!LUThatHas) continue; if (!reconcileNewOffset(*LUThatHas, F.BaseOffset, /*HasBaseReg=*/ false, LU.Kind, LU.AccessTy)) continue; DEBUG(dbgs() << " Deleting use "; LU.print(dbgs()); dbgs() << '\n'); LUThatHas->AllFixupsOutsideLoop &= LU.AllFixupsOutsideLoop; // Update the relocs to reference the new use. for (LSRFixup &Fixup : Fixups) { if (Fixup.LUIdx == LUIdx) { Fixup.LUIdx = LUThatHas - &Uses.front(); Fixup.Offset += F.BaseOffset; // Add the new offset to LUThatHas' offset list. if (LUThatHas->Offsets.back() != Fixup.Offset) { LUThatHas->Offsets.push_back(Fixup.Offset); if (Fixup.Offset > LUThatHas->MaxOffset) LUThatHas->MaxOffset = Fixup.Offset; if (Fixup.Offset < LUThatHas->MinOffset) LUThatHas->MinOffset = Fixup.Offset; } DEBUG(dbgs() << "New fixup has offset " << Fixup.Offset << '\n'); } if (Fixup.LUIdx == NumUses-1) Fixup.LUIdx = LUIdx; } // Delete formulae from the new use which are no longer legal. bool Any = false; for (size_t i = 0, e = LUThatHas->Formulae.size(); i != e; ++i) { Formula &F = LUThatHas->Formulae[i]; if (!isLegalUse(TTI, LUThatHas->MinOffset, LUThatHas->MaxOffset, LUThatHas->Kind, LUThatHas->AccessTy, F)) { DEBUG(dbgs() << " Deleting "; F.print(dbgs()); dbgs() << '\n'); LUThatHas->DeleteFormula(F); --i; --e; Any = true; } } if (Any) LUThatHas->RecomputeRegs(LUThatHas - &Uses.front(), RegUses); // Delete the old use. DeleteUse(LU, LUIdx); --LUIdx; --NumUses; break; } } DEBUG(dbgs() << "After pre-selection:\n"; print_uses(dbgs())); } /// Call FilterOutUndesirableDedicatedRegisters again, if necessary, now that /// we've done more filtering, as it may be able to find more formulae to /// eliminate. void LSRInstance::NarrowSearchSpaceByRefilteringUndesirableDedicatedRegisters(){ if (EstimateSearchSpaceComplexity() >= ComplexityLimit) { DEBUG(dbgs() << "The search space is too complex.\n"); DEBUG(dbgs() << "Narrowing the search space by re-filtering out " "undesirable dedicated registers.\n"); FilterOutUndesirableDedicatedRegisters(); DEBUG(dbgs() << "After pre-selection:\n"; print_uses(dbgs())); } } /// Pick a register which seems likely to be profitable, and then in any use /// which has any reference to that register, delete all formulae which do not /// reference that register. void LSRInstance::NarrowSearchSpaceByPickingWinnerRegs() { // With all other options exhausted, loop until the system is simple // enough to handle. SmallPtrSet Taken; while (EstimateSearchSpaceComplexity() >= ComplexityLimit) { // Ok, we have too many of formulae on our hands to conveniently handle. // Use a rough heuristic to thin out the list. DEBUG(dbgs() << "The search space is too complex.\n"); // Pick the register which is used by the most LSRUses, which is likely // to be a good reuse register candidate. const SCEV *Best = nullptr; unsigned BestNum = 0; for (const SCEV *Reg : RegUses) { if (Taken.count(Reg)) continue; if (!Best) Best = Reg; else { unsigned Count = RegUses.getUsedByIndices(Reg).count(); if (Count > BestNum) { Best = Reg; BestNum = Count; } } } DEBUG(dbgs() << "Narrowing the search space by assuming " << *Best << " will yield profitable reuse.\n"); Taken.insert(Best); // In any use with formulae which references this register, delete formulae // which don't reference it. for (size_t LUIdx = 0, NumUses = Uses.size(); LUIdx != NumUses; ++LUIdx) { LSRUse &LU = Uses[LUIdx]; if (!LU.Regs.count(Best)) continue; bool Any = false; for (size_t i = 0, e = LU.Formulae.size(); i != e; ++i) { Formula &F = LU.Formulae[i]; if (!F.referencesReg(Best)) { DEBUG(dbgs() << " Deleting "; F.print(dbgs()); dbgs() << '\n'); LU.DeleteFormula(F); --e; --i; Any = true; assert(e != 0 && "Use has no formulae left! Is Regs inconsistent?"); continue; } } if (Any) LU.RecomputeRegs(LUIdx, RegUses); } DEBUG(dbgs() << "After pre-selection:\n"; print_uses(dbgs())); } } /// If there are an extraordinary number of formulae to choose from, use some /// rough heuristics to prune down the number of formulae. This keeps the main /// solver from taking an extraordinary amount of time in some worst-case /// scenarios. void LSRInstance::NarrowSearchSpaceUsingHeuristics() { NarrowSearchSpaceByDetectingSupersets(); NarrowSearchSpaceByCollapsingUnrolledCode(); NarrowSearchSpaceByRefilteringUndesirableDedicatedRegisters(); NarrowSearchSpaceByPickingWinnerRegs(); } /// This is the recursive solver. void LSRInstance::SolveRecurse(SmallVectorImpl &Solution, Cost &SolutionCost, SmallVectorImpl &Workspace, const Cost &CurCost, const SmallPtrSet &CurRegs, DenseSet &VisitedRegs) const { // Some ideas: // - prune more: // - use more aggressive filtering // - sort the formula so that the most profitable solutions are found first // - sort the uses too // - search faster: // - don't compute a cost, and then compare. compare while computing a cost // and bail early. // - track register sets with SmallBitVector const LSRUse &LU = Uses[Workspace.size()]; // If this use references any register that's already a part of the // in-progress solution, consider it a requirement that a formula must // reference that register in order to be considered. This prunes out // unprofitable searching. SmallSetVector ReqRegs; for (const SCEV *S : CurRegs) if (LU.Regs.count(S)) ReqRegs.insert(S); SmallPtrSet NewRegs; Cost NewCost; for (const Formula &F : LU.Formulae) { // Ignore formulae which may not be ideal in terms of register reuse of // ReqRegs. The formula should use all required registers before // introducing new ones. int NumReqRegsToFind = std::min(F.getNumRegs(), ReqRegs.size()); for (const SCEV *Reg : ReqRegs) { if ((F.ScaledReg && F.ScaledReg == Reg) || std::find(F.BaseRegs.begin(), F.BaseRegs.end(), Reg) != F.BaseRegs.end()) { --NumReqRegsToFind; if (NumReqRegsToFind == 0) break; } } if (NumReqRegsToFind != 0) { // If none of the formulae satisfied the required registers, then we could // clear ReqRegs and try again. Currently, we simply give up in this case. continue; } // Evaluate the cost of the current formula. If it's already worse than // the current best, prune the search at that point. NewCost = CurCost; NewRegs = CurRegs; NewCost.RateFormula(TTI, F, NewRegs, VisitedRegs, L, LU.Offsets, SE, DT, LU); if (NewCost < SolutionCost) { Workspace.push_back(&F); if (Workspace.size() != Uses.size()) { SolveRecurse(Solution, SolutionCost, Workspace, NewCost, NewRegs, VisitedRegs); if (F.getNumRegs() == 1 && Workspace.size() == 1) VisitedRegs.insert(F.ScaledReg ? F.ScaledReg : F.BaseRegs[0]); } else { DEBUG(dbgs() << "New best at "; NewCost.print(dbgs()); dbgs() << ".\n Regs:"; for (const SCEV *S : NewRegs) dbgs() << ' ' << *S; dbgs() << '\n'); SolutionCost = NewCost; Solution = Workspace; } Workspace.pop_back(); } } } /// Choose one formula from each use. Return the results in the given Solution /// vector. void LSRInstance::Solve(SmallVectorImpl &Solution) const { SmallVector Workspace; Cost SolutionCost; SolutionCost.Lose(); Cost CurCost; SmallPtrSet CurRegs; DenseSet VisitedRegs; Workspace.reserve(Uses.size()); // SolveRecurse does all the work. SolveRecurse(Solution, SolutionCost, Workspace, CurCost, CurRegs, VisitedRegs); if (Solution.empty()) { DEBUG(dbgs() << "\nNo Satisfactory Solution\n"); return; } // Ok, we've now made all our decisions. DEBUG(dbgs() << "\n" "The chosen solution requires "; SolutionCost.print(dbgs()); dbgs() << ":\n"; for (size_t i = 0, e = Uses.size(); i != e; ++i) { dbgs() << " "; Uses[i].print(dbgs()); dbgs() << "\n" " "; Solution[i]->print(dbgs()); dbgs() << '\n'; }); assert(Solution.size() == Uses.size() && "Malformed solution!"); } /// Helper for AdjustInsertPositionForExpand. Climb up the dominator tree far as /// we can go while still being dominated by the input positions. This helps /// canonicalize the insert position, which encourages sharing. BasicBlock::iterator LSRInstance::HoistInsertPosition(BasicBlock::iterator IP, const SmallVectorImpl &Inputs) const { for (;;) { const Loop *IPLoop = LI.getLoopFor(IP->getParent()); unsigned IPLoopDepth = IPLoop ? IPLoop->getLoopDepth() : 0; BasicBlock *IDom; for (DomTreeNode *Rung = DT.getNode(IP->getParent()); ; ) { if (!Rung) return IP; Rung = Rung->getIDom(); if (!Rung) return IP; IDom = Rung->getBlock(); // Don't climb into a loop though. const Loop *IDomLoop = LI.getLoopFor(IDom); unsigned IDomDepth = IDomLoop ? IDomLoop->getLoopDepth() : 0; if (IDomDepth <= IPLoopDepth && (IDomDepth != IPLoopDepth || IDomLoop == IPLoop)) break; } bool AllDominate = true; Instruction *BetterPos = nullptr; Instruction *Tentative = IDom->getTerminator(); for (Instruction *Inst : Inputs) { if (Inst == Tentative || !DT.dominates(Inst, Tentative)) { AllDominate = false; break; } // Attempt to find an insert position in the middle of the block, // instead of at the end, so that it can be used for other expansions. if (IDom == Inst->getParent() && (!BetterPos || !DT.dominates(Inst, BetterPos))) BetterPos = &*std::next(BasicBlock::iterator(Inst)); } if (!AllDominate) break; if (BetterPos) IP = BetterPos->getIterator(); else IP = Tentative->getIterator(); } return IP; } /// Determine an input position which will be dominated by the operands and /// which will dominate the result. BasicBlock::iterator LSRInstance::AdjustInsertPositionForExpand(BasicBlock::iterator LowestIP, const LSRFixup &LF, const LSRUse &LU, SCEVExpander &Rewriter) const { // Collect some instructions which must be dominated by the // expanding replacement. These must be dominated by any operands that // will be required in the expansion. SmallVector Inputs; if (Instruction *I = dyn_cast(LF.OperandValToReplace)) Inputs.push_back(I); if (LU.Kind == LSRUse::ICmpZero) if (Instruction *I = dyn_cast(cast(LF.UserInst)->getOperand(1))) Inputs.push_back(I); if (LF.PostIncLoops.count(L)) { if (LF.isUseFullyOutsideLoop(L)) Inputs.push_back(L->getLoopLatch()->getTerminator()); else Inputs.push_back(IVIncInsertPos); } // The expansion must also be dominated by the increment positions of any // loops it for which it is using post-inc mode. for (const Loop *PIL : LF.PostIncLoops) { if (PIL == L) continue; // Be dominated by the loop exit. SmallVector ExitingBlocks; PIL->getExitingBlocks(ExitingBlocks); if (!ExitingBlocks.empty()) { BasicBlock *BB = ExitingBlocks[0]; for (unsigned i = 1, e = ExitingBlocks.size(); i != e; ++i) BB = DT.findNearestCommonDominator(BB, ExitingBlocks[i]); Inputs.push_back(BB->getTerminator()); } } assert(!isa(LowestIP) && !LowestIP->isEHPad() && !isa(LowestIP) && "Insertion point must be a normal instruction"); // Then, climb up the immediate dominator tree as far as we can go while // still being dominated by the input positions. BasicBlock::iterator IP = HoistInsertPosition(LowestIP, Inputs); // Don't insert instructions before PHI nodes. while (isa(IP)) ++IP; // Ignore landingpad instructions. while (!isa(IP) && IP->isEHPad()) ++IP; // Ignore debug intrinsics. while (isa(IP)) ++IP; // Set IP below instructions recently inserted by SCEVExpander. This keeps the // IP consistent across expansions and allows the previously inserted // instructions to be reused by subsequent expansion. while (Rewriter.isInsertedInstruction(&*IP) && IP != LowestIP) ++IP; return IP; } /// Emit instructions for the leading candidate expression for this LSRUse (this /// is called "expanding"). Value *LSRInstance::Expand(const LSRFixup &LF, const Formula &F, BasicBlock::iterator IP, SCEVExpander &Rewriter, SmallVectorImpl &DeadInsts) const { const LSRUse &LU = Uses[LF.LUIdx]; if (LU.RigidFormula) return LF.OperandValToReplace; // Determine an input position which will be dominated by the operands and // which will dominate the result. IP = AdjustInsertPositionForExpand(IP, LF, LU, Rewriter); // Inform the Rewriter if we have a post-increment use, so that it can // perform an advantageous expansion. Rewriter.setPostInc(LF.PostIncLoops); // This is the type that the user actually needs. Type *OpTy = LF.OperandValToReplace->getType(); // This will be the type that we'll initially expand to. Type *Ty = F.getType(); if (!Ty) // No type known; just expand directly to the ultimate type. Ty = OpTy; else if (SE.getEffectiveSCEVType(Ty) == SE.getEffectiveSCEVType(OpTy)) // Expand directly to the ultimate type if it's the right size. Ty = OpTy; // This is the type to do integer arithmetic in. Type *IntTy = SE.getEffectiveSCEVType(Ty); // Build up a list of operands to add together to form the full base. SmallVector Ops; // Expand the BaseRegs portion. for (const SCEV *Reg : F.BaseRegs) { assert(!Reg->isZero() && "Zero allocated in a base register!"); // If we're expanding for a post-inc user, make the post-inc adjustment. PostIncLoopSet &Loops = const_cast(LF.PostIncLoops); Reg = TransformForPostIncUse(Denormalize, Reg, LF.UserInst, LF.OperandValToReplace, Loops, SE, DT); Ops.push_back(SE.getUnknown(Rewriter.expandCodeFor(Reg, nullptr, &*IP))); } // Expand the ScaledReg portion. Value *ICmpScaledV = nullptr; if (F.Scale != 0) { const SCEV *ScaledS = F.ScaledReg; // If we're expanding for a post-inc user, make the post-inc adjustment. PostIncLoopSet &Loops = const_cast(LF.PostIncLoops); ScaledS = TransformForPostIncUse(Denormalize, ScaledS, LF.UserInst, LF.OperandValToReplace, Loops, SE, DT); if (LU.Kind == LSRUse::ICmpZero) { // Expand ScaleReg as if it was part of the base regs. if (F.Scale == 1) Ops.push_back( SE.getUnknown(Rewriter.expandCodeFor(ScaledS, nullptr, &*IP))); else { // An interesting way of "folding" with an icmp is to use a negated // scale, which we'll implement by inserting it into the other operand // of the icmp. assert(F.Scale == -1 && "The only scale supported by ICmpZero uses is -1!"); ICmpScaledV = Rewriter.expandCodeFor(ScaledS, nullptr, &*IP); } } else { // Otherwise just expand the scaled register and an explicit scale, // which is expected to be matched as part of the address. // Flush the operand list to suppress SCEVExpander hoisting address modes. // Unless the addressing mode will not be folded. if (!Ops.empty() && LU.Kind == LSRUse::Address && isAMCompletelyFolded(TTI, LU, F)) { Value *FullV = Rewriter.expandCodeFor(SE.getAddExpr(Ops), Ty, &*IP); Ops.clear(); Ops.push_back(SE.getUnknown(FullV)); } ScaledS = SE.getUnknown(Rewriter.expandCodeFor(ScaledS, nullptr, &*IP)); if (F.Scale != 1) ScaledS = SE.getMulExpr(ScaledS, SE.getConstant(ScaledS->getType(), F.Scale)); Ops.push_back(ScaledS); } } // Expand the GV portion. if (F.BaseGV) { // Flush the operand list to suppress SCEVExpander hoisting. if (!Ops.empty()) { Value *FullV = Rewriter.expandCodeFor(SE.getAddExpr(Ops), Ty, &*IP); Ops.clear(); Ops.push_back(SE.getUnknown(FullV)); } Ops.push_back(SE.getUnknown(F.BaseGV)); } // Flush the operand list to suppress SCEVExpander hoisting of both folded and // unfolded offsets. LSR assumes they both live next to their uses. if (!Ops.empty()) { Value *FullV = Rewriter.expandCodeFor(SE.getAddExpr(Ops), Ty, &*IP); Ops.clear(); Ops.push_back(SE.getUnknown(FullV)); } // Expand the immediate portion. int64_t Offset = (uint64_t)F.BaseOffset + LF.Offset; if (Offset != 0) { if (LU.Kind == LSRUse::ICmpZero) { // The other interesting way of "folding" with an ICmpZero is to use a // negated immediate. if (!ICmpScaledV) ICmpScaledV = ConstantInt::get(IntTy, -(uint64_t)Offset); else { Ops.push_back(SE.getUnknown(ICmpScaledV)); ICmpScaledV = ConstantInt::get(IntTy, Offset); } } else { // Just add the immediate values. These again are expected to be matched // as part of the address. Ops.push_back(SE.getUnknown(ConstantInt::getSigned(IntTy, Offset))); } } // Expand the unfolded offset portion. int64_t UnfoldedOffset = F.UnfoldedOffset; if (UnfoldedOffset != 0) { // Just add the immediate values. Ops.push_back(SE.getUnknown(ConstantInt::getSigned(IntTy, UnfoldedOffset))); } // Emit instructions summing all the operands. const SCEV *FullS = Ops.empty() ? SE.getConstant(IntTy, 0) : SE.getAddExpr(Ops); Value *FullV = Rewriter.expandCodeFor(FullS, Ty, &*IP); // We're done expanding now, so reset the rewriter. Rewriter.clearPostInc(); // An ICmpZero Formula represents an ICmp which we're handling as a // comparison against zero. Now that we've expanded an expression for that // form, update the ICmp's other operand. if (LU.Kind == LSRUse::ICmpZero) { ICmpInst *CI = cast(LF.UserInst); DeadInsts.emplace_back(CI->getOperand(1)); assert(!F.BaseGV && "ICmp does not support folding a global value and " "a scale at the same time!"); if (F.Scale == -1) { if (ICmpScaledV->getType() != OpTy) { Instruction *Cast = CastInst::Create(CastInst::getCastOpcode(ICmpScaledV, false, OpTy, false), ICmpScaledV, OpTy, "tmp", CI); ICmpScaledV = Cast; } CI->setOperand(1, ICmpScaledV); } else { // A scale of 1 means that the scale has been expanded as part of the // base regs. assert((F.Scale == 0 || F.Scale == 1) && "ICmp does not support folding a global value and " "a scale at the same time!"); Constant *C = ConstantInt::getSigned(SE.getEffectiveSCEVType(OpTy), -(uint64_t)Offset); if (C->getType() != OpTy) C = ConstantExpr::getCast(CastInst::getCastOpcode(C, false, OpTy, false), C, OpTy); CI->setOperand(1, C); } } return FullV; } /// Helper for Rewrite. PHI nodes are special because the use of their operands /// effectively happens in their predecessor blocks, so the expression may need /// to be expanded in multiple places. void LSRInstance::RewriteForPHI(PHINode *PN, const LSRFixup &LF, const Formula &F, SCEVExpander &Rewriter, SmallVectorImpl &DeadInsts) const { DenseMap Inserted; for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) if (PN->getIncomingValue(i) == LF.OperandValToReplace) { BasicBlock *BB = PN->getIncomingBlock(i); // If this is a critical edge, split the edge so that we do not insert // the code on all predecessor/successor paths. We do this unless this // is the canonical backedge for this loop, which complicates post-inc // users. if (e != 1 && BB->getTerminator()->getNumSuccessors() > 1 && !isa(BB->getTerminator())) { BasicBlock *Parent = PN->getParent(); Loop *PNLoop = LI.getLoopFor(Parent); if (!PNLoop || Parent != PNLoop->getHeader()) { // Split the critical edge. BasicBlock *NewBB = nullptr; if (!Parent->isLandingPad()) { NewBB = SplitCriticalEdge(BB, Parent, CriticalEdgeSplittingOptions(&DT, &LI) .setMergeIdenticalEdges() .setDontDeleteUselessPHIs()); } else { SmallVector NewBBs; SplitLandingPadPredecessors(Parent, BB, "", "", NewBBs, &DT, &LI); NewBB = NewBBs[0]; } // If NewBB==NULL, then SplitCriticalEdge refused to split because all // phi predecessors are identical. The simple thing to do is skip // splitting in this case rather than complicate the API. if (NewBB) { // If PN is outside of the loop and BB is in the loop, we want to // move the block to be immediately before the PHI block, not // immediately after BB. if (L->contains(BB) && !L->contains(PN)) NewBB->moveBefore(PN->getParent()); // Splitting the edge can reduce the number of PHI entries we have. e = PN->getNumIncomingValues(); BB = NewBB; i = PN->getBasicBlockIndex(BB); } } } std::pair::iterator, bool> Pair = Inserted.insert(std::make_pair(BB, static_cast(nullptr))); if (!Pair.second) PN->setIncomingValue(i, Pair.first->second); else { Value *FullV = Expand(LF, F, BB->getTerminator()->getIterator(), Rewriter, DeadInsts); // If this is reuse-by-noop-cast, insert the noop cast. Type *OpTy = LF.OperandValToReplace->getType(); if (FullV->getType() != OpTy) FullV = CastInst::Create(CastInst::getCastOpcode(FullV, false, OpTy, false), FullV, LF.OperandValToReplace->getType(), "tmp", BB->getTerminator()); PN->setIncomingValue(i, FullV); Pair.first->second = FullV; } } } /// Emit instructions for the leading candidate expression for this LSRUse (this /// is called "expanding"), and update the UserInst to reference the newly /// expanded value. void LSRInstance::Rewrite(const LSRFixup &LF, const Formula &F, SCEVExpander &Rewriter, SmallVectorImpl &DeadInsts) const { // First, find an insertion point that dominates UserInst. For PHI nodes, // find the nearest block which dominates all the relevant uses. if (PHINode *PN = dyn_cast(LF.UserInst)) { RewriteForPHI(PN, LF, F, Rewriter, DeadInsts); } else { Value *FullV = Expand(LF, F, LF.UserInst->getIterator(), Rewriter, DeadInsts); // If this is reuse-by-noop-cast, insert the noop cast. Type *OpTy = LF.OperandValToReplace->getType(); if (FullV->getType() != OpTy) { Instruction *Cast = CastInst::Create(CastInst::getCastOpcode(FullV, false, OpTy, false), FullV, OpTy, "tmp", LF.UserInst); FullV = Cast; } // Update the user. ICmpZero is handled specially here (for now) because // Expand may have updated one of the operands of the icmp already, and // its new value may happen to be equal to LF.OperandValToReplace, in // which case doing replaceUsesOfWith leads to replacing both operands // with the same value. TODO: Reorganize this. if (Uses[LF.LUIdx].Kind == LSRUse::ICmpZero) LF.UserInst->setOperand(0, FullV); else LF.UserInst->replaceUsesOfWith(LF.OperandValToReplace, FullV); } DeadInsts.emplace_back(LF.OperandValToReplace); } /// Rewrite all the fixup locations with new values, following the chosen /// solution. void LSRInstance::ImplementSolution( const SmallVectorImpl &Solution) { // Keep track of instructions we may have made dead, so that // we can remove them after we are done working. SmallVector DeadInsts; SCEVExpander Rewriter(SE, L->getHeader()->getModule()->getDataLayout(), "lsr"); #ifndef NDEBUG Rewriter.setDebugType(DEBUG_TYPE); #endif Rewriter.disableCanonicalMode(); Rewriter.enableLSRMode(); Rewriter.setIVIncInsertPos(L, IVIncInsertPos); // Mark phi nodes that terminate chains so the expander tries to reuse them. for (const IVChain &Chain : IVChainVec) { if (PHINode *PN = dyn_cast(Chain.tailUserInst())) Rewriter.setChainedPhi(PN); } // Expand the new value definitions and update the users. for (const LSRFixup &Fixup : Fixups) { Rewrite(Fixup, *Solution[Fixup.LUIdx], Rewriter, DeadInsts); Changed = true; } for (const IVChain &Chain : IVChainVec) { GenerateIVChain(Chain, Rewriter, DeadInsts); Changed = true; } // Clean up after ourselves. This must be done before deleting any // instructions. Rewriter.clear(); Changed |= DeleteTriviallyDeadInstructions(DeadInsts); } LSRInstance::LSRInstance(Loop *L, IVUsers &IU, ScalarEvolution &SE, DominatorTree &DT, LoopInfo &LI, const TargetTransformInfo &TTI) : IU(IU), SE(SE), DT(DT), LI(LI), TTI(TTI), L(L), Changed(false), IVIncInsertPos(nullptr) { // If LoopSimplify form is not available, stay out of trouble. if (!L->isLoopSimplifyForm()) return; // If there's no interesting work to be done, bail early. if (IU.empty()) return; // If there's too much analysis to be done, bail early. We won't be able to // model the problem anyway. unsigned NumUsers = 0; for (const IVStrideUse &U : IU) { if (++NumUsers > MaxIVUsers) { (void)U; DEBUG(dbgs() << "LSR skipping loop, too many IV Users in " << U << "\n"); return; } + // Bail out if we have a PHI on an EHPad that gets a value from a + // CatchSwitchInst. Because the CatchSwitchInst cannot be split, there is + // no good place to stick any instructions. + if (auto *PN = dyn_cast(U.getUser())) { + auto *FirstNonPHI = PN->getParent()->getFirstNonPHI(); + if (isa(FirstNonPHI) || + isa(FirstNonPHI)) + for (BasicBlock *PredBB : PN->blocks()) + if (isa(PredBB->getFirstNonPHI())) + return; + } } #ifndef NDEBUG // All dominating loops must have preheaders, or SCEVExpander may not be able // to materialize an AddRecExpr whose Start is an outer AddRecExpr. // // IVUsers analysis should only create users that are dominated by simple loop // headers. Since this loop should dominate all of its users, its user list // should be empty if this loop itself is not within a simple loop nest. for (DomTreeNode *Rung = DT.getNode(L->getLoopPreheader()); Rung; Rung = Rung->getIDom()) { BasicBlock *BB = Rung->getBlock(); const Loop *DomLoop = LI.getLoopFor(BB); if (DomLoop && DomLoop->getHeader() == BB) { assert(DomLoop->getLoopPreheader() && "LSR needs a simplified loop nest"); } } #endif // DEBUG DEBUG(dbgs() << "\nLSR on loop "; L->getHeader()->printAsOperand(dbgs(), /*PrintType=*/false); dbgs() << ":\n"); // First, perform some low-level loop optimizations. OptimizeShadowIV(); OptimizeLoopTermCond(); // If loop preparation eliminates all interesting IV users, bail. if (IU.empty()) return; // Skip nested loops until we can model them better with formulae. if (!L->empty()) { DEBUG(dbgs() << "LSR skipping outer loop " << *L << "\n"); return; } // Start collecting data and preparing for the solver. CollectChains(); CollectInterestingTypesAndFactors(); CollectFixupsAndInitialFormulae(); CollectLoopInvariantFixupsAndFormulae(); assert(!Uses.empty() && "IVUsers reported at least one use"); DEBUG(dbgs() << "LSR found " << Uses.size() << " uses:\n"; print_uses(dbgs())); // Now use the reuse data to generate a bunch of interesting ways // to formulate the values needed for the uses. GenerateAllReuseFormulae(); FilterOutUndesirableDedicatedRegisters(); NarrowSearchSpaceUsingHeuristics(); SmallVector Solution; Solve(Solution); // Release memory that is no longer needed. Factors.clear(); Types.clear(); RegUses.clear(); if (Solution.empty()) return; #ifndef NDEBUG // Formulae should be legal. for (const LSRUse &LU : Uses) { for (const Formula &F : LU.Formulae) assert(isLegalUse(TTI, LU.MinOffset, LU.MaxOffset, LU.Kind, LU.AccessTy, F) && "Illegal formula generated!"); }; #endif // Now that we've decided what we want, make it so. ImplementSolution(Solution); } void LSRInstance::print_factors_and_types(raw_ostream &OS) const { if (Factors.empty() && Types.empty()) return; OS << "LSR has identified the following interesting factors and types: "; bool First = true; for (int64_t Factor : Factors) { if (!First) OS << ", "; First = false; OS << '*' << Factor; } for (Type *Ty : Types) { if (!First) OS << ", "; First = false; OS << '(' << *Ty << ')'; } OS << '\n'; } void LSRInstance::print_fixups(raw_ostream &OS) const { OS << "LSR is examining the following fixup sites:\n"; for (const LSRFixup &LF : Fixups) { dbgs() << " "; LF.print(OS); OS << '\n'; } } void LSRInstance::print_uses(raw_ostream &OS) const { OS << "LSR is examining the following uses:\n"; for (const LSRUse &LU : Uses) { dbgs() << " "; LU.print(OS); OS << '\n'; for (const Formula &F : LU.Formulae) { OS << " "; F.print(OS); OS << '\n'; } } } void LSRInstance::print(raw_ostream &OS) const { print_factors_and_types(OS); print_fixups(OS); print_uses(OS); } LLVM_DUMP_METHOD void LSRInstance::dump() const { print(errs()); errs() << '\n'; } namespace { class LoopStrengthReduce : public LoopPass { public: static char ID; // Pass ID, replacement for typeid LoopStrengthReduce(); private: bool runOnLoop(Loop *L, LPPassManager &LPM) override; void getAnalysisUsage(AnalysisUsage &AU) const override; }; } char LoopStrengthReduce::ID = 0; INITIALIZE_PASS_BEGIN(LoopStrengthReduce, "loop-reduce", "Loop Strength Reduction", false, false) INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass) INITIALIZE_PASS_DEPENDENCY(IVUsers) INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(LoopSimplify) INITIALIZE_PASS_END(LoopStrengthReduce, "loop-reduce", "Loop Strength Reduction", false, false) Pass *llvm::createLoopStrengthReducePass() { return new LoopStrengthReduce(); } LoopStrengthReduce::LoopStrengthReduce() : LoopPass(ID) { initializeLoopStrengthReducePass(*PassRegistry::getPassRegistry()); } void LoopStrengthReduce::getAnalysisUsage(AnalysisUsage &AU) const { // We split critical edges, so we change the CFG. However, we do update // many analyses if they are around. AU.addPreservedID(LoopSimplifyID); AU.addRequired(); AU.addPreserved(); AU.addRequiredID(LoopSimplifyID); AU.addRequired(); AU.addPreserved(); AU.addRequired(); AU.addPreserved(); // Requiring LoopSimplify a second time here prevents IVUsers from running // twice, since LoopSimplify was invalidated by running ScalarEvolution. AU.addRequiredID(LoopSimplifyID); AU.addRequired(); AU.addPreserved(); AU.addRequired(); } bool LoopStrengthReduce::runOnLoop(Loop *L, LPPassManager & /*LPM*/) { if (skipOptnoneFunction(L)) return false; auto &IU = getAnalysis(); auto &SE = getAnalysis().getSE(); auto &DT = getAnalysis().getDomTree(); auto &LI = getAnalysis().getLoopInfo(); const auto &TTI = getAnalysis().getTTI( *L->getHeader()->getParent()); bool Changed = false; // Run the main LSR transformation. Changed |= LSRInstance(L, IU, SE, DT, LI, TTI).getChanged(); // Remove any extra phis created by processing inner loops. Changed |= DeleteDeadPHIs(L->getHeader()); if (EnablePhiElim && L->isLoopSimplifyForm()) { SmallVector DeadInsts; const DataLayout &DL = L->getHeader()->getModule()->getDataLayout(); SCEVExpander Rewriter(getAnalysis().getSE(), DL, "lsr"); #ifndef NDEBUG Rewriter.setDebugType(DEBUG_TYPE); #endif unsigned numFolded = Rewriter.replaceCongruentIVs( L, &getAnalysis().getDomTree(), DeadInsts, &getAnalysis().getTTI( *L->getHeader()->getParent())); if (numFolded) { Changed = true; DeleteTriviallyDeadInstructions(DeadInsts); DeleteDeadPHIs(L->getHeader()); } } return Changed; } Index: projects/clang380-import/contrib/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp =================================================================== --- projects/clang380-import/contrib/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp (revision 295858) +++ projects/clang380-import/contrib/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp (revision 295859) @@ -1,5823 +1,5758 @@ //===- LoopVectorize.cpp - A Loop Vectorizer ------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This is the LLVM loop vectorizer. This pass modifies 'vectorizable' loops // and generates target-independent LLVM-IR. // The vectorizer uses the TargetTransformInfo analysis to estimate the costs // of instructions in order to estimate the profitability of vectorization. // // The loop vectorizer combines consecutive loop iterations into a single // 'wide' iteration. After this transformation the index is incremented // by the SIMD vector width, and not by one. // // This pass has three parts: // 1. The main loop pass that drives the different parts. // 2. LoopVectorizationLegality - A unit that checks for the legality // of the vectorization. // 3. InnerLoopVectorizer - A unit that performs the actual // widening of instructions. // 4. LoopVectorizationCostModel - A unit that checks for the profitability // of vectorization. It decides on the optimal vector width, which // can be one, if vectorization is not profitable. // //===----------------------------------------------------------------------===// // // The reduction-variable vectorization is based on the paper: // D. Nuzman and R. Henderson. Multi-platform Auto-vectorization. // // Variable uniformity checks are inspired by: // Karrenberg, R. and Hack, S. Whole Function Vectorization. // // The interleaved access vectorization is based on the paper: // Dorit Nuzman, Ira Rosen and Ayal Zaks. Auto-Vectorization of Interleaved // Data for SIMD // // Other ideas/concepts are from: // A. Zaks and D. Nuzman. Autovectorization in GCC-two years later. // // S. Maleki, Y. Gao, M. Garzaran, T. Wong and D. Padua. An Evaluation of // Vectorizing Compilers. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/Vectorize.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/BasicAliasAnalysis.h" #include "llvm/Analysis/AliasSetTracker.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/BlockFrequencyInfo.h" #include "llvm/Analysis/CodeMetrics.h" #include "llvm/Analysis/DemandedBits.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/LoopAccessAnalysis.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/LoopIterator.h" #include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/ScalarEvolutionExpander.h" #include "llvm/Analysis/ScalarEvolutionExpressions.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/PatternMatch.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" #include "llvm/IR/ValueHandle.h" #include "llvm/IR/Verifier.h" #include "llvm/Pass.h" #include "llvm/Support/BranchProbability.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Analysis/VectorUtils.h" #include "llvm/Transforms/Utils/LoopUtils.h" #include #include #include #include using namespace llvm; using namespace llvm::PatternMatch; #define LV_NAME "loop-vectorize" #define DEBUG_TYPE LV_NAME STATISTIC(LoopsVectorized, "Number of loops vectorized"); STATISTIC(LoopsAnalyzed, "Number of loops analyzed for vectorization"); static cl::opt EnableIfConversion("enable-if-conversion", cl::init(true), cl::Hidden, cl::desc("Enable if-conversion during vectorization.")); /// We don't vectorize loops with a known constant trip count below this number. static cl::opt TinyTripCountVectorThreshold("vectorizer-min-trip-count", cl::init(16), cl::Hidden, cl::desc("Don't vectorize loops with a constant " "trip count that is smaller than this " "value.")); static cl::opt MaximizeBandwidth( "vectorizer-maximize-bandwidth", cl::init(false), cl::Hidden, cl::desc("Maximize bandwidth when selecting vectorization factor which " "will be determined by the smallest type in loop.")); /// This enables versioning on the strides of symbolically striding memory /// accesses in code like the following. /// for (i = 0; i < N; ++i) /// A[i * Stride1] += B[i * Stride2] ... /// /// Will be roughly translated to /// if (Stride1 == 1 && Stride2 == 1) { /// for (i = 0; i < N; i+=4) /// A[i:i+3] += ... /// } else /// ... static cl::opt EnableMemAccessVersioning( "enable-mem-access-versioning", cl::init(true), cl::Hidden, cl::desc("Enable symbolic stride memory access versioning")); static cl::opt EnableInterleavedMemAccesses( "enable-interleaved-mem-accesses", cl::init(false), cl::Hidden, cl::desc("Enable vectorization on interleaved memory accesses in a loop")); /// Maximum factor for an interleaved memory access. static cl::opt MaxInterleaveGroupFactor( "max-interleave-group-factor", cl::Hidden, cl::desc("Maximum factor for an interleaved access group (default = 8)"), cl::init(8)); /// We don't interleave loops with a known constant trip count below this /// number. static const unsigned TinyTripCountInterleaveThreshold = 128; static cl::opt ForceTargetNumScalarRegs( "force-target-num-scalar-regs", cl::init(0), cl::Hidden, cl::desc("A flag that overrides the target's number of scalar registers.")); static cl::opt ForceTargetNumVectorRegs( "force-target-num-vector-regs", cl::init(0), cl::Hidden, cl::desc("A flag that overrides the target's number of vector registers.")); /// Maximum vectorization interleave count. static const unsigned MaxInterleaveFactor = 16; static cl::opt ForceTargetMaxScalarInterleaveFactor( "force-target-max-scalar-interleave", cl::init(0), cl::Hidden, cl::desc("A flag that overrides the target's max interleave factor for " "scalar loops.")); static cl::opt ForceTargetMaxVectorInterleaveFactor( "force-target-max-vector-interleave", cl::init(0), cl::Hidden, cl::desc("A flag that overrides the target's max interleave factor for " "vectorized loops.")); static cl::opt ForceTargetInstructionCost( "force-target-instruction-cost", cl::init(0), cl::Hidden, cl::desc("A flag that overrides the target's expected cost for " "an instruction to a single constant value. Mostly " "useful for getting consistent testing.")); static cl::opt SmallLoopCost( "small-loop-cost", cl::init(20), cl::Hidden, cl::desc( "The cost of a loop that is considered 'small' by the interleaver.")); static cl::opt LoopVectorizeWithBlockFrequency( "loop-vectorize-with-block-frequency", cl::init(false), cl::Hidden, cl::desc("Enable the use of the block frequency analysis to access PGO " "heuristics minimizing code growth in cold regions and being more " "aggressive in hot regions.")); // Runtime interleave loops for load/store throughput. static cl::opt EnableLoadStoreRuntimeInterleave( "enable-loadstore-runtime-interleave", cl::init(true), cl::Hidden, cl::desc( "Enable runtime interleaving until load/store ports are saturated")); /// The number of stores in a loop that are allowed to need predication. static cl::opt NumberOfStoresToPredicate( "vectorize-num-stores-pred", cl::init(1), cl::Hidden, cl::desc("Max number of stores to be predicated behind an if.")); static cl::opt EnableIndVarRegisterHeur( "enable-ind-var-reg-heur", cl::init(true), cl::Hidden, cl::desc("Count the induction variable only once when interleaving")); static cl::opt EnableCondStoresVectorization( "enable-cond-stores-vec", cl::init(false), cl::Hidden, cl::desc("Enable if predication of stores during vectorization.")); static cl::opt MaxNestedScalarReductionIC( "max-nested-scalar-reduction-interleave", cl::init(2), cl::Hidden, cl::desc("The maximum interleave count to use when interleaving a scalar " "reduction in a nested loop.")); static cl::opt PragmaVectorizeMemoryCheckThreshold( "pragma-vectorize-memory-check-threshold", cl::init(128), cl::Hidden, cl::desc("The maximum allowed number of runtime memory checks with a " "vectorize(enable) pragma.")); static cl::opt VectorizeSCEVCheckThreshold( "vectorize-scev-check-threshold", cl::init(16), cl::Hidden, cl::desc("The maximum number of SCEV checks allowed.")); static cl::opt PragmaVectorizeSCEVCheckThreshold( "pragma-vectorize-scev-check-threshold", cl::init(128), cl::Hidden, cl::desc("The maximum number of SCEV checks allowed with a " "vectorize(enable) pragma")); namespace { // Forward declarations. class LoopVectorizeHints; class LoopVectorizationLegality; class LoopVectorizationCostModel; class LoopVectorizationRequirements; /// \brief This modifies LoopAccessReport to initialize message with /// loop-vectorizer-specific part. class VectorizationReport : public LoopAccessReport { public: VectorizationReport(Instruction *I = nullptr) : LoopAccessReport("loop not vectorized: ", I) {} /// \brief This allows promotion of the loop-access analysis report into the /// loop-vectorizer report. It modifies the message to add the /// loop-vectorizer-specific part of the message. explicit VectorizationReport(const LoopAccessReport &R) : LoopAccessReport(Twine("loop not vectorized: ") + R.str(), R.getInstr()) {} }; /// A helper function for converting Scalar types to vector types. /// If the incoming type is void, we return void. If the VF is 1, we return /// the scalar type. static Type* ToVectorTy(Type *Scalar, unsigned VF) { if (Scalar->isVoidTy() || VF == 1) return Scalar; return VectorType::get(Scalar, VF); } /// A helper function that returns GEP instruction and knows to skip a /// 'bitcast'. The 'bitcast' may be skipped if the source and the destination /// pointee types of the 'bitcast' have the same size. /// For example: /// bitcast double** %var to i64* - can be skipped /// bitcast double** %var to i8* - can not static GetElementPtrInst *getGEPInstruction(Value *Ptr) { if (isa(Ptr)) return cast(Ptr); if (isa(Ptr) && isa(cast(Ptr)->getOperand(0))) { Type *BitcastTy = Ptr->getType(); Type *GEPTy = cast(Ptr)->getSrcTy(); if (!isa(BitcastTy) || !isa(GEPTy)) return nullptr; Type *Pointee1Ty = cast(BitcastTy)->getPointerElementType(); Type *Pointee2Ty = cast(GEPTy)->getPointerElementType(); const DataLayout &DL = cast(Ptr)->getModule()->getDataLayout(); if (DL.getTypeSizeInBits(Pointee1Ty) == DL.getTypeSizeInBits(Pointee2Ty)) return cast(cast(Ptr)->getOperand(0)); } return nullptr; } /// InnerLoopVectorizer vectorizes loops which contain only one basic /// block to a specified vectorization factor (VF). /// This class performs the widening of scalars into vectors, or multiple /// scalars. This class also implements the following features: /// * It inserts an epilogue loop for handling loops that don't have iteration /// counts that are known to be a multiple of the vectorization factor. /// * It handles the code generation for reduction variables. /// * Scalarization (implementation using scalars) of un-vectorizable /// instructions. /// InnerLoopVectorizer does not perform any vectorization-legality /// checks, and relies on the caller to check for the different legality /// aspects. The InnerLoopVectorizer relies on the /// LoopVectorizationLegality class to provide information about the induction /// and reduction variables that were found to a given vectorization factor. class InnerLoopVectorizer { public: InnerLoopVectorizer(Loop *OrigLoop, PredicatedScalarEvolution &PSE, LoopInfo *LI, DominatorTree *DT, const TargetLibraryInfo *TLI, const TargetTransformInfo *TTI, unsigned VecWidth, unsigned UnrollFactor) : OrigLoop(OrigLoop), PSE(PSE), LI(LI), DT(DT), TLI(TLI), TTI(TTI), VF(VecWidth), UF(UnrollFactor), Builder(PSE.getSE()->getContext()), Induction(nullptr), OldInduction(nullptr), WidenMap(UnrollFactor), TripCount(nullptr), VectorTripCount(nullptr), Legal(nullptr), AddedSafetyChecks(false) {} // Perform the actual loop widening (vectorization). // MinimumBitWidths maps scalar integer values to the smallest bitwidth they // can be validly truncated to. The cost model has assumed this truncation // will happen when vectorizing. void vectorize(LoopVectorizationLegality *L, MapVector MinimumBitWidths) { MinBWs = MinimumBitWidths; Legal = L; // Create a new empty loop. Unlink the old loop and connect the new one. createEmptyLoop(); // Widen each instruction in the old loop to a new one in the new loop. // Use the Legality module to find the induction and reduction variables. vectorizeLoop(); } // Return true if any runtime check is added. bool IsSafetyChecksAdded() { return AddedSafetyChecks; } virtual ~InnerLoopVectorizer() {} protected: /// A small list of PHINodes. typedef SmallVector PhiVector; /// When we unroll loops we have multiple vector values for each scalar. /// This data structure holds the unrolled and vectorized values that /// originated from one scalar instruction. typedef SmallVector VectorParts; // When we if-convert we need to create edge masks. We have to cache values // so that we don't end up with exponential recursion/IR. typedef DenseMap, VectorParts> EdgeMaskCache; /// Create an empty loop, based on the loop ranges of the old loop. void createEmptyLoop(); /// Create a new induction variable inside L. PHINode *createInductionVariable(Loop *L, Value *Start, Value *End, Value *Step, Instruction *DL); /// Copy and widen the instructions from the old loop. virtual void vectorizeLoop(); /// \brief The Loop exit block may have single value PHI nodes where the /// incoming value is 'Undef'. While vectorizing we only handled real values /// that were defined inside the loop. Here we fix the 'undef case'. /// See PR14725. void fixLCSSAPHIs(); /// Shrinks vector element sizes based on information in "MinBWs". void truncateToMinimalBitwidths(); /// A helper function that computes the predicate of the block BB, assuming /// that the header block of the loop is set to True. It returns the *entry* /// mask for the block BB. VectorParts createBlockInMask(BasicBlock *BB); /// A helper function that computes the predicate of the edge between SRC /// and DST. VectorParts createEdgeMask(BasicBlock *Src, BasicBlock *Dst); /// A helper function to vectorize a single BB within the innermost loop. void vectorizeBlockInLoop(BasicBlock *BB, PhiVector *PV); /// Vectorize a single PHINode in a block. This method handles the induction /// variable canonicalization. It supports both VF = 1 for unrolled loops and /// arbitrary length vectors. void widenPHIInstruction(Instruction *PN, VectorParts &Entry, unsigned UF, unsigned VF, PhiVector *PV); /// Insert the new loop to the loop hierarchy and pass manager /// and update the analysis passes. void updateAnalysis(); /// This instruction is un-vectorizable. Implement it as a sequence /// of scalars. If \p IfPredicateStore is true we need to 'hide' each /// scalarized instruction behind an if block predicated on the control /// dependence of the instruction. virtual void scalarizeInstruction(Instruction *Instr, bool IfPredicateStore=false); /// Vectorize Load and Store instructions, virtual void vectorizeMemoryInstruction(Instruction *Instr); /// Create a broadcast instruction. This method generates a broadcast /// instruction (shuffle) for loop invariant values and for the induction /// value. If this is the induction variable then we extend it to N, N+1, ... /// this is needed because each iteration in the loop corresponds to a SIMD /// element. virtual Value *getBroadcastInstrs(Value *V); /// This function adds (StartIdx, StartIdx + Step, StartIdx + 2*Step, ...) /// to each vector element of Val. The sequence starts at StartIndex. virtual Value *getStepVector(Value *Val, int StartIdx, Value *Step); /// When we go over instructions in the basic block we rely on previous /// values within the current basic block or on loop invariant values. /// When we widen (vectorize) values we place them in the map. If the values /// are not within the map, they have to be loop invariant, so we simply /// broadcast them into a vector. VectorParts &getVectorValue(Value *V); /// Try to vectorize the interleaved access group that \p Instr belongs to. void vectorizeInterleaveGroup(Instruction *Instr); /// Generate a shuffle sequence that will reverse the vector Vec. virtual Value *reverseVector(Value *Vec); /// Returns (and creates if needed) the original loop trip count. Value *getOrCreateTripCount(Loop *NewLoop); /// Returns (and creates if needed) the trip count of the widened loop. Value *getOrCreateVectorTripCount(Loop *NewLoop); /// Emit a bypass check to see if the trip count would overflow, or we /// wouldn't have enough iterations to execute one vector loop. void emitMinimumIterationCountCheck(Loop *L, BasicBlock *Bypass); /// Emit a bypass check to see if the vector trip count is nonzero. void emitVectorLoopEnteredCheck(Loop *L, BasicBlock *Bypass); /// Emit a bypass check to see if all of the SCEV assumptions we've /// had to make are correct. void emitSCEVChecks(Loop *L, BasicBlock *Bypass); /// Emit bypass checks to check any memory assumptions we may have made. void emitMemRuntimeChecks(Loop *L, BasicBlock *Bypass); /// This is a helper class that holds the vectorizer state. It maps scalar /// instructions to vector instructions. When the code is 'unrolled' then /// then a single scalar value is mapped to multiple vector parts. The parts /// are stored in the VectorPart type. struct ValueMap { /// C'tor. UnrollFactor controls the number of vectors ('parts') that /// are mapped. ValueMap(unsigned UnrollFactor) : UF(UnrollFactor) {} /// \return True if 'Key' is saved in the Value Map. bool has(Value *Key) const { return MapStorage.count(Key); } /// Initializes a new entry in the map. Sets all of the vector parts to the /// save value in 'Val'. /// \return A reference to a vector with splat values. VectorParts &splat(Value *Key, Value *Val) { VectorParts &Entry = MapStorage[Key]; Entry.assign(UF, Val); return Entry; } ///\return A reference to the value that is stored at 'Key'. VectorParts &get(Value *Key) { VectorParts &Entry = MapStorage[Key]; if (Entry.empty()) Entry.resize(UF); assert(Entry.size() == UF); return Entry; } private: /// The unroll factor. Each entry in the map stores this number of vector /// elements. unsigned UF; /// Map storage. We use std::map and not DenseMap because insertions to a /// dense map invalidates its iterators. std::map MapStorage; }; /// The original loop. Loop *OrigLoop; /// A wrapper around ScalarEvolution used to add runtime SCEV checks. Applies /// dynamic knowledge to simplify SCEV expressions and converts them to a /// more usable form. PredicatedScalarEvolution &PSE; /// Loop Info. LoopInfo *LI; /// Dominator Tree. DominatorTree *DT; /// Alias Analysis. AliasAnalysis *AA; /// Target Library Info. const TargetLibraryInfo *TLI; /// Target Transform Info. const TargetTransformInfo *TTI; /// The vectorization SIMD factor to use. Each vector will have this many /// vector elements. unsigned VF; protected: /// The vectorization unroll factor to use. Each scalar is vectorized to this /// many different vector instructions. unsigned UF; /// The builder that we use IRBuilder<> Builder; // --- Vectorization state --- /// The vector-loop preheader. BasicBlock *LoopVectorPreHeader; /// The scalar-loop preheader. BasicBlock *LoopScalarPreHeader; /// Middle Block between the vector and the scalar. BasicBlock *LoopMiddleBlock; ///The ExitBlock of the scalar loop. BasicBlock *LoopExitBlock; ///The vector loop body. SmallVector LoopVectorBody; ///The scalar loop body. BasicBlock *LoopScalarBody; /// A list of all bypass blocks. The first block is the entry of the loop. SmallVector LoopBypassBlocks; /// The new Induction variable which was added to the new block. PHINode *Induction; /// The induction variable of the old basic block. PHINode *OldInduction; /// Maps scalars to widened vectors. ValueMap WidenMap; /// Store instructions that should be predicated, as a pair /// SmallVector, 4> PredicatedStores; EdgeMaskCache MaskCache; /// Trip count of the original loop. Value *TripCount; /// Trip count of the widened loop (TripCount - TripCount % (VF*UF)) Value *VectorTripCount; /// Map of scalar integer values to the smallest bitwidth they can be legally /// represented as. The vector equivalents of these values should be truncated /// to this type. MapVector MinBWs; LoopVectorizationLegality *Legal; // Record whether runtime check is added. bool AddedSafetyChecks; }; class InnerLoopUnroller : public InnerLoopVectorizer { public: InnerLoopUnroller(Loop *OrigLoop, PredicatedScalarEvolution &PSE, LoopInfo *LI, DominatorTree *DT, const TargetLibraryInfo *TLI, const TargetTransformInfo *TTI, unsigned UnrollFactor) : InnerLoopVectorizer(OrigLoop, PSE, LI, DT, TLI, TTI, 1, UnrollFactor) {} private: void scalarizeInstruction(Instruction *Instr, bool IfPredicateStore = false) override; void vectorizeMemoryInstruction(Instruction *Instr) override; Value *getBroadcastInstrs(Value *V) override; Value *getStepVector(Value *Val, int StartIdx, Value *Step) override; Value *reverseVector(Value *Vec) override; }; /// \brief Look for a meaningful debug location on the instruction or it's /// operands. static Instruction *getDebugLocFromInstOrOperands(Instruction *I) { if (!I) return I; DebugLoc Empty; if (I->getDebugLoc() != Empty) return I; for (User::op_iterator OI = I->op_begin(), OE = I->op_end(); OI != OE; ++OI) { if (Instruction *OpInst = dyn_cast(*OI)) if (OpInst->getDebugLoc() != Empty) return OpInst; } return I; } /// \brief Set the debug location in the builder using the debug location in the /// instruction. static void setDebugLocFromInst(IRBuilder<> &B, const Value *Ptr) { if (const Instruction *Inst = dyn_cast_or_null(Ptr)) B.SetCurrentDebugLocation(Inst->getDebugLoc()); else B.SetCurrentDebugLocation(DebugLoc()); } #ifndef NDEBUG /// \return string containing a file name and a line # for the given loop. static std::string getDebugLocString(const Loop *L) { std::string Result; if (L) { raw_string_ostream OS(Result); if (const DebugLoc LoopDbgLoc = L->getStartLoc()) LoopDbgLoc.print(OS); else // Just print the module name. OS << L->getHeader()->getParent()->getParent()->getModuleIdentifier(); OS.flush(); } return Result; } #endif /// \brief Propagate known metadata from one instruction to another. static void propagateMetadata(Instruction *To, const Instruction *From) { SmallVector, 4> Metadata; From->getAllMetadataOtherThanDebugLoc(Metadata); for (auto M : Metadata) { unsigned Kind = M.first; // These are safe to transfer (this is safe for TBAA, even when we // if-convert, because should that metadata have had a control dependency // on the condition, and thus actually aliased with some other // non-speculated memory access when the condition was false, this would be // caught by the runtime overlap checks). if (Kind != LLVMContext::MD_tbaa && Kind != LLVMContext::MD_alias_scope && Kind != LLVMContext::MD_noalias && Kind != LLVMContext::MD_fpmath && Kind != LLVMContext::MD_nontemporal) continue; To->setMetadata(Kind, M.second); } } /// \brief Propagate known metadata from one instruction to a vector of others. static void propagateMetadata(SmallVectorImpl &To, const Instruction *From) { for (Value *V : To) if (Instruction *I = dyn_cast(V)) propagateMetadata(I, From); } /// \brief The group of interleaved loads/stores sharing the same stride and /// close to each other. /// /// Each member in this group has an index starting from 0, and the largest /// index should be less than interleaved factor, which is equal to the absolute /// value of the access's stride. /// /// E.g. An interleaved load group of factor 4: /// for (unsigned i = 0; i < 1024; i+=4) { /// a = A[i]; // Member of index 0 /// b = A[i+1]; // Member of index 1 /// d = A[i+3]; // Member of index 3 /// ... /// } /// /// An interleaved store group of factor 4: /// for (unsigned i = 0; i < 1024; i+=4) { /// ... /// A[i] = a; // Member of index 0 /// A[i+1] = b; // Member of index 1 /// A[i+2] = c; // Member of index 2 /// A[i+3] = d; // Member of index 3 /// } /// /// Note: the interleaved load group could have gaps (missing members), but /// the interleaved store group doesn't allow gaps. class InterleaveGroup { public: InterleaveGroup(Instruction *Instr, int Stride, unsigned Align) : Align(Align), SmallestKey(0), LargestKey(0), InsertPos(Instr) { assert(Align && "The alignment should be non-zero"); Factor = std::abs(Stride); assert(Factor > 1 && "Invalid interleave factor"); Reverse = Stride < 0; Members[0] = Instr; } bool isReverse() const { return Reverse; } unsigned getFactor() const { return Factor; } unsigned getAlignment() const { return Align; } unsigned getNumMembers() const { return Members.size(); } /// \brief Try to insert a new member \p Instr with index \p Index and /// alignment \p NewAlign. The index is related to the leader and it could be /// negative if it is the new leader. /// /// \returns false if the instruction doesn't belong to the group. bool insertMember(Instruction *Instr, int Index, unsigned NewAlign) { assert(NewAlign && "The new member's alignment should be non-zero"); int Key = Index + SmallestKey; // Skip if there is already a member with the same index. if (Members.count(Key)) return false; if (Key > LargestKey) { // The largest index is always less than the interleave factor. if (Index >= static_cast(Factor)) return false; LargestKey = Key; } else if (Key < SmallestKey) { // The largest index is always less than the interleave factor. if (LargestKey - Key >= static_cast(Factor)) return false; SmallestKey = Key; } // It's always safe to select the minimum alignment. Align = std::min(Align, NewAlign); Members[Key] = Instr; return true; } /// \brief Get the member with the given index \p Index /// /// \returns nullptr if contains no such member. Instruction *getMember(unsigned Index) const { int Key = SmallestKey + Index; if (!Members.count(Key)) return nullptr; return Members.find(Key)->second; } /// \brief Get the index for the given member. Unlike the key in the member /// map, the index starts from 0. unsigned getIndex(Instruction *Instr) const { for (auto I : Members) if (I.second == Instr) return I.first - SmallestKey; llvm_unreachable("InterleaveGroup contains no such member"); } Instruction *getInsertPos() const { return InsertPos; } void setInsertPos(Instruction *Inst) { InsertPos = Inst; } private: unsigned Factor; // Interleave Factor. bool Reverse; unsigned Align; DenseMap Members; int SmallestKey; int LargestKey; // To avoid breaking dependences, vectorized instructions of an interleave // group should be inserted at either the first load or the last store in // program order. // // E.g. %even = load i32 // Insert Position // %add = add i32 %even // Use of %even // %odd = load i32 // // store i32 %even // %odd = add i32 // Def of %odd // store i32 %odd // Insert Position Instruction *InsertPos; }; /// \brief Drive the analysis of interleaved memory accesses in the loop. /// /// Use this class to analyze interleaved accesses only when we can vectorize /// a loop. Otherwise it's meaningless to do analysis as the vectorization /// on interleaved accesses is unsafe. /// /// The analysis collects interleave groups and records the relationships /// between the member and the group in a map. class InterleavedAccessInfo { public: InterleavedAccessInfo(PredicatedScalarEvolution &PSE, Loop *L, DominatorTree *DT) : PSE(PSE), TheLoop(L), DT(DT) {} ~InterleavedAccessInfo() { SmallSet DelSet; // Avoid releasing a pointer twice. for (auto &I : InterleaveGroupMap) DelSet.insert(I.second); for (auto *Ptr : DelSet) delete Ptr; } /// \brief Analyze the interleaved accesses and collect them in interleave /// groups. Substitute symbolic strides using \p Strides. void analyzeInterleaving(const ValueToValueMap &Strides); /// \brief Check if \p Instr belongs to any interleave group. bool isInterleaved(Instruction *Instr) const { return InterleaveGroupMap.count(Instr); } /// \brief Get the interleave group that \p Instr belongs to. /// /// \returns nullptr if doesn't have such group. InterleaveGroup *getInterleaveGroup(Instruction *Instr) const { if (InterleaveGroupMap.count(Instr)) return InterleaveGroupMap.find(Instr)->second; return nullptr; } private: /// A wrapper around ScalarEvolution, used to add runtime SCEV checks. /// Simplifies SCEV expressions in the context of existing SCEV assumptions. /// The interleaved access analysis can also add new predicates (for example /// by versioning strides of pointers). PredicatedScalarEvolution &PSE; Loop *TheLoop; DominatorTree *DT; /// Holds the relationships between the members and the interleave group. DenseMap InterleaveGroupMap; /// \brief The descriptor for a strided memory access. struct StrideDescriptor { StrideDescriptor(int Stride, const SCEV *Scev, unsigned Size, unsigned Align) : Stride(Stride), Scev(Scev), Size(Size), Align(Align) {} StrideDescriptor() : Stride(0), Scev(nullptr), Size(0), Align(0) {} int Stride; // The access's stride. It is negative for a reverse access. const SCEV *Scev; // The scalar expression of this access unsigned Size; // The size of the memory object. unsigned Align; // The alignment of this access. }; /// \brief Create a new interleave group with the given instruction \p Instr, /// stride \p Stride and alignment \p Align. /// /// \returns the newly created interleave group. InterleaveGroup *createInterleaveGroup(Instruction *Instr, int Stride, unsigned Align) { assert(!InterleaveGroupMap.count(Instr) && "Already in an interleaved access group"); InterleaveGroupMap[Instr] = new InterleaveGroup(Instr, Stride, Align); return InterleaveGroupMap[Instr]; } /// \brief Release the group and remove all the relationships. void releaseGroup(InterleaveGroup *Group) { for (unsigned i = 0; i < Group->getFactor(); i++) if (Instruction *Member = Group->getMember(i)) InterleaveGroupMap.erase(Member); delete Group; } /// \brief Collect all the accesses with a constant stride in program order. void collectConstStridedAccesses( MapVector &StrideAccesses, const ValueToValueMap &Strides); }; /// Utility class for getting and setting loop vectorizer hints in the form /// of loop metadata. /// This class keeps a number of loop annotations locally (as member variables) /// and can, upon request, write them back as metadata on the loop. It will /// initially scan the loop for existing metadata, and will update the local /// values based on information in the loop. /// We cannot write all values to metadata, as the mere presence of some info, /// for example 'force', means a decision has been made. So, we need to be /// careful NOT to add them if the user hasn't specifically asked so. class LoopVectorizeHints { enum HintKind { HK_WIDTH, HK_UNROLL, HK_FORCE }; /// Hint - associates name and validation with the hint value. struct Hint { const char * Name; unsigned Value; // This may have to change for non-numeric values. HintKind Kind; Hint(const char * Name, unsigned Value, HintKind Kind) : Name(Name), Value(Value), Kind(Kind) { } bool validate(unsigned Val) { switch (Kind) { case HK_WIDTH: return isPowerOf2_32(Val) && Val <= VectorizerParams::MaxVectorWidth; case HK_UNROLL: return isPowerOf2_32(Val) && Val <= MaxInterleaveFactor; case HK_FORCE: return (Val <= 1); } return false; } }; /// Vectorization width. Hint Width; /// Vectorization interleave factor. Hint Interleave; /// Vectorization forced Hint Force; /// Return the loop metadata prefix. static StringRef Prefix() { return "llvm.loop."; } public: enum ForceKind { FK_Undefined = -1, ///< Not selected. FK_Disabled = 0, ///< Forcing disabled. FK_Enabled = 1, ///< Forcing enabled. }; LoopVectorizeHints(const Loop *L, bool DisableInterleaving) : Width("vectorize.width", VectorizerParams::VectorizationFactor, HK_WIDTH), Interleave("interleave.count", DisableInterleaving, HK_UNROLL), Force("vectorize.enable", FK_Undefined, HK_FORCE), TheLoop(L) { // Populate values with existing loop metadata. getHintsFromMetadata(); // force-vector-interleave overrides DisableInterleaving. if (VectorizerParams::isInterleaveForced()) Interleave.Value = VectorizerParams::VectorizationInterleave; DEBUG(if (DisableInterleaving && Interleave.Value == 1) dbgs() << "LV: Interleaving disabled by the pass manager\n"); } /// Mark the loop L as already vectorized by setting the width to 1. void setAlreadyVectorized() { Width.Value = Interleave.Value = 1; Hint Hints[] = {Width, Interleave}; writeHintsToMetadata(Hints); } bool allowVectorization(Function *F, Loop *L, bool AlwaysVectorize) const { if (getForce() == LoopVectorizeHints::FK_Disabled) { DEBUG(dbgs() << "LV: Not vectorizing: #pragma vectorize disable.\n"); emitOptimizationRemarkAnalysis(F->getContext(), vectorizeAnalysisPassName(), *F, L->getStartLoc(), emitRemark()); return false; } if (!AlwaysVectorize && getForce() != LoopVectorizeHints::FK_Enabled) { DEBUG(dbgs() << "LV: Not vectorizing: No #pragma vectorize enable.\n"); emitOptimizationRemarkAnalysis(F->getContext(), vectorizeAnalysisPassName(), *F, L->getStartLoc(), emitRemark()); return false; } if (getWidth() == 1 && getInterleave() == 1) { // FIXME: Add a separate metadata to indicate when the loop has already // been vectorized instead of setting width and count to 1. DEBUG(dbgs() << "LV: Not vectorizing: Disabled/already vectorized.\n"); // FIXME: Add interleave.disable metadata. This will allow // vectorize.disable to be used without disabling the pass and errors // to differentiate between disabled vectorization and a width of 1. emitOptimizationRemarkAnalysis( F->getContext(), vectorizeAnalysisPassName(), *F, L->getStartLoc(), "loop not vectorized: vectorization and interleaving are explicitly " "disabled, or vectorize width and interleave count are both set to " "1"); return false; } return true; } /// Dumps all the hint information. std::string emitRemark() const { VectorizationReport R; if (Force.Value == LoopVectorizeHints::FK_Disabled) R << "vectorization is explicitly disabled"; else { R << "use -Rpass-analysis=loop-vectorize for more info"; if (Force.Value == LoopVectorizeHints::FK_Enabled) { R << " (Force=true"; if (Width.Value != 0) R << ", Vector Width=" << Width.Value; if (Interleave.Value != 0) R << ", Interleave Count=" << Interleave.Value; R << ")"; } } return R.str(); } unsigned getWidth() const { return Width.Value; } unsigned getInterleave() const { return Interleave.Value; } enum ForceKind getForce() const { return (ForceKind)Force.Value; } const char *vectorizeAnalysisPassName() const { // If hints are provided that don't disable vectorization use the // AlwaysPrint pass name to force the frontend to print the diagnostic. if (getWidth() == 1) return LV_NAME; if (getForce() == LoopVectorizeHints::FK_Disabled) return LV_NAME; if (getForce() == LoopVectorizeHints::FK_Undefined && getWidth() == 0) return LV_NAME; return DiagnosticInfo::AlwaysPrint; } bool allowReordering() const { // When enabling loop hints are provided we allow the vectorizer to change // the order of operations that is given by the scalar loop. This is not // enabled by default because can be unsafe or inefficient. For example, // reordering floating-point operations will change the way round-off // error accumulates in the loop. return getForce() == LoopVectorizeHints::FK_Enabled || getWidth() > 1; } private: /// Find hints specified in the loop metadata and update local values. void getHintsFromMetadata() { MDNode *LoopID = TheLoop->getLoopID(); if (!LoopID) return; // First operand should refer to the loop id itself. assert(LoopID->getNumOperands() > 0 && "requires at least one operand"); assert(LoopID->getOperand(0) == LoopID && "invalid loop id"); for (unsigned i = 1, ie = LoopID->getNumOperands(); i < ie; ++i) { const MDString *S = nullptr; SmallVector Args; // The expected hint is either a MDString or a MDNode with the first // operand a MDString. if (const MDNode *MD = dyn_cast(LoopID->getOperand(i))) { if (!MD || MD->getNumOperands() == 0) continue; S = dyn_cast(MD->getOperand(0)); for (unsigned i = 1, ie = MD->getNumOperands(); i < ie; ++i) Args.push_back(MD->getOperand(i)); } else { S = dyn_cast(LoopID->getOperand(i)); assert(Args.size() == 0 && "too many arguments for MDString"); } if (!S) continue; // Check if the hint starts with the loop metadata prefix. StringRef Name = S->getString(); if (Args.size() == 1) setHint(Name, Args[0]); } } /// Checks string hint with one operand and set value if valid. void setHint(StringRef Name, Metadata *Arg) { if (!Name.startswith(Prefix())) return; Name = Name.substr(Prefix().size(), StringRef::npos); const ConstantInt *C = mdconst::dyn_extract(Arg); if (!C) return; unsigned Val = C->getZExtValue(); Hint *Hints[] = {&Width, &Interleave, &Force}; for (auto H : Hints) { if (Name == H->Name) { if (H->validate(Val)) H->Value = Val; else DEBUG(dbgs() << "LV: ignoring invalid hint '" << Name << "'\n"); break; } } } /// Create a new hint from name / value pair. MDNode *createHintMetadata(StringRef Name, unsigned V) const { LLVMContext &Context = TheLoop->getHeader()->getContext(); Metadata *MDs[] = {MDString::get(Context, Name), ConstantAsMetadata::get( ConstantInt::get(Type::getInt32Ty(Context), V))}; return MDNode::get(Context, MDs); } /// Matches metadata with hint name. bool matchesHintMetadataName(MDNode *Node, ArrayRef HintTypes) { MDString* Name = dyn_cast(Node->getOperand(0)); if (!Name) return false; for (auto H : HintTypes) if (Name->getString().endswith(H.Name)) return true; return false; } /// Sets current hints into loop metadata, keeping other values intact. void writeHintsToMetadata(ArrayRef HintTypes) { if (HintTypes.size() == 0) return; // Reserve the first element to LoopID (see below). SmallVector MDs(1); // If the loop already has metadata, then ignore the existing operands. MDNode *LoopID = TheLoop->getLoopID(); if (LoopID) { for (unsigned i = 1, ie = LoopID->getNumOperands(); i < ie; ++i) { MDNode *Node = cast(LoopID->getOperand(i)); // If node in update list, ignore old value. if (!matchesHintMetadataName(Node, HintTypes)) MDs.push_back(Node); } } // Now, add the missing hints. for (auto H : HintTypes) MDs.push_back(createHintMetadata(Twine(Prefix(), H.Name).str(), H.Value)); // Replace current metadata node with new one. LLVMContext &Context = TheLoop->getHeader()->getContext(); MDNode *NewLoopID = MDNode::get(Context, MDs); // Set operand 0 to refer to the loop id itself. NewLoopID->replaceOperandWith(0, NewLoopID); TheLoop->setLoopID(NewLoopID); } /// The loop these hints belong to. const Loop *TheLoop; }; static void emitAnalysisDiag(const Function *TheFunction, const Loop *TheLoop, const LoopVectorizeHints &Hints, const LoopAccessReport &Message) { const char *Name = Hints.vectorizeAnalysisPassName(); LoopAccessReport::emitAnalysis(Message, TheFunction, TheLoop, Name); } static void emitMissedWarning(Function *F, Loop *L, const LoopVectorizeHints &LH) { emitOptimizationRemarkMissed(F->getContext(), LV_NAME, *F, L->getStartLoc(), LH.emitRemark()); if (LH.getForce() == LoopVectorizeHints::FK_Enabled) { if (LH.getWidth() != 1) emitLoopVectorizeWarning( F->getContext(), *F, L->getStartLoc(), "failed explicitly specified loop vectorization"); else if (LH.getInterleave() != 1) emitLoopInterleaveWarning( F->getContext(), *F, L->getStartLoc(), "failed explicitly specified loop interleaving"); } } /// LoopVectorizationLegality checks if it is legal to vectorize a loop, and /// to what vectorization factor. /// This class does not look at the profitability of vectorization, only the /// legality. This class has two main kinds of checks: /// * Memory checks - The code in canVectorizeMemory checks if vectorization /// will change the order of memory accesses in a way that will change the /// correctness of the program. /// * Scalars checks - The code in canVectorizeInstrs and canVectorizeMemory /// checks for a number of different conditions, such as the availability of a /// single induction variable, that all types are supported and vectorize-able, /// etc. This code reflects the capabilities of InnerLoopVectorizer. /// This class is also used by InnerLoopVectorizer for identifying /// induction variable and the different reduction variables. class LoopVectorizationLegality { public: LoopVectorizationLegality(Loop *L, PredicatedScalarEvolution &PSE, DominatorTree *DT, TargetLibraryInfo *TLI, AliasAnalysis *AA, Function *F, const TargetTransformInfo *TTI, LoopAccessAnalysis *LAA, LoopVectorizationRequirements *R, const LoopVectorizeHints *H) : NumPredStores(0), TheLoop(L), PSE(PSE), TLI(TLI), TheFunction(F), TTI(TTI), DT(DT), LAA(LAA), LAI(nullptr), InterleaveInfo(PSE, L, DT), Induction(nullptr), WidestIndTy(nullptr), HasFunNoNaNAttr(false), Requirements(R), Hints(H) {} /// ReductionList contains the reduction descriptors for all /// of the reductions that were found in the loop. typedef DenseMap ReductionList; /// InductionList saves induction variables and maps them to the /// induction descriptor. typedef MapVector InductionList; /// Returns true if it is legal to vectorize this loop. /// This does not mean that it is profitable to vectorize this /// loop, only that it is legal to do so. bool canVectorize(); /// Returns the Induction variable. PHINode *getInduction() { return Induction; } /// Returns the reduction variables found in the loop. ReductionList *getReductionVars() { return &Reductions; } /// Returns the induction variables found in the loop. InductionList *getInductionVars() { return &Inductions; } /// Returns the widest induction type. Type *getWidestInductionType() { return WidestIndTy; } /// Returns True if V is an induction variable in this loop. bool isInductionVariable(const Value *V); /// Returns True if PN is a reduction variable in this loop. bool isReductionVariable(PHINode *PN) { return Reductions.count(PN); } /// Return true if the block BB needs to be predicated in order for the loop /// to be vectorized. bool blockNeedsPredication(BasicBlock *BB); /// Check if this pointer is consecutive when vectorizing. This happens /// when the last index of the GEP is the induction variable, or that the /// pointer itself is an induction variable. /// This check allows us to vectorize A[idx] into a wide load/store. /// Returns: /// 0 - Stride is unknown or non-consecutive. /// 1 - Address is consecutive. /// -1 - Address is consecutive, and decreasing. int isConsecutivePtr(Value *Ptr); /// Returns true if the value V is uniform within the loop. bool isUniform(Value *V); /// Returns true if this instruction will remain scalar after vectorization. bool isUniformAfterVectorization(Instruction* I) { return Uniforms.count(I); } /// Returns the information that we collected about runtime memory check. const RuntimePointerChecking *getRuntimePointerChecking() const { return LAI->getRuntimePointerChecking(); } const LoopAccessInfo *getLAI() const { return LAI; } /// \brief Check if \p Instr belongs to any interleaved access group. bool isAccessInterleaved(Instruction *Instr) { return InterleaveInfo.isInterleaved(Instr); } /// \brief Get the interleaved access group that \p Instr belongs to. const InterleaveGroup *getInterleavedAccessGroup(Instruction *Instr) { return InterleaveInfo.getInterleaveGroup(Instr); } unsigned getMaxSafeDepDistBytes() { return LAI->getMaxSafeDepDistBytes(); } bool hasStride(Value *V) { return StrideSet.count(V); } bool mustCheckStrides() { return !StrideSet.empty(); } SmallPtrSet::iterator strides_begin() { return StrideSet.begin(); } SmallPtrSet::iterator strides_end() { return StrideSet.end(); } /// Returns true if the target machine supports masked store operation /// for the given \p DataType and kind of access to \p Ptr. bool isLegalMaskedStore(Type *DataType, Value *Ptr) { return isConsecutivePtr(Ptr) && TTI->isLegalMaskedStore(DataType); } /// Returns true if the target machine supports masked load operation /// for the given \p DataType and kind of access to \p Ptr. bool isLegalMaskedLoad(Type *DataType, Value *Ptr) { return isConsecutivePtr(Ptr) && TTI->isLegalMaskedLoad(DataType); } /// Returns true if vector representation of the instruction \p I /// requires mask. bool isMaskRequired(const Instruction* I) { return (MaskedOp.count(I) != 0); } unsigned getNumStores() const { return LAI->getNumStores(); } unsigned getNumLoads() const { return LAI->getNumLoads(); } unsigned getNumPredStores() const { return NumPredStores; } private: /// Check if a single basic block loop is vectorizable. /// At this point we know that this is a loop with a constant trip count /// and we only need to check individual instructions. bool canVectorizeInstrs(); /// When we vectorize loops we may change the order in which /// we read and write from memory. This method checks if it is /// legal to vectorize the code, considering only memory constrains. /// Returns true if the loop is vectorizable bool canVectorizeMemory(); /// Return true if we can vectorize this loop using the IF-conversion /// transformation. bool canVectorizeWithIfConvert(); /// Collect the variables that need to stay uniform after vectorization. void collectLoopUniforms(); /// Return true if all of the instructions in the block can be speculatively /// executed. \p SafePtrs is a list of addresses that are known to be legal /// and we know that we can read from them without segfault. bool blockCanBePredicated(BasicBlock *BB, SmallPtrSetImpl &SafePtrs); /// \brief Collect memory access with loop invariant strides. /// /// Looks for accesses like "a[i * StrideA]" where "StrideA" is loop /// invariant. void collectStridedAccess(Value *LoadOrStoreInst); /// Report an analysis message to assist the user in diagnosing loops that are /// not vectorized. These are handled as LoopAccessReport rather than /// VectorizationReport because the << operator of VectorizationReport returns /// LoopAccessReport. void emitAnalysis(const LoopAccessReport &Message) const { emitAnalysisDiag(TheFunction, TheLoop, *Hints, Message); } unsigned NumPredStores; /// The loop that we evaluate. Loop *TheLoop; /// A wrapper around ScalarEvolution used to add runtime SCEV checks. /// Applies dynamic knowledge to simplify SCEV expressions in the context /// of existing SCEV assumptions. The analysis will also add a minimal set /// of new predicates if this is required to enable vectorization and /// unrolling. PredicatedScalarEvolution &PSE; /// Target Library Info. TargetLibraryInfo *TLI; /// Parent function Function *TheFunction; /// Target Transform Info const TargetTransformInfo *TTI; /// Dominator Tree. DominatorTree *DT; // LoopAccess analysis. LoopAccessAnalysis *LAA; // And the loop-accesses info corresponding to this loop. This pointer is // null until canVectorizeMemory sets it up. const LoopAccessInfo *LAI; /// The interleave access information contains groups of interleaved accesses /// with the same stride and close to each other. InterleavedAccessInfo InterleaveInfo; // --- vectorization state --- // /// Holds the integer induction variable. This is the counter of the /// loop. PHINode *Induction; /// Holds the reduction variables. ReductionList Reductions; /// Holds all of the induction variables that we found in the loop. /// Notice that inductions don't need to start at zero and that induction /// variables can be pointers. InductionList Inductions; /// Holds the widest induction type encountered. Type *WidestIndTy; /// Allowed outside users. This holds the reduction /// vars which can be accessed from outside the loop. SmallPtrSet AllowedExit; /// This set holds the variables which are known to be uniform after /// vectorization. SmallPtrSet Uniforms; /// Can we assume the absence of NaNs. bool HasFunNoNaNAttr; /// Vectorization requirements that will go through late-evaluation. LoopVectorizationRequirements *Requirements; /// Used to emit an analysis of any legality issues. const LoopVectorizeHints *Hints; ValueToValueMap Strides; SmallPtrSet StrideSet; /// While vectorizing these instructions we have to generate a /// call to the appropriate masked intrinsic SmallPtrSet MaskedOp; }; /// LoopVectorizationCostModel - estimates the expected speedups due to /// vectorization. /// In many cases vectorization is not profitable. This can happen because of /// a number of reasons. In this class we mainly attempt to predict the /// expected speedup/slowdowns due to the supported instruction set. We use the /// TargetTransformInfo to query the different backends for the cost of /// different operations. class LoopVectorizationCostModel { public: - LoopVectorizationCostModel(Loop *L, PredicatedScalarEvolution &PSE, - LoopInfo *LI, LoopVectorizationLegality *Legal, + LoopVectorizationCostModel(Loop *L, ScalarEvolution *SE, LoopInfo *LI, + LoopVectorizationLegality *Legal, const TargetTransformInfo &TTI, const TargetLibraryInfo *TLI, DemandedBits *DB, AssumptionCache *AC, const Function *F, - const LoopVectorizeHints *Hints) - : TheLoop(L), PSE(PSE), LI(LI), Legal(Legal), TTI(TTI), TLI(TLI), DB(DB), - AC(AC), TheFunction(F), Hints(Hints) {} + const LoopVectorizeHints *Hints, + SmallPtrSetImpl &ValuesToIgnore) + : TheLoop(L), SE(SE), LI(LI), Legal(Legal), TTI(TTI), TLI(TLI), DB(DB), + TheFunction(F), Hints(Hints), ValuesToIgnore(ValuesToIgnore) {} /// Information about vectorization costs struct VectorizationFactor { unsigned Width; // Vector width with best cost unsigned Cost; // Cost of the loop with that width }; /// \return The most profitable vectorization factor and the cost of that VF. /// This method checks every power of two up to VF. If UserVF is not ZERO /// then this vectorization factor will be selected if vectorization is /// possible. VectorizationFactor selectVectorizationFactor(bool OptForSize); /// \return The size (in bits) of the smallest and widest types in the code /// that needs to be vectorized. We ignore values that remain scalar such as /// 64 bit loop indices. std::pair getSmallestAndWidestTypes(); /// \return The desired interleave count. /// If interleave count has been specified by metadata it will be returned. /// Otherwise, the interleave count is computed and returned. VF and LoopCost /// are the selected vectorization factor and the cost of the selected VF. unsigned selectInterleaveCount(bool OptForSize, unsigned VF, unsigned LoopCost); /// \return The most profitable unroll factor. /// This method finds the best unroll-factor based on register pressure and /// other parameters. VF and LoopCost are the selected vectorization factor /// and the cost of the selected VF. unsigned computeInterleaveCount(bool OptForSize, unsigned VF, unsigned LoopCost); /// \brief A struct that represents some properties of the register usage /// of a loop. struct RegisterUsage { /// Holds the number of loop invariant values that are used in the loop. unsigned LoopInvariantRegs; /// Holds the maximum number of concurrent live intervals in the loop. unsigned MaxLocalUsers; /// Holds the number of instructions in the loop. unsigned NumInstructions; }; /// \return Returns information about the register usages of the loop for the /// given vectorization factors. SmallVector calculateRegisterUsage(const SmallVector &VFs); - /// Collect values we want to ignore in the cost model. - void collectValuesToIgnore(); - private: /// Returns the expected execution cost. The unit of the cost does /// not matter because we use the 'cost' units to compare different /// vector widths. The cost that is returned is *not* normalized by /// the factor width. unsigned expectedCost(unsigned VF); /// Returns the execution time cost of an instruction for a given vector /// width. Vector width of one means scalar. unsigned getInstructionCost(Instruction *I, unsigned VF); /// Returns whether the instruction is a load or store and will be a emitted /// as a vector operation. bool isConsecutiveLoadOrStore(Instruction *I); /// Report an analysis message to assist the user in diagnosing loops that are /// not vectorized. These are handled as LoopAccessReport rather than /// VectorizationReport because the << operator of VectorizationReport returns /// LoopAccessReport. void emitAnalysis(const LoopAccessReport &Message) const { emitAnalysisDiag(TheFunction, TheLoop, *Hints, Message); } public: /// Map of scalar integer values to the smallest bitwidth they can be legally /// represented as. The vector equivalents of these values should be truncated /// to this type. MapVector MinBWs; /// The loop that we evaluate. Loop *TheLoop; - /// Predicated scalar evolution analysis. - PredicatedScalarEvolution &PSE; + /// Scev analysis. + ScalarEvolution *SE; /// Loop Info analysis. LoopInfo *LI; /// Vectorization legality. LoopVectorizationLegality *Legal; /// Vector target information. const TargetTransformInfo &TTI; /// Target Library Info. const TargetLibraryInfo *TLI; - /// Demanded bits analysis. + /// Demanded bits analysis DemandedBits *DB; - /// Assumption cache. - AssumptionCache *AC; const Function *TheFunction; - /// Loop Vectorize Hint. + // Loop Vectorize Hint. const LoopVectorizeHints *Hints; - /// Values to ignore in the cost model. - SmallPtrSet ValuesToIgnore; - /// Values to ignore in the cost model when VF > 1. - SmallPtrSet VecValuesToIgnore; + // Values to ignore in the cost model. + const SmallPtrSetImpl &ValuesToIgnore; }; /// \brief This holds vectorization requirements that must be verified late in /// the process. The requirements are set by legalize and costmodel. Once /// vectorization has been determined to be possible and profitable the /// requirements can be verified by looking for metadata or compiler options. /// For example, some loops require FP commutativity which is only allowed if /// vectorization is explicitly specified or if the fast-math compiler option /// has been provided. /// Late evaluation of these requirements allows helpful diagnostics to be /// composed that tells the user what need to be done to vectorize the loop. For /// example, by specifying #pragma clang loop vectorize or -ffast-math. Late /// evaluation should be used only when diagnostics can generated that can be /// followed by a non-expert user. class LoopVectorizationRequirements { public: LoopVectorizationRequirements() : NumRuntimePointerChecks(0), UnsafeAlgebraInst(nullptr) {} void addUnsafeAlgebraInst(Instruction *I) { // First unsafe algebra instruction. if (!UnsafeAlgebraInst) UnsafeAlgebraInst = I; } void addRuntimePointerChecks(unsigned Num) { NumRuntimePointerChecks = Num; } bool doesNotMeet(Function *F, Loop *L, const LoopVectorizeHints &Hints) { const char *Name = Hints.vectorizeAnalysisPassName(); bool Failed = false; if (UnsafeAlgebraInst && !Hints.allowReordering()) { emitOptimizationRemarkAnalysisFPCommute( F->getContext(), Name, *F, UnsafeAlgebraInst->getDebugLoc(), VectorizationReport() << "cannot prove it is safe to reorder " "floating-point operations"); Failed = true; } // Test if runtime memcheck thresholds are exceeded. bool PragmaThresholdReached = NumRuntimePointerChecks > PragmaVectorizeMemoryCheckThreshold; bool ThresholdReached = NumRuntimePointerChecks > VectorizerParams::RuntimeMemoryCheckThreshold; if ((ThresholdReached && !Hints.allowReordering()) || PragmaThresholdReached) { emitOptimizationRemarkAnalysisAliasing( F->getContext(), Name, *F, L->getStartLoc(), VectorizationReport() << "cannot prove it is safe to reorder memory operations"); DEBUG(dbgs() << "LV: Too many memory checks needed.\n"); Failed = true; } return Failed; } private: unsigned NumRuntimePointerChecks; Instruction *UnsafeAlgebraInst; }; static void addInnerLoop(Loop &L, SmallVectorImpl &V) { if (L.empty()) return V.push_back(&L); for (Loop *InnerL : L) addInnerLoop(*InnerL, V); } /// The LoopVectorize Pass. struct LoopVectorize : public FunctionPass { /// Pass identification, replacement for typeid static char ID; explicit LoopVectorize(bool NoUnrolling = false, bool AlwaysVectorize = true) : FunctionPass(ID), DisableUnrolling(NoUnrolling), AlwaysVectorize(AlwaysVectorize) { initializeLoopVectorizePass(*PassRegistry::getPassRegistry()); } ScalarEvolution *SE; LoopInfo *LI; TargetTransformInfo *TTI; DominatorTree *DT; BlockFrequencyInfo *BFI; TargetLibraryInfo *TLI; DemandedBits *DB; AliasAnalysis *AA; AssumptionCache *AC; LoopAccessAnalysis *LAA; bool DisableUnrolling; bool AlwaysVectorize; BlockFrequency ColdEntryFreq; bool runOnFunction(Function &F) override { SE = &getAnalysis().getSE(); LI = &getAnalysis().getLoopInfo(); TTI = &getAnalysis().getTTI(F); DT = &getAnalysis().getDomTree(); BFI = &getAnalysis().getBFI(); auto *TLIP = getAnalysisIfAvailable(); TLI = TLIP ? &TLIP->getTLI() : nullptr; AA = &getAnalysis().getAAResults(); AC = &getAnalysis().getAssumptionCache(F); LAA = &getAnalysis(); DB = &getAnalysis(); // Compute some weights outside of the loop over the loops. Compute this // using a BranchProbability to re-use its scaling math. const BranchProbability ColdProb(1, 5); // 20% ColdEntryFreq = BlockFrequency(BFI->getEntryFreq()) * ColdProb; // Don't attempt if // 1. the target claims to have no vector registers, and // 2. interleaving won't help ILP. // // The second condition is necessary because, even if the target has no // vector registers, loop vectorization may still enable scalar // interleaving. if (!TTI->getNumberOfRegisters(true) && TTI->getMaxInterleaveFactor(1) < 2) return false; // Build up a worklist of inner-loops to vectorize. This is necessary as // the act of vectorizing or partially unrolling a loop creates new loops // and can invalidate iterators across the loops. SmallVector Worklist; for (Loop *L : *LI) addInnerLoop(*L, Worklist); LoopsAnalyzed += Worklist.size(); // Now walk the identified inner loops. bool Changed = false; while (!Worklist.empty()) Changed |= processLoop(Worklist.pop_back_val()); // Process each loop nest in the function. return Changed; } static void AddRuntimeUnrollDisableMetaData(Loop *L) { SmallVector MDs; // Reserve first location for self reference to the LoopID metadata node. MDs.push_back(nullptr); bool IsUnrollMetadata = false; MDNode *LoopID = L->getLoopID(); if (LoopID) { // First find existing loop unrolling disable metadata. for (unsigned i = 1, ie = LoopID->getNumOperands(); i < ie; ++i) { MDNode *MD = dyn_cast(LoopID->getOperand(i)); if (MD) { const MDString *S = dyn_cast(MD->getOperand(0)); IsUnrollMetadata = S && S->getString().startswith("llvm.loop.unroll.disable"); } MDs.push_back(LoopID->getOperand(i)); } } if (!IsUnrollMetadata) { // Add runtime unroll disable metadata. LLVMContext &Context = L->getHeader()->getContext(); SmallVector DisableOperands; DisableOperands.push_back( MDString::get(Context, "llvm.loop.unroll.runtime.disable")); MDNode *DisableNode = MDNode::get(Context, DisableOperands); MDs.push_back(DisableNode); MDNode *NewLoopID = MDNode::get(Context, MDs); // Set operand 0 to refer to the loop id itself. NewLoopID->replaceOperandWith(0, NewLoopID); L->setLoopID(NewLoopID); } } bool processLoop(Loop *L) { assert(L->empty() && "Only process inner loops."); #ifndef NDEBUG const std::string DebugLocStr = getDebugLocString(L); #endif /* NDEBUG */ DEBUG(dbgs() << "\nLV: Checking a loop in \"" << L->getHeader()->getParent()->getName() << "\" from " << DebugLocStr << "\n"); LoopVectorizeHints Hints(L, DisableUnrolling); DEBUG(dbgs() << "LV: Loop hints:" << " force=" << (Hints.getForce() == LoopVectorizeHints::FK_Disabled ? "disabled" : (Hints.getForce() == LoopVectorizeHints::FK_Enabled ? "enabled" : "?")) << " width=" << Hints.getWidth() << " unroll=" << Hints.getInterleave() << "\n"); // Function containing loop Function *F = L->getHeader()->getParent(); // Looking at the diagnostic output is the only way to determine if a loop // was vectorized (other than looking at the IR or machine code), so it // is important to generate an optimization remark for each loop. Most of // these messages are generated by emitOptimizationRemarkAnalysis. Remarks // generated by emitOptimizationRemark and emitOptimizationRemarkMissed are // less verbose reporting vectorized loops and unvectorized loops that may // benefit from vectorization, respectively. if (!Hints.allowVectorization(F, L, AlwaysVectorize)) { DEBUG(dbgs() << "LV: Loop hints prevent vectorization.\n"); return false; } // Check the loop for a trip count threshold: // do not vectorize loops with a tiny trip count. const unsigned TC = SE->getSmallConstantTripCount(L); if (TC > 0u && TC < TinyTripCountVectorThreshold) { DEBUG(dbgs() << "LV: Found a loop with a very small trip count. " << "This loop is not worth vectorizing."); if (Hints.getForce() == LoopVectorizeHints::FK_Enabled) DEBUG(dbgs() << " But vectorizing was explicitly forced.\n"); else { DEBUG(dbgs() << "\n"); emitAnalysisDiag(F, L, Hints, VectorizationReport() << "vectorization is not beneficial " "and is not explicitly forced"); return false; } } PredicatedScalarEvolution PSE(*SE); // Check if it is legal to vectorize the loop. LoopVectorizationRequirements Requirements; LoopVectorizationLegality LVL(L, PSE, DT, TLI, AA, F, TTI, LAA, &Requirements, &Hints); if (!LVL.canVectorize()) { DEBUG(dbgs() << "LV: Not vectorizing: Cannot prove legality.\n"); emitMissedWarning(F, L, Hints); return false; } + // Collect values we want to ignore in the cost model. This includes + // type-promoting instructions we identified during reduction detection. + SmallPtrSet ValuesToIgnore; + CodeMetrics::collectEphemeralValues(L, AC, ValuesToIgnore); + for (auto &Reduction : *LVL.getReductionVars()) { + RecurrenceDescriptor &RedDes = Reduction.second; + SmallPtrSetImpl &Casts = RedDes.getCastInsts(); + ValuesToIgnore.insert(Casts.begin(), Casts.end()); + } + // Use the cost model. - LoopVectorizationCostModel CM(L, PSE, LI, &LVL, *TTI, TLI, DB, AC, F, - &Hints); - CM.collectValuesToIgnore(); + LoopVectorizationCostModel CM(L, PSE.getSE(), LI, &LVL, *TTI, TLI, DB, AC, + F, &Hints, ValuesToIgnore); // Check the function attributes to find out if this function should be // optimized for size. bool OptForSize = Hints.getForce() != LoopVectorizeHints::FK_Enabled && F->optForSize(); // Compute the weighted frequency of this loop being executed and see if it // is less than 20% of the function entry baseline frequency. Note that we // always have a canonical loop here because we think we *can* vectorize. // FIXME: This is hidden behind a flag due to pervasive problems with // exactly what block frequency models. if (LoopVectorizeWithBlockFrequency) { BlockFrequency LoopEntryFreq = BFI->getBlockFreq(L->getLoopPreheader()); if (Hints.getForce() != LoopVectorizeHints::FK_Enabled && LoopEntryFreq < ColdEntryFreq) OptForSize = true; } // Check the function attributes to see if implicit floats are allowed. // FIXME: This check doesn't seem possibly correct -- what if the loop is // an integer loop and the vector instructions selected are purely integer // vector instructions? if (F->hasFnAttribute(Attribute::NoImplicitFloat)) { DEBUG(dbgs() << "LV: Can't vectorize when the NoImplicitFloat" "attribute is used.\n"); emitAnalysisDiag( F, L, Hints, VectorizationReport() << "loop not vectorized due to NoImplicitFloat attribute"); emitMissedWarning(F, L, Hints); return false; } // Select the optimal vectorization factor. const LoopVectorizationCostModel::VectorizationFactor VF = CM.selectVectorizationFactor(OptForSize); // Select the interleave count. unsigned IC = CM.selectInterleaveCount(OptForSize, VF.Width, VF.Cost); // Get user interleave count. unsigned UserIC = Hints.getInterleave(); // Identify the diagnostic messages that should be produced. std::string VecDiagMsg, IntDiagMsg; bool VectorizeLoop = true, InterleaveLoop = true; if (Requirements.doesNotMeet(F, L, Hints)) { DEBUG(dbgs() << "LV: Not vectorizing: loop did not meet vectorization " "requirements.\n"); emitMissedWarning(F, L, Hints); return false; } if (VF.Width == 1) { DEBUG(dbgs() << "LV: Vectorization is possible but not beneficial.\n"); VecDiagMsg = "the cost-model indicates that vectorization is not beneficial"; VectorizeLoop = false; } if (IC == 1 && UserIC <= 1) { // Tell the user interleaving is not beneficial. DEBUG(dbgs() << "LV: Interleaving is not beneficial.\n"); IntDiagMsg = "the cost-model indicates that interleaving is not beneficial"; InterleaveLoop = false; if (UserIC == 1) IntDiagMsg += " and is explicitly disabled or interleave count is set to 1"; } else if (IC > 1 && UserIC == 1) { // Tell the user interleaving is beneficial, but it explicitly disabled. DEBUG(dbgs() << "LV: Interleaving is beneficial but is explicitly disabled."); IntDiagMsg = "the cost-model indicates that interleaving is beneficial " "but is explicitly disabled or interleave count is set to 1"; InterleaveLoop = false; } // Override IC if user provided an interleave count. IC = UserIC > 0 ? UserIC : IC; // Emit diagnostic messages, if any. const char *VAPassName = Hints.vectorizeAnalysisPassName(); if (!VectorizeLoop && !InterleaveLoop) { // Do not vectorize or interleaving the loop. emitOptimizationRemarkAnalysis(F->getContext(), VAPassName, *F, L->getStartLoc(), VecDiagMsg); emitOptimizationRemarkAnalysis(F->getContext(), LV_NAME, *F, L->getStartLoc(), IntDiagMsg); return false; } else if (!VectorizeLoop && InterleaveLoop) { DEBUG(dbgs() << "LV: Interleave Count is " << IC << '\n'); emitOptimizationRemarkAnalysis(F->getContext(), VAPassName, *F, L->getStartLoc(), VecDiagMsg); } else if (VectorizeLoop && !InterleaveLoop) { DEBUG(dbgs() << "LV: Found a vectorizable loop (" << VF.Width << ") in " << DebugLocStr << '\n'); emitOptimizationRemarkAnalysis(F->getContext(), LV_NAME, *F, L->getStartLoc(), IntDiagMsg); } else if (VectorizeLoop && InterleaveLoop) { DEBUG(dbgs() << "LV: Found a vectorizable loop (" << VF.Width << ") in " << DebugLocStr << '\n'); DEBUG(dbgs() << "LV: Interleave Count is " << IC << '\n'); } if (!VectorizeLoop) { assert(IC > 1 && "interleave count should not be 1 or 0"); // If we decided that it is not legal to vectorize the loop then // interleave it. InnerLoopUnroller Unroller(L, PSE, LI, DT, TLI, TTI, IC); Unroller.vectorize(&LVL, CM.MinBWs); emitOptimizationRemark(F->getContext(), LV_NAME, *F, L->getStartLoc(), Twine("interleaved loop (interleaved count: ") + Twine(IC) + ")"); } else { // If we decided that it is *legal* to vectorize the loop then do it. InnerLoopVectorizer LB(L, PSE, LI, DT, TLI, TTI, VF.Width, IC); LB.vectorize(&LVL, CM.MinBWs); ++LoopsVectorized; // Add metadata to disable runtime unrolling scalar loop when there's no // runtime check about strides and memory. Because at this situation, // scalar loop is rarely used not worthy to be unrolled. if (!LB.IsSafetyChecksAdded()) AddRuntimeUnrollDisableMetaData(L); // Report the vectorization decision. emitOptimizationRemark(F->getContext(), LV_NAME, *F, L->getStartLoc(), Twine("vectorized loop (vectorization width: ") + Twine(VF.Width) + ", interleaved count: " + Twine(IC) + ")"); } // Mark the loop as already vectorized to avoid vectorizing again. Hints.setAlreadyVectorized(); DEBUG(verifyFunction(*L->getHeader()->getParent())); return true; } void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired(); AU.addRequiredID(LoopSimplifyID); AU.addRequiredID(LCSSAID); AU.addRequired(); AU.addRequired(); AU.addRequired(); AU.addRequired(); AU.addRequired(); AU.addRequired(); AU.addRequired(); AU.addRequired(); AU.addPreserved(); AU.addPreserved(); AU.addPreserved(); AU.addPreserved(); AU.addPreserved(); } }; } // end anonymous namespace //===----------------------------------------------------------------------===// // Implementation of LoopVectorizationLegality, InnerLoopVectorizer and // LoopVectorizationCostModel. //===----------------------------------------------------------------------===// Value *InnerLoopVectorizer::getBroadcastInstrs(Value *V) { // We need to place the broadcast of invariant variables outside the loop. Instruction *Instr = dyn_cast(V); bool NewInstr = (Instr && std::find(LoopVectorBody.begin(), LoopVectorBody.end(), Instr->getParent()) != LoopVectorBody.end()); bool Invariant = OrigLoop->isLoopInvariant(V) && !NewInstr; // Place the code for broadcasting invariant variables in the new preheader. IRBuilder<>::InsertPointGuard Guard(Builder); if (Invariant) Builder.SetInsertPoint(LoopVectorPreHeader->getTerminator()); // Broadcast the scalar into all locations in the vector. Value *Shuf = Builder.CreateVectorSplat(VF, V, "broadcast"); return Shuf; } Value *InnerLoopVectorizer::getStepVector(Value *Val, int StartIdx, Value *Step) { assert(Val->getType()->isVectorTy() && "Must be a vector"); assert(Val->getType()->getScalarType()->isIntegerTy() && "Elem must be an integer"); assert(Step->getType() == Val->getType()->getScalarType() && "Step has wrong type"); // Create the types. Type *ITy = Val->getType()->getScalarType(); VectorType *Ty = cast(Val->getType()); int VLen = Ty->getNumElements(); SmallVector Indices; // Create a vector of consecutive numbers from zero to VF. for (int i = 0; i < VLen; ++i) Indices.push_back(ConstantInt::get(ITy, StartIdx + i)); // Add the consecutive indices to the vector value. Constant *Cv = ConstantVector::get(Indices); assert(Cv->getType() == Val->getType() && "Invalid consecutive vec"); Step = Builder.CreateVectorSplat(VLen, Step); assert(Step->getType() == Val->getType() && "Invalid step vec"); // FIXME: The newly created binary instructions should contain nsw/nuw flags, // which can be found from the original scalar operations. Step = Builder.CreateMul(Cv, Step); return Builder.CreateAdd(Val, Step, "induction"); } int LoopVectorizationLegality::isConsecutivePtr(Value *Ptr) { assert(Ptr->getType()->isPointerTy() && "Unexpected non-ptr"); auto *SE = PSE.getSE(); // Make sure that the pointer does not point to structs. if (Ptr->getType()->getPointerElementType()->isAggregateType()) return 0; // If this value is a pointer induction variable we know it is consecutive. PHINode *Phi = dyn_cast_or_null(Ptr); if (Phi && Inductions.count(Phi)) { InductionDescriptor II = Inductions[Phi]; return II.getConsecutiveDirection(); } GetElementPtrInst *Gep = getGEPInstruction(Ptr); if (!Gep) return 0; unsigned NumOperands = Gep->getNumOperands(); Value *GpPtr = Gep->getPointerOperand(); // If this GEP value is a consecutive pointer induction variable and all of // the indices are constant then we know it is consecutive. We can Phi = dyn_cast(GpPtr); if (Phi && Inductions.count(Phi)) { // Make sure that the pointer does not point to structs. PointerType *GepPtrType = cast(GpPtr->getType()); if (GepPtrType->getElementType()->isAggregateType()) return 0; // Make sure that all of the index operands are loop invariant. for (unsigned i = 1; i < NumOperands; ++i) if (!SE->isLoopInvariant(PSE.getSCEV(Gep->getOperand(i)), TheLoop)) return 0; InductionDescriptor II = Inductions[Phi]; return II.getConsecutiveDirection(); } unsigned InductionOperand = getGEPInductionOperand(Gep); // Check that all of the gep indices are uniform except for our induction // operand. for (unsigned i = 0; i != NumOperands; ++i) if (i != InductionOperand && !SE->isLoopInvariant(PSE.getSCEV(Gep->getOperand(i)), TheLoop)) return 0; // We can emit wide load/stores only if the last non-zero index is the // induction variable. const SCEV *Last = nullptr; if (!Strides.count(Gep)) Last = PSE.getSCEV(Gep->getOperand(InductionOperand)); else { // Because of the multiplication by a stride we can have a s/zext cast. // We are going to replace this stride by 1 so the cast is safe to ignore. // // %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] // %0 = trunc i64 %indvars.iv to i32 // %mul = mul i32 %0, %Stride1 // %idxprom = zext i32 %mul to i64 << Safe cast. // %arrayidx = getelementptr inbounds i32* %B, i64 %idxprom // Last = replaceSymbolicStrideSCEV(PSE, Strides, Gep->getOperand(InductionOperand), Gep); if (const SCEVCastExpr *C = dyn_cast(Last)) Last = (C->getSCEVType() == scSignExtend || C->getSCEVType() == scZeroExtend) ? C->getOperand() : Last; } if (const SCEVAddRecExpr *AR = dyn_cast(Last)) { const SCEV *Step = AR->getStepRecurrence(*SE); // The memory is consecutive because the last index is consecutive // and all other indices are loop invariant. if (Step->isOne()) return 1; if (Step->isAllOnesValue()) return -1; } return 0; } bool LoopVectorizationLegality::isUniform(Value *V) { return LAI->isUniform(V); } InnerLoopVectorizer::VectorParts& InnerLoopVectorizer::getVectorValue(Value *V) { assert(V != Induction && "The new induction variable should not be used."); assert(!V->getType()->isVectorTy() && "Can't widen a vector"); // If we have a stride that is replaced by one, do it here. if (Legal->hasStride(V)) V = ConstantInt::get(V->getType(), 1); // If we have this scalar in the map, return it. if (WidenMap.has(V)) return WidenMap.get(V); // If this scalar is unknown, assume that it is a constant or that it is // loop invariant. Broadcast V and save the value for future uses. Value *B = getBroadcastInstrs(V); return WidenMap.splat(V, B); } Value *InnerLoopVectorizer::reverseVector(Value *Vec) { assert(Vec->getType()->isVectorTy() && "Invalid type"); SmallVector ShuffleMask; for (unsigned i = 0; i < VF; ++i) ShuffleMask.push_back(Builder.getInt32(VF - i - 1)); return Builder.CreateShuffleVector(Vec, UndefValue::get(Vec->getType()), ConstantVector::get(ShuffleMask), "reverse"); } // Get a mask to interleave \p NumVec vectors into a wide vector. // I.e. <0, VF, VF*2, ..., VF*(NumVec-1), 1, VF+1, VF*2+1, ...> // E.g. For 2 interleaved vectors, if VF is 4, the mask is: // <0, 4, 1, 5, 2, 6, 3, 7> static Constant *getInterleavedMask(IRBuilder<> &Builder, unsigned VF, unsigned NumVec) { SmallVector Mask; for (unsigned i = 0; i < VF; i++) for (unsigned j = 0; j < NumVec; j++) Mask.push_back(Builder.getInt32(j * VF + i)); return ConstantVector::get(Mask); } // Get the strided mask starting from index \p Start. // I.e. static Constant *getStridedMask(IRBuilder<> &Builder, unsigned Start, unsigned Stride, unsigned VF) { SmallVector Mask; for (unsigned i = 0; i < VF; i++) Mask.push_back(Builder.getInt32(Start + i * Stride)); return ConstantVector::get(Mask); } // Get a mask of two parts: The first part consists of sequential integers // starting from 0, The second part consists of UNDEFs. // I.e. <0, 1, 2, ..., NumInt - 1, undef, ..., undef> static Constant *getSequentialMask(IRBuilder<> &Builder, unsigned NumInt, unsigned NumUndef) { SmallVector Mask; for (unsigned i = 0; i < NumInt; i++) Mask.push_back(Builder.getInt32(i)); Constant *Undef = UndefValue::get(Builder.getInt32Ty()); for (unsigned i = 0; i < NumUndef; i++) Mask.push_back(Undef); return ConstantVector::get(Mask); } // Concatenate two vectors with the same element type. The 2nd vector should // not have more elements than the 1st vector. If the 2nd vector has less // elements, extend it with UNDEFs. static Value *ConcatenateTwoVectors(IRBuilder<> &Builder, Value *V1, Value *V2) { VectorType *VecTy1 = dyn_cast(V1->getType()); VectorType *VecTy2 = dyn_cast(V2->getType()); assert(VecTy1 && VecTy2 && VecTy1->getScalarType() == VecTy2->getScalarType() && "Expect two vectors with the same element type"); unsigned NumElts1 = VecTy1->getNumElements(); unsigned NumElts2 = VecTy2->getNumElements(); assert(NumElts1 >= NumElts2 && "Unexpect the first vector has less elements"); if (NumElts1 > NumElts2) { // Extend with UNDEFs. Constant *ExtMask = getSequentialMask(Builder, NumElts2, NumElts1 - NumElts2); V2 = Builder.CreateShuffleVector(V2, UndefValue::get(VecTy2), ExtMask); } Constant *Mask = getSequentialMask(Builder, NumElts1 + NumElts2, 0); return Builder.CreateShuffleVector(V1, V2, Mask); } // Concatenate vectors in the given list. All vectors have the same type. static Value *ConcatenateVectors(IRBuilder<> &Builder, ArrayRef InputList) { unsigned NumVec = InputList.size(); assert(NumVec > 1 && "Should be at least two vectors"); SmallVector ResList; ResList.append(InputList.begin(), InputList.end()); do { SmallVector TmpList; for (unsigned i = 0; i < NumVec - 1; i += 2) { Value *V0 = ResList[i], *V1 = ResList[i + 1]; assert((V0->getType() == V1->getType() || i == NumVec - 2) && "Only the last vector may have a different type"); TmpList.push_back(ConcatenateTwoVectors(Builder, V0, V1)); } // Push the last vector if the total number of vectors is odd. if (NumVec % 2 != 0) TmpList.push_back(ResList[NumVec - 1]); ResList = TmpList; NumVec = ResList.size(); } while (NumVec > 1); return ResList[0]; } // Try to vectorize the interleave group that \p Instr belongs to. // // E.g. Translate following interleaved load group (factor = 3): // for (i = 0; i < N; i+=3) { // R = Pic[i]; // Member of index 0 // G = Pic[i+1]; // Member of index 1 // B = Pic[i+2]; // Member of index 2 // ... // do something to R, G, B // } // To: // %wide.vec = load <12 x i32> ; Read 4 tuples of R,G,B // %R.vec = shuffle %wide.vec, undef, <0, 3, 6, 9> ; R elements // %G.vec = shuffle %wide.vec, undef, <1, 4, 7, 10> ; G elements // %B.vec = shuffle %wide.vec, undef, <2, 5, 8, 11> ; B elements // // Or translate following interleaved store group (factor = 3): // for (i = 0; i < N; i+=3) { // ... do something to R, G, B // Pic[i] = R; // Member of index 0 // Pic[i+1] = G; // Member of index 1 // Pic[i+2] = B; // Member of index 2 // } // To: // %R_G.vec = shuffle %R.vec, %G.vec, <0, 1, 2, ..., 7> // %B_U.vec = shuffle %B.vec, undef, <0, 1, 2, 3, u, u, u, u> // %interleaved.vec = shuffle %R_G.vec, %B_U.vec, // <0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11> ; Interleave R,G,B elements // store <12 x i32> %interleaved.vec ; Write 4 tuples of R,G,B void InnerLoopVectorizer::vectorizeInterleaveGroup(Instruction *Instr) { const InterleaveGroup *Group = Legal->getInterleavedAccessGroup(Instr); assert(Group && "Fail to get an interleaved access group."); // Skip if current instruction is not the insert position. if (Instr != Group->getInsertPos()) return; LoadInst *LI = dyn_cast(Instr); StoreInst *SI = dyn_cast(Instr); Value *Ptr = LI ? LI->getPointerOperand() : SI->getPointerOperand(); // Prepare for the vector type of the interleaved load/store. Type *ScalarTy = LI ? LI->getType() : SI->getValueOperand()->getType(); unsigned InterleaveFactor = Group->getFactor(); Type *VecTy = VectorType::get(ScalarTy, InterleaveFactor * VF); Type *PtrTy = VecTy->getPointerTo(Ptr->getType()->getPointerAddressSpace()); // Prepare for the new pointers. setDebugLocFromInst(Builder, Ptr); VectorParts &PtrParts = getVectorValue(Ptr); SmallVector NewPtrs; unsigned Index = Group->getIndex(Instr); for (unsigned Part = 0; Part < UF; Part++) { // Extract the pointer for current instruction from the pointer vector. A // reverse access uses the pointer in the last lane. Value *NewPtr = Builder.CreateExtractElement( PtrParts[Part], Group->isReverse() ? Builder.getInt32(VF - 1) : Builder.getInt32(0)); // Notice current instruction could be any index. Need to adjust the address // to the member of index 0. // // E.g. a = A[i+1]; // Member of index 1 (Current instruction) // b = A[i]; // Member of index 0 // Current pointer is pointed to A[i+1], adjust it to A[i]. // // E.g. A[i+1] = a; // Member of index 1 // A[i] = b; // Member of index 0 // A[i+2] = c; // Member of index 2 (Current instruction) // Current pointer is pointed to A[i+2], adjust it to A[i]. NewPtr = Builder.CreateGEP(NewPtr, Builder.getInt32(-Index)); // Cast to the vector pointer type. NewPtrs.push_back(Builder.CreateBitCast(NewPtr, PtrTy)); } setDebugLocFromInst(Builder, Instr); Value *UndefVec = UndefValue::get(VecTy); // Vectorize the interleaved load group. if (LI) { for (unsigned Part = 0; Part < UF; Part++) { Instruction *NewLoadInstr = Builder.CreateAlignedLoad( NewPtrs[Part], Group->getAlignment(), "wide.vec"); for (unsigned i = 0; i < InterleaveFactor; i++) { Instruction *Member = Group->getMember(i); // Skip the gaps in the group. if (!Member) continue; Constant *StrideMask = getStridedMask(Builder, i, InterleaveFactor, VF); Value *StridedVec = Builder.CreateShuffleVector( NewLoadInstr, UndefVec, StrideMask, "strided.vec"); // If this member has different type, cast the result type. if (Member->getType() != ScalarTy) { VectorType *OtherVTy = VectorType::get(Member->getType(), VF); StridedVec = Builder.CreateBitOrPointerCast(StridedVec, OtherVTy); } VectorParts &Entry = WidenMap.get(Member); Entry[Part] = Group->isReverse() ? reverseVector(StridedVec) : StridedVec; } propagateMetadata(NewLoadInstr, Instr); } return; } // The sub vector type for current instruction. VectorType *SubVT = VectorType::get(ScalarTy, VF); // Vectorize the interleaved store group. for (unsigned Part = 0; Part < UF; Part++) { // Collect the stored vector from each member. SmallVector StoredVecs; for (unsigned i = 0; i < InterleaveFactor; i++) { // Interleaved store group doesn't allow a gap, so each index has a member Instruction *Member = Group->getMember(i); assert(Member && "Fail to get a member from an interleaved store group"); Value *StoredVec = getVectorValue(dyn_cast(Member)->getValueOperand())[Part]; if (Group->isReverse()) StoredVec = reverseVector(StoredVec); // If this member has different type, cast it to an unified type. if (StoredVec->getType() != SubVT) StoredVec = Builder.CreateBitOrPointerCast(StoredVec, SubVT); StoredVecs.push_back(StoredVec); } // Concatenate all vectors into a wide vector. Value *WideVec = ConcatenateVectors(Builder, StoredVecs); // Interleave the elements in the wide vector. Constant *IMask = getInterleavedMask(Builder, VF, InterleaveFactor); Value *IVec = Builder.CreateShuffleVector(WideVec, UndefVec, IMask, "interleaved.vec"); Instruction *NewStoreInstr = Builder.CreateAlignedStore(IVec, NewPtrs[Part], Group->getAlignment()); propagateMetadata(NewStoreInstr, Instr); } } void InnerLoopVectorizer::vectorizeMemoryInstruction(Instruction *Instr) { // Attempt to issue a wide load. LoadInst *LI = dyn_cast(Instr); StoreInst *SI = dyn_cast(Instr); assert((LI || SI) && "Invalid Load/Store instruction"); // Try to vectorize the interleave group if this access is interleaved. if (Legal->isAccessInterleaved(Instr)) return vectorizeInterleaveGroup(Instr); Type *ScalarDataTy = LI ? LI->getType() : SI->getValueOperand()->getType(); Type *DataTy = VectorType::get(ScalarDataTy, VF); Value *Ptr = LI ? LI->getPointerOperand() : SI->getPointerOperand(); unsigned Alignment = LI ? LI->getAlignment() : SI->getAlignment(); // An alignment of 0 means target abi alignment. We need to use the scalar's // target abi alignment in such a case. const DataLayout &DL = Instr->getModule()->getDataLayout(); if (!Alignment) Alignment = DL.getABITypeAlignment(ScalarDataTy); unsigned AddressSpace = Ptr->getType()->getPointerAddressSpace(); unsigned ScalarAllocatedSize = DL.getTypeAllocSize(ScalarDataTy); unsigned VectorElementSize = DL.getTypeStoreSize(DataTy) / VF; if (SI && Legal->blockNeedsPredication(SI->getParent()) && !Legal->isMaskRequired(SI)) return scalarizeInstruction(Instr, true); if (ScalarAllocatedSize != VectorElementSize) return scalarizeInstruction(Instr); // If the pointer is loop invariant or if it is non-consecutive, // scalarize the load. int ConsecutiveStride = Legal->isConsecutivePtr(Ptr); bool Reverse = ConsecutiveStride < 0; bool UniformLoad = LI && Legal->isUniform(Ptr); if (!ConsecutiveStride || UniformLoad) return scalarizeInstruction(Instr); Constant *Zero = Builder.getInt32(0); VectorParts &Entry = WidenMap.get(Instr); // Handle consecutive loads/stores. GetElementPtrInst *Gep = getGEPInstruction(Ptr); if (Gep && Legal->isInductionVariable(Gep->getPointerOperand())) { setDebugLocFromInst(Builder, Gep); Value *PtrOperand = Gep->getPointerOperand(); Value *FirstBasePtr = getVectorValue(PtrOperand)[0]; FirstBasePtr = Builder.CreateExtractElement(FirstBasePtr, Zero); // Create the new GEP with the new induction variable. GetElementPtrInst *Gep2 = cast(Gep->clone()); Gep2->setOperand(0, FirstBasePtr); Gep2->setName("gep.indvar.base"); Ptr = Builder.Insert(Gep2); } else if (Gep) { setDebugLocFromInst(Builder, Gep); assert(PSE.getSE()->isLoopInvariant(PSE.getSCEV(Gep->getPointerOperand()), OrigLoop) && "Base ptr must be invariant"); // The last index does not have to be the induction. It can be // consecutive and be a function of the index. For example A[I+1]; unsigned NumOperands = Gep->getNumOperands(); unsigned InductionOperand = getGEPInductionOperand(Gep); // Create the new GEP with the new induction variable. GetElementPtrInst *Gep2 = cast(Gep->clone()); for (unsigned i = 0; i < NumOperands; ++i) { Value *GepOperand = Gep->getOperand(i); Instruction *GepOperandInst = dyn_cast(GepOperand); // Update last index or loop invariant instruction anchored in loop. if (i == InductionOperand || (GepOperandInst && OrigLoop->contains(GepOperandInst))) { assert((i == InductionOperand || PSE.getSE()->isLoopInvariant(PSE.getSCEV(GepOperandInst), OrigLoop)) && "Must be last index or loop invariant"); VectorParts &GEPParts = getVectorValue(GepOperand); Value *Index = GEPParts[0]; Index = Builder.CreateExtractElement(Index, Zero); Gep2->setOperand(i, Index); Gep2->setName("gep.indvar.idx"); } } Ptr = Builder.Insert(Gep2); } else { // Use the induction element ptr. assert(isa(Ptr) && "Invalid induction ptr"); setDebugLocFromInst(Builder, Ptr); VectorParts &PtrVal = getVectorValue(Ptr); Ptr = Builder.CreateExtractElement(PtrVal[0], Zero); } VectorParts Mask = createBlockInMask(Instr->getParent()); // Handle Stores: if (SI) { assert(!Legal->isUniform(SI->getPointerOperand()) && "We do not allow storing to uniform addresses"); setDebugLocFromInst(Builder, SI); // We don't want to update the value in the map as it might be used in // another expression. So don't use a reference type for "StoredVal". VectorParts StoredVal = getVectorValue(SI->getValueOperand()); for (unsigned Part = 0; Part < UF; ++Part) { // Calculate the pointer for the specific unroll-part. Value *PartPtr = Builder.CreateGEP(nullptr, Ptr, Builder.getInt32(Part * VF)); if (Reverse) { // If we store to reverse consecutive memory locations, then we need // to reverse the order of elements in the stored value. StoredVal[Part] = reverseVector(StoredVal[Part]); // If the address is consecutive but reversed, then the // wide store needs to start at the last vector element. PartPtr = Builder.CreateGEP(nullptr, Ptr, Builder.getInt32(-Part * VF)); PartPtr = Builder.CreateGEP(nullptr, PartPtr, Builder.getInt32(1 - VF)); Mask[Part] = reverseVector(Mask[Part]); } Value *VecPtr = Builder.CreateBitCast(PartPtr, DataTy->getPointerTo(AddressSpace)); Instruction *NewSI; if (Legal->isMaskRequired(SI)) NewSI = Builder.CreateMaskedStore(StoredVal[Part], VecPtr, Alignment, Mask[Part]); else NewSI = Builder.CreateAlignedStore(StoredVal[Part], VecPtr, Alignment); propagateMetadata(NewSI, SI); } return; } // Handle loads. assert(LI && "Must have a load instruction"); setDebugLocFromInst(Builder, LI); for (unsigned Part = 0; Part < UF; ++Part) { // Calculate the pointer for the specific unroll-part. Value *PartPtr = Builder.CreateGEP(nullptr, Ptr, Builder.getInt32(Part * VF)); if (Reverse) { // If the address is consecutive but reversed, then the // wide load needs to start at the last vector element. PartPtr = Builder.CreateGEP(nullptr, Ptr, Builder.getInt32(-Part * VF)); PartPtr = Builder.CreateGEP(nullptr, PartPtr, Builder.getInt32(1 - VF)); Mask[Part] = reverseVector(Mask[Part]); } Instruction* NewLI; Value *VecPtr = Builder.CreateBitCast(PartPtr, DataTy->getPointerTo(AddressSpace)); if (Legal->isMaskRequired(LI)) NewLI = Builder.CreateMaskedLoad(VecPtr, Alignment, Mask[Part], UndefValue::get(DataTy), "wide.masked.load"); else NewLI = Builder.CreateAlignedLoad(VecPtr, Alignment, "wide.load"); propagateMetadata(NewLI, LI); Entry[Part] = Reverse ? reverseVector(NewLI) : NewLI; } } void InnerLoopVectorizer::scalarizeInstruction(Instruction *Instr, bool IfPredicateStore) { assert(!Instr->getType()->isAggregateType() && "Can't handle vectors"); // Holds vector parameters or scalars, in case of uniform vals. SmallVector Params; setDebugLocFromInst(Builder, Instr); // Find all of the vectorized parameters. for (unsigned op = 0, e = Instr->getNumOperands(); op != e; ++op) { Value *SrcOp = Instr->getOperand(op); // If we are accessing the old induction variable, use the new one. if (SrcOp == OldInduction) { Params.push_back(getVectorValue(SrcOp)); continue; } // Try using previously calculated values. Instruction *SrcInst = dyn_cast(SrcOp); // If the src is an instruction that appeared earlier in the basic block, // then it should already be vectorized. if (SrcInst && OrigLoop->contains(SrcInst)) { assert(WidenMap.has(SrcInst) && "Source operand is unavailable"); // The parameter is a vector value from earlier. Params.push_back(WidenMap.get(SrcInst)); } else { // The parameter is a scalar from outside the loop. Maybe even a constant. VectorParts Scalars; Scalars.append(UF, SrcOp); Params.push_back(Scalars); } } assert(Params.size() == Instr->getNumOperands() && "Invalid number of operands"); // Does this instruction return a value ? bool IsVoidRetTy = Instr->getType()->isVoidTy(); Value *UndefVec = IsVoidRetTy ? nullptr : UndefValue::get(VectorType::get(Instr->getType(), VF)); // Create a new entry in the WidenMap and initialize it to Undef or Null. VectorParts &VecResults = WidenMap.splat(Instr, UndefVec); VectorParts Cond; if (IfPredicateStore) { assert(Instr->getParent()->getSinglePredecessor() && "Only support single predecessor blocks"); Cond = createEdgeMask(Instr->getParent()->getSinglePredecessor(), Instr->getParent()); } // For each vector unroll 'part': for (unsigned Part = 0; Part < UF; ++Part) { // For each scalar that we create: for (unsigned Width = 0; Width < VF; ++Width) { // Start if-block. Value *Cmp = nullptr; if (IfPredicateStore) { Cmp = Builder.CreateExtractElement(Cond[Part], Builder.getInt32(Width)); Cmp = Builder.CreateICmp(ICmpInst::ICMP_EQ, Cmp, ConstantInt::get(Cmp->getType(), 1)); } Instruction *Cloned = Instr->clone(); if (!IsVoidRetTy) Cloned->setName(Instr->getName() + ".cloned"); // Replace the operands of the cloned instructions with extracted scalars. for (unsigned op = 0, e = Instr->getNumOperands(); op != e; ++op) { Value *Op = Params[op][Part]; // Param is a vector. Need to extract the right lane. if (Op->getType()->isVectorTy()) Op = Builder.CreateExtractElement(Op, Builder.getInt32(Width)); Cloned->setOperand(op, Op); } // Place the cloned scalar in the new loop. Builder.Insert(Cloned); // If the original scalar returns a value we need to place it in a vector // so that future users will be able to use it. if (!IsVoidRetTy) VecResults[Part] = Builder.CreateInsertElement(VecResults[Part], Cloned, Builder.getInt32(Width)); // End if-block. if (IfPredicateStore) PredicatedStores.push_back(std::make_pair(cast(Cloned), Cmp)); } } } PHINode *InnerLoopVectorizer::createInductionVariable(Loop *L, Value *Start, Value *End, Value *Step, Instruction *DL) { BasicBlock *Header = L->getHeader(); BasicBlock *Latch = L->getLoopLatch(); // As we're just creating this loop, it's possible no latch exists // yet. If so, use the header as this will be a single block loop. if (!Latch) Latch = Header; IRBuilder<> Builder(&*Header->getFirstInsertionPt()); setDebugLocFromInst(Builder, getDebugLocFromInstOrOperands(OldInduction)); auto *Induction = Builder.CreatePHI(Start->getType(), 2, "index"); Builder.SetInsertPoint(Latch->getTerminator()); // Create i+1 and fill the PHINode. Value *Next = Builder.CreateAdd(Induction, Step, "index.next"); Induction->addIncoming(Start, L->getLoopPreheader()); Induction->addIncoming(Next, Latch); // Create the compare. Value *ICmp = Builder.CreateICmpEQ(Next, End); Builder.CreateCondBr(ICmp, L->getExitBlock(), Header); // Now we have two terminators. Remove the old one from the block. Latch->getTerminator()->eraseFromParent(); return Induction; } Value *InnerLoopVectorizer::getOrCreateTripCount(Loop *L) { if (TripCount) return TripCount; IRBuilder<> Builder(L->getLoopPreheader()->getTerminator()); // Find the loop boundaries. ScalarEvolution *SE = PSE.getSE(); const SCEV *BackedgeTakenCount = SE->getBackedgeTakenCount(OrigLoop); assert(BackedgeTakenCount != SE->getCouldNotCompute() && "Invalid loop count"); Type *IdxTy = Legal->getWidestInductionType(); // The exit count might have the type of i64 while the phi is i32. This can // happen if we have an induction variable that is sign extended before the // compare. The only way that we get a backedge taken count is that the // induction variable was signed and as such will not overflow. In such a case // truncation is legal. if (BackedgeTakenCount->getType()->getPrimitiveSizeInBits() > IdxTy->getPrimitiveSizeInBits()) BackedgeTakenCount = SE->getTruncateOrNoop(BackedgeTakenCount, IdxTy); BackedgeTakenCount = SE->getNoopOrZeroExtend(BackedgeTakenCount, IdxTy); // Get the total trip count from the count by adding 1. const SCEV *ExitCount = SE->getAddExpr( BackedgeTakenCount, SE->getOne(BackedgeTakenCount->getType())); const DataLayout &DL = L->getHeader()->getModule()->getDataLayout(); // Expand the trip count and place the new instructions in the preheader. // Notice that the pre-header does not change, only the loop body. SCEVExpander Exp(*SE, DL, "induction"); // Count holds the overall loop count (N). TripCount = Exp.expandCodeFor(ExitCount, ExitCount->getType(), L->getLoopPreheader()->getTerminator()); if (TripCount->getType()->isPointerTy()) TripCount = CastInst::CreatePointerCast(TripCount, IdxTy, "exitcount.ptrcnt.to.int", L->getLoopPreheader()->getTerminator()); return TripCount; } Value *InnerLoopVectorizer::getOrCreateVectorTripCount(Loop *L) { if (VectorTripCount) return VectorTripCount; Value *TC = getOrCreateTripCount(L); IRBuilder<> Builder(L->getLoopPreheader()->getTerminator()); // Now we need to generate the expression for N - (N % VF), which is // the part that the vectorized body will execute. // The loop step is equal to the vectorization factor (num of SIMD elements) // times the unroll factor (num of SIMD instructions). Constant *Step = ConstantInt::get(TC->getType(), VF * UF); Value *R = Builder.CreateURem(TC, Step, "n.mod.vf"); VectorTripCount = Builder.CreateSub(TC, R, "n.vec"); return VectorTripCount; } void InnerLoopVectorizer::emitMinimumIterationCountCheck(Loop *L, BasicBlock *Bypass) { Value *Count = getOrCreateTripCount(L); BasicBlock *BB = L->getLoopPreheader(); IRBuilder<> Builder(BB->getTerminator()); // Generate code to check that the loop's trip count that we computed by // adding one to the backedge-taken count will not overflow. Value *CheckMinIters = Builder.CreateICmpULT(Count, ConstantInt::get(Count->getType(), VF * UF), "min.iters.check"); BasicBlock *NewBB = BB->splitBasicBlock(BB->getTerminator(), "min.iters.checked"); if (L->getParentLoop()) L->getParentLoop()->addBasicBlockToLoop(NewBB, *LI); ReplaceInstWithInst(BB->getTerminator(), BranchInst::Create(Bypass, NewBB, CheckMinIters)); LoopBypassBlocks.push_back(BB); } void InnerLoopVectorizer::emitVectorLoopEnteredCheck(Loop *L, BasicBlock *Bypass) { Value *TC = getOrCreateVectorTripCount(L); BasicBlock *BB = L->getLoopPreheader(); IRBuilder<> Builder(BB->getTerminator()); // Now, compare the new count to zero. If it is zero skip the vector loop and // jump to the scalar loop. Value *Cmp = Builder.CreateICmpEQ(TC, Constant::getNullValue(TC->getType()), "cmp.zero"); // Generate code to check that the loop's trip count that we computed by // adding one to the backedge-taken count will not overflow. BasicBlock *NewBB = BB->splitBasicBlock(BB->getTerminator(), "vector.ph"); if (L->getParentLoop()) L->getParentLoop()->addBasicBlockToLoop(NewBB, *LI); ReplaceInstWithInst(BB->getTerminator(), BranchInst::Create(Bypass, NewBB, Cmp)); LoopBypassBlocks.push_back(BB); } void InnerLoopVectorizer::emitSCEVChecks(Loop *L, BasicBlock *Bypass) { BasicBlock *BB = L->getLoopPreheader(); // Generate the code to check that the SCEV assumptions that we made. // We want the new basic block to start at the first instruction in a // sequence of instructions that form a check. SCEVExpander Exp(*PSE.getSE(), Bypass->getModule()->getDataLayout(), "scev.check"); Value *SCEVCheck = Exp.expandCodeForPredicate(&PSE.getUnionPredicate(), BB->getTerminator()); if (auto *C = dyn_cast(SCEVCheck)) if (C->isZero()) return; // Create a new block containing the stride check. BB->setName("vector.scevcheck"); auto *NewBB = BB->splitBasicBlock(BB->getTerminator(), "vector.ph"); if (L->getParentLoop()) L->getParentLoop()->addBasicBlockToLoop(NewBB, *LI); ReplaceInstWithInst(BB->getTerminator(), BranchInst::Create(Bypass, NewBB, SCEVCheck)); LoopBypassBlocks.push_back(BB); AddedSafetyChecks = true; } void InnerLoopVectorizer::emitMemRuntimeChecks(Loop *L, BasicBlock *Bypass) { BasicBlock *BB = L->getLoopPreheader(); // Generate the code that checks in runtime if arrays overlap. We put the // checks into a separate block to make the more common case of few elements // faster. Instruction *FirstCheckInst; Instruction *MemRuntimeCheck; std::tie(FirstCheckInst, MemRuntimeCheck) = Legal->getLAI()->addRuntimeChecks(BB->getTerminator()); if (!MemRuntimeCheck) return; // Create a new block containing the memory check. BB->setName("vector.memcheck"); auto *NewBB = BB->splitBasicBlock(BB->getTerminator(), "vector.ph"); if (L->getParentLoop()) L->getParentLoop()->addBasicBlockToLoop(NewBB, *LI); ReplaceInstWithInst(BB->getTerminator(), BranchInst::Create(Bypass, NewBB, MemRuntimeCheck)); LoopBypassBlocks.push_back(BB); AddedSafetyChecks = true; } void InnerLoopVectorizer::createEmptyLoop() { /* In this function we generate a new loop. The new loop will contain the vectorized instructions while the old loop will continue to run the scalar remainder. [ ] <-- loop iteration number check. / | / v | [ ] <-- vector loop bypass (may consist of multiple blocks). | / | | / v || [ ] <-- vector pre header. |/ | | v | [ ] \ | [ ]_| <-- vector loop. | | | v | -[ ] <--- middle-block. | / | | / v -|- >[ ] <--- new preheader. | | | v | [ ] \ | [ ]_| <-- old scalar loop to handle remainder. \ | \ v >[ ] <-- exit block. ... */ BasicBlock *OldBasicBlock = OrigLoop->getHeader(); BasicBlock *VectorPH = OrigLoop->getLoopPreheader(); BasicBlock *ExitBlock = OrigLoop->getExitBlock(); assert(VectorPH && "Invalid loop structure"); assert(ExitBlock && "Must have an exit block"); // Some loops have a single integer induction variable, while other loops // don't. One example is c++ iterators that often have multiple pointer // induction variables. In the code below we also support a case where we // don't have a single induction variable. // // We try to obtain an induction variable from the original loop as hard // as possible. However if we don't find one that: // - is an integer // - counts from zero, stepping by one // - is the size of the widest induction variable type // then we create a new one. OldInduction = Legal->getInduction(); Type *IdxTy = Legal->getWidestInductionType(); // Split the single block loop into the two loop structure described above. BasicBlock *VecBody = VectorPH->splitBasicBlock(VectorPH->getTerminator(), "vector.body"); BasicBlock *MiddleBlock = VecBody->splitBasicBlock(VecBody->getTerminator(), "middle.block"); BasicBlock *ScalarPH = MiddleBlock->splitBasicBlock(MiddleBlock->getTerminator(), "scalar.ph"); // Create and register the new vector loop. Loop* Lp = new Loop(); Loop *ParentLoop = OrigLoop->getParentLoop(); // Insert the new loop into the loop nest and register the new basic blocks // before calling any utilities such as SCEV that require valid LoopInfo. if (ParentLoop) { ParentLoop->addChildLoop(Lp); ParentLoop->addBasicBlockToLoop(ScalarPH, *LI); ParentLoop->addBasicBlockToLoop(MiddleBlock, *LI); } else { LI->addTopLevelLoop(Lp); } Lp->addBasicBlockToLoop(VecBody, *LI); // Find the loop boundaries. Value *Count = getOrCreateTripCount(Lp); Value *StartIdx = ConstantInt::get(IdxTy, 0); // We need to test whether the backedge-taken count is uint##_max. Adding one // to it will cause overflow and an incorrect loop trip count in the vector // body. In case of overflow we want to directly jump to the scalar remainder // loop. emitMinimumIterationCountCheck(Lp, ScalarPH); // Now, compare the new count to zero. If it is zero skip the vector loop and // jump to the scalar loop. emitVectorLoopEnteredCheck(Lp, ScalarPH); // Generate the code to check any assumptions that we've made for SCEV // expressions. emitSCEVChecks(Lp, ScalarPH); // Generate the code that checks in runtime if arrays overlap. We put the // checks into a separate block to make the more common case of few elements // faster. emitMemRuntimeChecks(Lp, ScalarPH); // Generate the induction variable. // The loop step is equal to the vectorization factor (num of SIMD elements) // times the unroll factor (num of SIMD instructions). Value *CountRoundDown = getOrCreateVectorTripCount(Lp); Constant *Step = ConstantInt::get(IdxTy, VF * UF); Induction = createInductionVariable(Lp, StartIdx, CountRoundDown, Step, getDebugLocFromInstOrOperands(OldInduction)); // We are going to resume the execution of the scalar loop. // Go over all of the induction variables that we found and fix the // PHIs that are left in the scalar version of the loop. // The starting values of PHI nodes depend on the counter of the last // iteration in the vectorized loop. // If we come from a bypass edge then we need to start from the original // start value. // This variable saves the new starting index for the scalar loop. It is used // to test if there are any tail iterations left once the vector loop has // completed. LoopVectorizationLegality::InductionList::iterator I, E; LoopVectorizationLegality::InductionList *List = Legal->getInductionVars(); for (I = List->begin(), E = List->end(); I != E; ++I) { PHINode *OrigPhi = I->first; InductionDescriptor II = I->second; // Create phi nodes to merge from the backedge-taken check block. PHINode *BCResumeVal = PHINode::Create(OrigPhi->getType(), 3, "bc.resume.val", ScalarPH->getTerminator()); Value *EndValue; if (OrigPhi == OldInduction) { // We know what the end value is. EndValue = CountRoundDown; } else { IRBuilder<> B(LoopBypassBlocks.back()->getTerminator()); Value *CRD = B.CreateSExtOrTrunc(CountRoundDown, II.getStepValue()->getType(), "cast.crd"); EndValue = II.transform(B, CRD); EndValue->setName("ind.end"); } // The new PHI merges the original incoming value, in case of a bypass, // or the value at the end of the vectorized loop. BCResumeVal->addIncoming(EndValue, MiddleBlock); // Fix the scalar body counter (PHI node). unsigned BlockIdx = OrigPhi->getBasicBlockIndex(ScalarPH); // The old induction's phi node in the scalar body needs the truncated // value. for (unsigned I = 0, E = LoopBypassBlocks.size(); I != E; ++I) BCResumeVal->addIncoming(II.getStartValue(), LoopBypassBlocks[I]); OrigPhi->setIncomingValue(BlockIdx, BCResumeVal); } // Add a check in the middle block to see if we have completed // all of the iterations in the first vector loop. // If (N - N%VF) == N, then we *don't* need to run the remainder. Value *CmpN = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, Count, CountRoundDown, "cmp.n", MiddleBlock->getTerminator()); ReplaceInstWithInst(MiddleBlock->getTerminator(), BranchInst::Create(ExitBlock, ScalarPH, CmpN)); // Get ready to start creating new instructions into the vectorized body. Builder.SetInsertPoint(&*VecBody->getFirstInsertionPt()); // Save the state. LoopVectorPreHeader = Lp->getLoopPreheader(); LoopScalarPreHeader = ScalarPH; LoopMiddleBlock = MiddleBlock; LoopExitBlock = ExitBlock; LoopVectorBody.push_back(VecBody); LoopScalarBody = OldBasicBlock; LoopVectorizeHints Hints(Lp, true); Hints.setAlreadyVectorized(); } namespace { struct CSEDenseMapInfo { static bool canHandle(Instruction *I) { return isa(I) || isa(I) || isa(I) || isa(I); } static inline Instruction *getEmptyKey() { return DenseMapInfo::getEmptyKey(); } static inline Instruction *getTombstoneKey() { return DenseMapInfo::getTombstoneKey(); } static unsigned getHashValue(Instruction *I) { assert(canHandle(I) && "Unknown instruction!"); return hash_combine(I->getOpcode(), hash_combine_range(I->value_op_begin(), I->value_op_end())); } static bool isEqual(Instruction *LHS, Instruction *RHS) { if (LHS == getEmptyKey() || RHS == getEmptyKey() || LHS == getTombstoneKey() || RHS == getTombstoneKey()) return LHS == RHS; return LHS->isIdenticalTo(RHS); } }; } /// \brief Check whether this block is a predicated block. /// Due to if predication of stores we might create a sequence of "if(pred) a[i] /// = ...; " blocks. We start with one vectorized basic block. For every /// conditional block we split this vectorized block. Therefore, every second /// block will be a predicated one. static bool isPredicatedBlock(unsigned BlockNum) { return BlockNum % 2; } ///\brief Perform cse of induction variable instructions. static void cse(SmallVector &BBs) { // Perform simple cse. SmallDenseMap CSEMap; for (unsigned i = 0, e = BBs.size(); i != e; ++i) { BasicBlock *BB = BBs[i]; for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E;) { Instruction *In = &*I++; if (!CSEDenseMapInfo::canHandle(In)) continue; // Check if we can replace this instruction with any of the // visited instructions. if (Instruction *V = CSEMap.lookup(In)) { In->replaceAllUsesWith(V); In->eraseFromParent(); continue; } // Ignore instructions in conditional blocks. We create "if (pred) a[i] = // ...;" blocks for predicated stores. Every second block is a predicated // block. if (isPredicatedBlock(i)) continue; CSEMap[In] = In; } } } /// \brief Adds a 'fast' flag to floating point operations. static Value *addFastMathFlag(Value *V) { if (isa(V)){ FastMathFlags Flags; Flags.setUnsafeAlgebra(); cast(V)->setFastMathFlags(Flags); } return V; } /// Estimate the overhead of scalarizing a value. Insert and Extract are set if /// the result needs to be inserted and/or extracted from vectors. static unsigned getScalarizationOverhead(Type *Ty, bool Insert, bool Extract, const TargetTransformInfo &TTI) { if (Ty->isVoidTy()) return 0; assert(Ty->isVectorTy() && "Can only scalarize vectors"); unsigned Cost = 0; for (int i = 0, e = Ty->getVectorNumElements(); i < e; ++i) { if (Insert) Cost += TTI.getVectorInstrCost(Instruction::InsertElement, Ty, i); if (Extract) Cost += TTI.getVectorInstrCost(Instruction::ExtractElement, Ty, i); } return Cost; } // Estimate cost of a call instruction CI if it were vectorized with factor VF. // Return the cost of the instruction, including scalarization overhead if it's // needed. The flag NeedToScalarize shows if the call needs to be scalarized - // i.e. either vector version isn't available, or is too expensive. static unsigned getVectorCallCost(CallInst *CI, unsigned VF, const TargetTransformInfo &TTI, const TargetLibraryInfo *TLI, bool &NeedToScalarize) { Function *F = CI->getCalledFunction(); StringRef FnName = CI->getCalledFunction()->getName(); Type *ScalarRetTy = CI->getType(); SmallVector Tys, ScalarTys; for (auto &ArgOp : CI->arg_operands()) ScalarTys.push_back(ArgOp->getType()); // Estimate cost of scalarized vector call. The source operands are assumed // to be vectors, so we need to extract individual elements from there, // execute VF scalar calls, and then gather the result into the vector return // value. unsigned ScalarCallCost = TTI.getCallInstrCost(F, ScalarRetTy, ScalarTys); if (VF == 1) return ScalarCallCost; // Compute corresponding vector type for return value and arguments. Type *RetTy = ToVectorTy(ScalarRetTy, VF); for (unsigned i = 0, ie = ScalarTys.size(); i != ie; ++i) Tys.push_back(ToVectorTy(ScalarTys[i], VF)); // Compute costs of unpacking argument values for the scalar calls and // packing the return values to a vector. unsigned ScalarizationCost = getScalarizationOverhead(RetTy, true, false, TTI); for (unsigned i = 0, ie = Tys.size(); i != ie; ++i) ScalarizationCost += getScalarizationOverhead(Tys[i], false, true, TTI); unsigned Cost = ScalarCallCost * VF + ScalarizationCost; // If we can't emit a vector call for this function, then the currently found // cost is the cost we need to return. NeedToScalarize = true; if (!TLI || !TLI->isFunctionVectorizable(FnName, VF) || CI->isNoBuiltin()) return Cost; // If the corresponding vector cost is cheaper, return its cost. unsigned VectorCallCost = TTI.getCallInstrCost(nullptr, RetTy, Tys); if (VectorCallCost < Cost) { NeedToScalarize = false; return VectorCallCost; } return Cost; } // Estimate cost of an intrinsic call instruction CI if it were vectorized with // factor VF. Return the cost of the instruction, including scalarization // overhead if it's needed. static unsigned getVectorIntrinsicCost(CallInst *CI, unsigned VF, const TargetTransformInfo &TTI, const TargetLibraryInfo *TLI) { Intrinsic::ID ID = getIntrinsicIDForCall(CI, TLI); assert(ID && "Expected intrinsic call!"); Type *RetTy = ToVectorTy(CI->getType(), VF); SmallVector Tys; for (unsigned i = 0, ie = CI->getNumArgOperands(); i != ie; ++i) Tys.push_back(ToVectorTy(CI->getArgOperand(i)->getType(), VF)); return TTI.getIntrinsicInstrCost(ID, RetTy, Tys); } static Type *smallestIntegerVectorType(Type *T1, Type *T2) { IntegerType *I1 = cast(T1->getVectorElementType()); IntegerType *I2 = cast(T2->getVectorElementType()); return I1->getBitWidth() < I2->getBitWidth() ? T1 : T2; } static Type *largestIntegerVectorType(Type *T1, Type *T2) { IntegerType *I1 = cast(T1->getVectorElementType()); IntegerType *I2 = cast(T2->getVectorElementType()); return I1->getBitWidth() > I2->getBitWidth() ? T1 : T2; } void InnerLoopVectorizer::truncateToMinimalBitwidths() { // For every instruction `I` in MinBWs, truncate the operands, create a // truncated version of `I` and reextend its result. InstCombine runs // later and will remove any ext/trunc pairs. // for (auto &KV : MinBWs) { VectorParts &Parts = WidenMap.get(KV.first); for (Value *&I : Parts) { if (I->use_empty()) continue; Type *OriginalTy = I->getType(); Type *ScalarTruncatedTy = IntegerType::get(OriginalTy->getContext(), KV.second); Type *TruncatedTy = VectorType::get(ScalarTruncatedTy, OriginalTy->getVectorNumElements()); if (TruncatedTy == OriginalTy) continue; IRBuilder<> B(cast(I)); auto ShrinkOperand = [&](Value *V) -> Value* { if (auto *ZI = dyn_cast(V)) if (ZI->getSrcTy() == TruncatedTy) return ZI->getOperand(0); return B.CreateZExtOrTrunc(V, TruncatedTy); }; // The actual instruction modification depends on the instruction type, // unfortunately. Value *NewI = nullptr; if (BinaryOperator *BO = dyn_cast(I)) { NewI = B.CreateBinOp(BO->getOpcode(), ShrinkOperand(BO->getOperand(0)), ShrinkOperand(BO->getOperand(1))); cast(NewI)->copyIRFlags(I); } else if (ICmpInst *CI = dyn_cast(I)) { NewI = B.CreateICmp(CI->getPredicate(), ShrinkOperand(CI->getOperand(0)), ShrinkOperand(CI->getOperand(1))); } else if (SelectInst *SI = dyn_cast(I)) { NewI = B.CreateSelect(SI->getCondition(), ShrinkOperand(SI->getTrueValue()), ShrinkOperand(SI->getFalseValue())); } else if (CastInst *CI = dyn_cast(I)) { switch (CI->getOpcode()) { default: llvm_unreachable("Unhandled cast!"); case Instruction::Trunc: NewI = ShrinkOperand(CI->getOperand(0)); break; case Instruction::SExt: NewI = B.CreateSExtOrTrunc(CI->getOperand(0), smallestIntegerVectorType(OriginalTy, TruncatedTy)); break; case Instruction::ZExt: NewI = B.CreateZExtOrTrunc(CI->getOperand(0), smallestIntegerVectorType(OriginalTy, TruncatedTy)); break; } } else if (ShuffleVectorInst *SI = dyn_cast(I)) { auto Elements0 = SI->getOperand(0)->getType()->getVectorNumElements(); auto *O0 = B.CreateZExtOrTrunc(SI->getOperand(0), VectorType::get(ScalarTruncatedTy, Elements0)); auto Elements1 = SI->getOperand(1)->getType()->getVectorNumElements(); auto *O1 = B.CreateZExtOrTrunc(SI->getOperand(1), VectorType::get(ScalarTruncatedTy, Elements1)); NewI = B.CreateShuffleVector(O0, O1, SI->getMask()); } else if (isa(I)) { // Don't do anything with the operands, just extend the result. continue; } else { llvm_unreachable("Unhandled instruction type!"); } // Lastly, extend the result. NewI->takeName(cast(I)); Value *Res = B.CreateZExtOrTrunc(NewI, OriginalTy); I->replaceAllUsesWith(Res); cast(I)->eraseFromParent(); I = Res; } } // We'll have created a bunch of ZExts that are now parentless. Clean up. for (auto &KV : MinBWs) { VectorParts &Parts = WidenMap.get(KV.first); for (Value *&I : Parts) { ZExtInst *Inst = dyn_cast(I); if (Inst && Inst->use_empty()) { Value *NewI = Inst->getOperand(0); Inst->eraseFromParent(); I = NewI; } } } } void InnerLoopVectorizer::vectorizeLoop() { //===------------------------------------------------===// // // Notice: any optimization or new instruction that go // into the code below should be also be implemented in // the cost-model. // //===------------------------------------------------===// Constant *Zero = Builder.getInt32(0); // In order to support reduction variables we need to be able to vectorize // Phi nodes. Phi nodes have cycles, so we need to vectorize them in two // stages. First, we create a new vector PHI node with no incoming edges. // We use this value when we vectorize all of the instructions that use the // PHI. Next, after all of the instructions in the block are complete we // add the new incoming edges to the PHI. At this point all of the // instructions in the basic block are vectorized, so we can use them to // construct the PHI. PhiVector RdxPHIsToFix; // Scan the loop in a topological order to ensure that defs are vectorized // before users. LoopBlocksDFS DFS(OrigLoop); DFS.perform(LI); // Vectorize all of the blocks in the original loop. for (LoopBlocksDFS::RPOIterator bb = DFS.beginRPO(), be = DFS.endRPO(); bb != be; ++bb) vectorizeBlockInLoop(*bb, &RdxPHIsToFix); // Insert truncates and extends for any truncated instructions as hints to // InstCombine. if (VF > 1) truncateToMinimalBitwidths(); // At this point every instruction in the original loop is widened to // a vector form. We are almost done. Now, we need to fix the PHI nodes // that we vectorized. The PHI nodes are currently empty because we did // not want to introduce cycles. Notice that the remaining PHI nodes // that we need to fix are reduction variables. // Create the 'reduced' values for each of the induction vars. // The reduced values are the vector values that we scalarize and combine // after the loop is finished. for (PhiVector::iterator it = RdxPHIsToFix.begin(), e = RdxPHIsToFix.end(); it != e; ++it) { PHINode *RdxPhi = *it; assert(RdxPhi && "Unable to recover vectorized PHI"); // Find the reduction variable descriptor. assert(Legal->isReductionVariable(RdxPhi) && "Unable to find the reduction variable"); RecurrenceDescriptor RdxDesc = (*Legal->getReductionVars())[RdxPhi]; RecurrenceDescriptor::RecurrenceKind RK = RdxDesc.getRecurrenceKind(); TrackingVH ReductionStartValue = RdxDesc.getRecurrenceStartValue(); Instruction *LoopExitInst = RdxDesc.getLoopExitInstr(); RecurrenceDescriptor::MinMaxRecurrenceKind MinMaxKind = RdxDesc.getMinMaxRecurrenceKind(); setDebugLocFromInst(Builder, ReductionStartValue); // We need to generate a reduction vector from the incoming scalar. // To do so, we need to generate the 'identity' vector and override // one of the elements with the incoming scalar reduction. We need // to do it in the vector-loop preheader. Builder.SetInsertPoint(LoopBypassBlocks[1]->getTerminator()); // This is the vector-clone of the value that leaves the loop. VectorParts &VectorExit = getVectorValue(LoopExitInst); Type *VecTy = VectorExit[0]->getType(); // Find the reduction identity variable. Zero for addition, or, xor, // one for multiplication, -1 for And. Value *Identity; Value *VectorStart; if (RK == RecurrenceDescriptor::RK_IntegerMinMax || RK == RecurrenceDescriptor::RK_FloatMinMax) { // MinMax reduction have the start value as their identify. if (VF == 1) { VectorStart = Identity = ReductionStartValue; } else { VectorStart = Identity = Builder.CreateVectorSplat(VF, ReductionStartValue, "minmax.ident"); } } else { // Handle other reduction kinds: Constant *Iden = RecurrenceDescriptor::getRecurrenceIdentity( RK, VecTy->getScalarType()); if (VF == 1) { Identity = Iden; // This vector is the Identity vector where the first element is the // incoming scalar reduction. VectorStart = ReductionStartValue; } else { Identity = ConstantVector::getSplat(VF, Iden); // This vector is the Identity vector where the first element is the // incoming scalar reduction. VectorStart = Builder.CreateInsertElement(Identity, ReductionStartValue, Zero); } } // Fix the vector-loop phi. // Reductions do not have to start at zero. They can start with // any loop invariant values. VectorParts &VecRdxPhi = WidenMap.get(RdxPhi); BasicBlock *Latch = OrigLoop->getLoopLatch(); Value *LoopVal = RdxPhi->getIncomingValueForBlock(Latch); VectorParts &Val = getVectorValue(LoopVal); for (unsigned part = 0; part < UF; ++part) { // Make sure to add the reduction stat value only to the // first unroll part. Value *StartVal = (part == 0) ? VectorStart : Identity; cast(VecRdxPhi[part])->addIncoming(StartVal, LoopVectorPreHeader); cast(VecRdxPhi[part])->addIncoming(Val[part], LoopVectorBody.back()); } // Before each round, move the insertion point right between // the PHIs and the values we are going to write. // This allows us to write both PHINodes and the extractelement // instructions. Builder.SetInsertPoint(&*LoopMiddleBlock->getFirstInsertionPt()); VectorParts RdxParts = getVectorValue(LoopExitInst); setDebugLocFromInst(Builder, LoopExitInst); // If the vector reduction can be performed in a smaller type, we truncate // then extend the loop exit value to enable InstCombine to evaluate the // entire expression in the smaller type. if (VF > 1 && RdxPhi->getType() != RdxDesc.getRecurrenceType()) { Type *RdxVecTy = VectorType::get(RdxDesc.getRecurrenceType(), VF); Builder.SetInsertPoint(LoopVectorBody.back()->getTerminator()); for (unsigned part = 0; part < UF; ++part) { Value *Trunc = Builder.CreateTrunc(RdxParts[part], RdxVecTy); Value *Extnd = RdxDesc.isSigned() ? Builder.CreateSExt(Trunc, VecTy) : Builder.CreateZExt(Trunc, VecTy); for (Value::user_iterator UI = RdxParts[part]->user_begin(); UI != RdxParts[part]->user_end();) if (*UI != Trunc) { (*UI++)->replaceUsesOfWith(RdxParts[part], Extnd); RdxParts[part] = Extnd; } else { ++UI; } } Builder.SetInsertPoint(&*LoopMiddleBlock->getFirstInsertionPt()); for (unsigned part = 0; part < UF; ++part) RdxParts[part] = Builder.CreateTrunc(RdxParts[part], RdxVecTy); } // Reduce all of the unrolled parts into a single vector. Value *ReducedPartRdx = RdxParts[0]; unsigned Op = RecurrenceDescriptor::getRecurrenceBinOp(RK); setDebugLocFromInst(Builder, ReducedPartRdx); for (unsigned part = 1; part < UF; ++part) { if (Op != Instruction::ICmp && Op != Instruction::FCmp) // Floating point operations had to be 'fast' to enable the reduction. ReducedPartRdx = addFastMathFlag( Builder.CreateBinOp((Instruction::BinaryOps)Op, RdxParts[part], ReducedPartRdx, "bin.rdx")); else ReducedPartRdx = RecurrenceDescriptor::createMinMaxOp( Builder, MinMaxKind, ReducedPartRdx, RdxParts[part]); } if (VF > 1) { // VF is a power of 2 so we can emit the reduction using log2(VF) shuffles // and vector ops, reducing the set of values being computed by half each // round. assert(isPowerOf2_32(VF) && "Reduction emission only supported for pow2 vectors!"); Value *TmpVec = ReducedPartRdx; SmallVector ShuffleMask(VF, nullptr); for (unsigned i = VF; i != 1; i >>= 1) { // Move the upper half of the vector to the lower half. for (unsigned j = 0; j != i/2; ++j) ShuffleMask[j] = Builder.getInt32(i/2 + j); // Fill the rest of the mask with undef. std::fill(&ShuffleMask[i/2], ShuffleMask.end(), UndefValue::get(Builder.getInt32Ty())); Value *Shuf = Builder.CreateShuffleVector(TmpVec, UndefValue::get(TmpVec->getType()), ConstantVector::get(ShuffleMask), "rdx.shuf"); if (Op != Instruction::ICmp && Op != Instruction::FCmp) // Floating point operations had to be 'fast' to enable the reduction. TmpVec = addFastMathFlag(Builder.CreateBinOp( (Instruction::BinaryOps)Op, TmpVec, Shuf, "bin.rdx")); else TmpVec = RecurrenceDescriptor::createMinMaxOp(Builder, MinMaxKind, TmpVec, Shuf); } // The result is in the first element of the vector. ReducedPartRdx = Builder.CreateExtractElement(TmpVec, Builder.getInt32(0)); // If the reduction can be performed in a smaller type, we need to extend // the reduction to the wider type before we branch to the original loop. if (RdxPhi->getType() != RdxDesc.getRecurrenceType()) ReducedPartRdx = RdxDesc.isSigned() ? Builder.CreateSExt(ReducedPartRdx, RdxPhi->getType()) : Builder.CreateZExt(ReducedPartRdx, RdxPhi->getType()); } // Create a phi node that merges control-flow from the backedge-taken check // block and the middle block. PHINode *BCBlockPhi = PHINode::Create(RdxPhi->getType(), 2, "bc.merge.rdx", LoopScalarPreHeader->getTerminator()); for (unsigned I = 0, E = LoopBypassBlocks.size(); I != E; ++I) BCBlockPhi->addIncoming(ReductionStartValue, LoopBypassBlocks[I]); BCBlockPhi->addIncoming(ReducedPartRdx, LoopMiddleBlock); // Now, we need to fix the users of the reduction variable // inside and outside of the scalar remainder loop. // We know that the loop is in LCSSA form. We need to update the // PHI nodes in the exit blocks. for (BasicBlock::iterator LEI = LoopExitBlock->begin(), LEE = LoopExitBlock->end(); LEI != LEE; ++LEI) { PHINode *LCSSAPhi = dyn_cast(LEI); if (!LCSSAPhi) break; // All PHINodes need to have a single entry edge, or two if // we already fixed them. assert(LCSSAPhi->getNumIncomingValues() < 3 && "Invalid LCSSA PHI"); // We found our reduction value exit-PHI. Update it with the // incoming bypass edge. if (LCSSAPhi->getIncomingValue(0) == LoopExitInst) { // Add an edge coming from the bypass. LCSSAPhi->addIncoming(ReducedPartRdx, LoopMiddleBlock); break; } }// end of the LCSSA phi scan. // Fix the scalar loop reduction variable with the incoming reduction sum // from the vector body and from the backedge value. int IncomingEdgeBlockIdx = (RdxPhi)->getBasicBlockIndex(OrigLoop->getLoopLatch()); assert(IncomingEdgeBlockIdx >= 0 && "Invalid block index"); // Pick the other block. int SelfEdgeBlockIdx = (IncomingEdgeBlockIdx ? 0 : 1); (RdxPhi)->setIncomingValue(SelfEdgeBlockIdx, BCBlockPhi); (RdxPhi)->setIncomingValue(IncomingEdgeBlockIdx, LoopExitInst); }// end of for each redux variable. fixLCSSAPHIs(); // Make sure DomTree is updated. updateAnalysis(); // Predicate any stores. for (auto KV : PredicatedStores) { BasicBlock::iterator I(KV.first); auto *BB = SplitBlock(I->getParent(), &*std::next(I), DT, LI); auto *T = SplitBlockAndInsertIfThen(KV.second, &*I, /*Unreachable=*/false, /*BranchWeights=*/nullptr, DT); I->moveBefore(T); I->getParent()->setName("pred.store.if"); BB->setName("pred.store.continue"); } DEBUG(DT->verifyDomTree()); // Remove redundant induction instructions. cse(LoopVectorBody); } void InnerLoopVectorizer::fixLCSSAPHIs() { for (BasicBlock::iterator LEI = LoopExitBlock->begin(), LEE = LoopExitBlock->end(); LEI != LEE; ++LEI) { PHINode *LCSSAPhi = dyn_cast(LEI); if (!LCSSAPhi) break; if (LCSSAPhi->getNumIncomingValues() == 1) LCSSAPhi->addIncoming(UndefValue::get(LCSSAPhi->getType()), LoopMiddleBlock); } } InnerLoopVectorizer::VectorParts InnerLoopVectorizer::createEdgeMask(BasicBlock *Src, BasicBlock *Dst) { assert(std::find(pred_begin(Dst), pred_end(Dst), Src) != pred_end(Dst) && "Invalid edge"); // Look for cached value. std::pair Edge(Src, Dst); EdgeMaskCache::iterator ECEntryIt = MaskCache.find(Edge); if (ECEntryIt != MaskCache.end()) return ECEntryIt->second; VectorParts SrcMask = createBlockInMask(Src); // The terminator has to be a branch inst! BranchInst *BI = dyn_cast(Src->getTerminator()); assert(BI && "Unexpected terminator found"); if (BI->isConditional()) { VectorParts EdgeMask = getVectorValue(BI->getCondition()); if (BI->getSuccessor(0) != Dst) for (unsigned part = 0; part < UF; ++part) EdgeMask[part] = Builder.CreateNot(EdgeMask[part]); for (unsigned part = 0; part < UF; ++part) EdgeMask[part] = Builder.CreateAnd(EdgeMask[part], SrcMask[part]); MaskCache[Edge] = EdgeMask; return EdgeMask; } MaskCache[Edge] = SrcMask; return SrcMask; } InnerLoopVectorizer::VectorParts InnerLoopVectorizer::createBlockInMask(BasicBlock *BB) { assert(OrigLoop->contains(BB) && "Block is not a part of a loop"); // Loop incoming mask is all-one. if (OrigLoop->getHeader() == BB) { Value *C = ConstantInt::get(IntegerType::getInt1Ty(BB->getContext()), 1); return getVectorValue(C); } // This is the block mask. We OR all incoming edges, and with zero. Value *Zero = ConstantInt::get(IntegerType::getInt1Ty(BB->getContext()), 0); VectorParts BlockMask = getVectorValue(Zero); // For each pred: for (pred_iterator it = pred_begin(BB), e = pred_end(BB); it != e; ++it) { VectorParts EM = createEdgeMask(*it, BB); for (unsigned part = 0; part < UF; ++part) BlockMask[part] = Builder.CreateOr(BlockMask[part], EM[part]); } return BlockMask; } void InnerLoopVectorizer::widenPHIInstruction( Instruction *PN, InnerLoopVectorizer::VectorParts &Entry, unsigned UF, unsigned VF, PhiVector *PV) { PHINode* P = cast(PN); // Handle reduction variables: if (Legal->isReductionVariable(P)) { for (unsigned part = 0; part < UF; ++part) { // This is phase one of vectorizing PHIs. Type *VecTy = (VF == 1) ? PN->getType() : VectorType::get(PN->getType(), VF); Entry[part] = PHINode::Create( VecTy, 2, "vec.phi", &*LoopVectorBody.back()->getFirstInsertionPt()); } PV->push_back(P); return; } setDebugLocFromInst(Builder, P); // Check for PHI nodes that are lowered to vector selects. if (P->getParent() != OrigLoop->getHeader()) { // We know that all PHIs in non-header blocks are converted into // selects, so we don't have to worry about the insertion order and we // can just use the builder. // At this point we generate the predication tree. There may be // duplications since this is a simple recursive scan, but future // optimizations will clean it up. unsigned NumIncoming = P->getNumIncomingValues(); // Generate a sequence of selects of the form: // SELECT(Mask3, In3, // SELECT(Mask2, In2, // ( ...))) for (unsigned In = 0; In < NumIncoming; In++) { VectorParts Cond = createEdgeMask(P->getIncomingBlock(In), P->getParent()); VectorParts &In0 = getVectorValue(P->getIncomingValue(In)); for (unsigned part = 0; part < UF; ++part) { // We might have single edge PHIs (blocks) - use an identity // 'select' for the first PHI operand. if (In == 0) Entry[part] = Builder.CreateSelect(Cond[part], In0[part], In0[part]); else // Select between the current value and the previous incoming edge // based on the incoming mask. Entry[part] = Builder.CreateSelect(Cond[part], In0[part], Entry[part], "predphi"); } } return; } // This PHINode must be an induction variable. // Make sure that we know about it. assert(Legal->getInductionVars()->count(P) && "Not an induction variable"); InductionDescriptor II = Legal->getInductionVars()->lookup(P); // FIXME: The newly created binary instructions should contain nsw/nuw flags, // which can be found from the original scalar operations. switch (II.getKind()) { case InductionDescriptor::IK_NoInduction: llvm_unreachable("Unknown induction"); case InductionDescriptor::IK_IntInduction: { assert(P->getType() == II.getStartValue()->getType() && "Types must match"); // Handle other induction variables that are now based on the // canonical one. Value *V = Induction; if (P != OldInduction) { V = Builder.CreateSExtOrTrunc(Induction, P->getType()); V = II.transform(Builder, V); V->setName("offset.idx"); } Value *Broadcasted = getBroadcastInstrs(V); // After broadcasting the induction variable we need to make the vector // consecutive by adding 0, 1, 2, etc. for (unsigned part = 0; part < UF; ++part) Entry[part] = getStepVector(Broadcasted, VF * part, II.getStepValue()); return; } case InductionDescriptor::IK_PtrInduction: // Handle the pointer induction variable case. assert(P->getType()->isPointerTy() && "Unexpected type."); // This is the normalized GEP that starts counting at zero. Value *PtrInd = Induction; PtrInd = Builder.CreateSExtOrTrunc(PtrInd, II.getStepValue()->getType()); // This is the vector of results. Notice that we don't generate // vector geps because scalar geps result in better code. for (unsigned part = 0; part < UF; ++part) { if (VF == 1) { int EltIndex = part; Constant *Idx = ConstantInt::get(PtrInd->getType(), EltIndex); Value *GlobalIdx = Builder.CreateAdd(PtrInd, Idx); Value *SclrGep = II.transform(Builder, GlobalIdx); SclrGep->setName("next.gep"); Entry[part] = SclrGep; continue; } Value *VecVal = UndefValue::get(VectorType::get(P->getType(), VF)); for (unsigned int i = 0; i < VF; ++i) { int EltIndex = i + part * VF; Constant *Idx = ConstantInt::get(PtrInd->getType(), EltIndex); Value *GlobalIdx = Builder.CreateAdd(PtrInd, Idx); Value *SclrGep = II.transform(Builder, GlobalIdx); SclrGep->setName("next.gep"); VecVal = Builder.CreateInsertElement(VecVal, SclrGep, Builder.getInt32(i), "insert.gep"); } Entry[part] = VecVal; } return; } } void InnerLoopVectorizer::vectorizeBlockInLoop(BasicBlock *BB, PhiVector *PV) { // For each instruction in the old loop. for (BasicBlock::iterator it = BB->begin(), e = BB->end(); it != e; ++it) { VectorParts &Entry = WidenMap.get(&*it); switch (it->getOpcode()) { case Instruction::Br: // Nothing to do for PHIs and BR, since we already took care of the // loop control flow instructions. continue; case Instruction::PHI: { // Vectorize PHINodes. widenPHIInstruction(&*it, Entry, UF, VF, PV); continue; }// End of PHI. case Instruction::Add: case Instruction::FAdd: case Instruction::Sub: case Instruction::FSub: case Instruction::Mul: case Instruction::FMul: case Instruction::UDiv: case Instruction::SDiv: case Instruction::FDiv: case Instruction::URem: case Instruction::SRem: case Instruction::FRem: case Instruction::Shl: case Instruction::LShr: case Instruction::AShr: case Instruction::And: case Instruction::Or: case Instruction::Xor: { // Just widen binops. BinaryOperator *BinOp = dyn_cast(it); setDebugLocFromInst(Builder, BinOp); VectorParts &A = getVectorValue(it->getOperand(0)); VectorParts &B = getVectorValue(it->getOperand(1)); // Use this vector value for all users of the original instruction. for (unsigned Part = 0; Part < UF; ++Part) { Value *V = Builder.CreateBinOp(BinOp->getOpcode(), A[Part], B[Part]); if (BinaryOperator *VecOp = dyn_cast(V)) VecOp->copyIRFlags(BinOp); Entry[Part] = V; } propagateMetadata(Entry, &*it); break; } case Instruction::Select: { // Widen selects. // If the selector is loop invariant we can create a select // instruction with a scalar condition. Otherwise, use vector-select. auto *SE = PSE.getSE(); bool InvariantCond = SE->isLoopInvariant(PSE.getSCEV(it->getOperand(0)), OrigLoop); setDebugLocFromInst(Builder, &*it); // The condition can be loop invariant but still defined inside the // loop. This means that we can't just use the original 'cond' value. // We have to take the 'vectorized' value and pick the first lane. // Instcombine will make this a no-op. VectorParts &Cond = getVectorValue(it->getOperand(0)); VectorParts &Op0 = getVectorValue(it->getOperand(1)); VectorParts &Op1 = getVectorValue(it->getOperand(2)); Value *ScalarCond = (VF == 1) ? Cond[0] : Builder.CreateExtractElement(Cond[0], Builder.getInt32(0)); for (unsigned Part = 0; Part < UF; ++Part) { Entry[Part] = Builder.CreateSelect( InvariantCond ? ScalarCond : Cond[Part], Op0[Part], Op1[Part]); } propagateMetadata(Entry, &*it); break; } case Instruction::ICmp: case Instruction::FCmp: { // Widen compares. Generate vector compares. bool FCmp = (it->getOpcode() == Instruction::FCmp); CmpInst *Cmp = dyn_cast(it); setDebugLocFromInst(Builder, &*it); VectorParts &A = getVectorValue(it->getOperand(0)); VectorParts &B = getVectorValue(it->getOperand(1)); for (unsigned Part = 0; Part < UF; ++Part) { Value *C = nullptr; if (FCmp) { C = Builder.CreateFCmp(Cmp->getPredicate(), A[Part], B[Part]); cast(C)->copyFastMathFlags(&*it); } else { C = Builder.CreateICmp(Cmp->getPredicate(), A[Part], B[Part]); } Entry[Part] = C; } propagateMetadata(Entry, &*it); break; } case Instruction::Store: case Instruction::Load: vectorizeMemoryInstruction(&*it); break; case Instruction::ZExt: case Instruction::SExt: case Instruction::FPToUI: case Instruction::FPToSI: case Instruction::FPExt: case Instruction::PtrToInt: case Instruction::IntToPtr: case Instruction::SIToFP: case Instruction::UIToFP: case Instruction::Trunc: case Instruction::FPTrunc: case Instruction::BitCast: { CastInst *CI = dyn_cast(it); setDebugLocFromInst(Builder, &*it); /// Optimize the special case where the source is the induction /// variable. Notice that we can only optimize the 'trunc' case /// because: a. FP conversions lose precision, b. sext/zext may wrap, /// c. other casts depend on pointer size. if (CI->getOperand(0) == OldInduction && it->getOpcode() == Instruction::Trunc) { Value *ScalarCast = Builder.CreateCast(CI->getOpcode(), Induction, CI->getType()); Value *Broadcasted = getBroadcastInstrs(ScalarCast); InductionDescriptor II = Legal->getInductionVars()->lookup(OldInduction); Constant *Step = ConstantInt::getSigned( CI->getType(), II.getStepValue()->getSExtValue()); for (unsigned Part = 0; Part < UF; ++Part) Entry[Part] = getStepVector(Broadcasted, VF * Part, Step); propagateMetadata(Entry, &*it); break; } /// Vectorize casts. Type *DestTy = (VF == 1) ? CI->getType() : VectorType::get(CI->getType(), VF); VectorParts &A = getVectorValue(it->getOperand(0)); for (unsigned Part = 0; Part < UF; ++Part) Entry[Part] = Builder.CreateCast(CI->getOpcode(), A[Part], DestTy); propagateMetadata(Entry, &*it); break; } case Instruction::Call: { // Ignore dbg intrinsics. if (isa(it)) break; setDebugLocFromInst(Builder, &*it); Module *M = BB->getParent()->getParent(); CallInst *CI = cast(it); StringRef FnName = CI->getCalledFunction()->getName(); Function *F = CI->getCalledFunction(); Type *RetTy = ToVectorTy(CI->getType(), VF); SmallVector Tys; for (unsigned i = 0, ie = CI->getNumArgOperands(); i != ie; ++i) Tys.push_back(ToVectorTy(CI->getArgOperand(i)->getType(), VF)); Intrinsic::ID ID = getIntrinsicIDForCall(CI, TLI); if (ID && (ID == Intrinsic::assume || ID == Intrinsic::lifetime_end || ID == Intrinsic::lifetime_start)) { scalarizeInstruction(&*it); break; } // The flag shows whether we use Intrinsic or a usual Call for vectorized // version of the instruction. // Is it beneficial to perform intrinsic call compared to lib call? bool NeedToScalarize; unsigned CallCost = getVectorCallCost(CI, VF, *TTI, TLI, NeedToScalarize); bool UseVectorIntrinsic = ID && getVectorIntrinsicCost(CI, VF, *TTI, TLI) <= CallCost; if (!UseVectorIntrinsic && NeedToScalarize) { scalarizeInstruction(&*it); break; } for (unsigned Part = 0; Part < UF; ++Part) { SmallVector Args; for (unsigned i = 0, ie = CI->getNumArgOperands(); i != ie; ++i) { Value *Arg = CI->getArgOperand(i); // Some intrinsics have a scalar argument - don't replace it with a // vector. if (!UseVectorIntrinsic || !hasVectorInstrinsicScalarOpd(ID, i)) { VectorParts &VectorArg = getVectorValue(CI->getArgOperand(i)); Arg = VectorArg[Part]; } Args.push_back(Arg); } Function *VectorF; if (UseVectorIntrinsic) { // Use vector version of the intrinsic. Type *TysForDecl[] = {CI->getType()}; if (VF > 1) TysForDecl[0] = VectorType::get(CI->getType()->getScalarType(), VF); VectorF = Intrinsic::getDeclaration(M, ID, TysForDecl); } else { // Use vector version of the library call. StringRef VFnName = TLI->getVectorizedFunction(FnName, VF); assert(!VFnName.empty() && "Vector function name is empty."); VectorF = M->getFunction(VFnName); if (!VectorF) { // Generate a declaration FunctionType *FTy = FunctionType::get(RetTy, Tys, false); VectorF = Function::Create(FTy, Function::ExternalLinkage, VFnName, M); VectorF->copyAttributesFrom(F); } } assert(VectorF && "Can't create vector function."); Entry[Part] = Builder.CreateCall(VectorF, Args); } propagateMetadata(Entry, &*it); break; } default: // All other instructions are unsupported. Scalarize them. scalarizeInstruction(&*it); break; }// end of switch. }// end of for_each instr. } void InnerLoopVectorizer::updateAnalysis() { // Forget the original basic block. PSE.getSE()->forgetLoop(OrigLoop); // Update the dominator tree information. assert(DT->properlyDominates(LoopBypassBlocks.front(), LoopExitBlock) && "Entry does not dominate exit."); for (unsigned I = 1, E = LoopBypassBlocks.size(); I != E; ++I) DT->addNewBlock(LoopBypassBlocks[I], LoopBypassBlocks[I-1]); DT->addNewBlock(LoopVectorPreHeader, LoopBypassBlocks.back()); // We don't predicate stores by this point, so the vector body should be a // single loop. assert(LoopVectorBody.size() == 1 && "Expected single block loop!"); DT->addNewBlock(LoopVectorBody[0], LoopVectorPreHeader); DT->addNewBlock(LoopMiddleBlock, LoopVectorBody.back()); DT->addNewBlock(LoopScalarPreHeader, LoopBypassBlocks[0]); DT->changeImmediateDominator(LoopScalarBody, LoopScalarPreHeader); DT->changeImmediateDominator(LoopExitBlock, LoopBypassBlocks[0]); DEBUG(DT->verifyDomTree()); } /// \brief Check whether it is safe to if-convert this phi node. /// /// Phi nodes with constant expressions that can trap are not safe to if /// convert. static bool canIfConvertPHINodes(BasicBlock *BB) { for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) { PHINode *Phi = dyn_cast(I); if (!Phi) return true; for (unsigned p = 0, e = Phi->getNumIncomingValues(); p != e; ++p) if (Constant *C = dyn_cast(Phi->getIncomingValue(p))) if (C->canTrap()) return false; } return true; } bool LoopVectorizationLegality::canVectorizeWithIfConvert() { if (!EnableIfConversion) { emitAnalysis(VectorizationReport() << "if-conversion is disabled"); return false; } assert(TheLoop->getNumBlocks() > 1 && "Single block loops are vectorizable"); // A list of pointers that we can safely read and write to. SmallPtrSet SafePointes; // Collect safe addresses. for (Loop::block_iterator BI = TheLoop->block_begin(), BE = TheLoop->block_end(); BI != BE; ++BI) { BasicBlock *BB = *BI; if (blockNeedsPredication(BB)) continue; for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) { if (LoadInst *LI = dyn_cast(I)) SafePointes.insert(LI->getPointerOperand()); else if (StoreInst *SI = dyn_cast(I)) SafePointes.insert(SI->getPointerOperand()); } } // Collect the blocks that need predication. BasicBlock *Header = TheLoop->getHeader(); for (Loop::block_iterator BI = TheLoop->block_begin(), BE = TheLoop->block_end(); BI != BE; ++BI) { BasicBlock *BB = *BI; // We don't support switch statements inside loops. if (!isa(BB->getTerminator())) { emitAnalysis(VectorizationReport(BB->getTerminator()) << "loop contains a switch statement"); return false; } // We must be able to predicate all blocks that need to be predicated. if (blockNeedsPredication(BB)) { if (!blockCanBePredicated(BB, SafePointes)) { emitAnalysis(VectorizationReport(BB->getTerminator()) << "control flow cannot be substituted for a select"); return false; } } else if (BB != Header && !canIfConvertPHINodes(BB)) { emitAnalysis(VectorizationReport(BB->getTerminator()) << "control flow cannot be substituted for a select"); return false; } } // We can if-convert this loop. return true; } bool LoopVectorizationLegality::canVectorize() { // We must have a loop in canonical form. Loops with indirectbr in them cannot // be canonicalized. if (!TheLoop->getLoopPreheader()) { emitAnalysis( VectorizationReport() << "loop control flow is not understood by vectorizer"); return false; } // We can only vectorize innermost loops. if (!TheLoop->empty()) { emitAnalysis(VectorizationReport() << "loop is not the innermost loop"); return false; } // We must have a single backedge. if (TheLoop->getNumBackEdges() != 1) { emitAnalysis( VectorizationReport() << "loop control flow is not understood by vectorizer"); return false; } // We must have a single exiting block. if (!TheLoop->getExitingBlock()) { emitAnalysis( VectorizationReport() << "loop control flow is not understood by vectorizer"); return false; } // We only handle bottom-tested loops, i.e. loop in which the condition is // checked at the end of each iteration. With that we can assume that all // instructions in the loop are executed the same number of times. if (TheLoop->getExitingBlock() != TheLoop->getLoopLatch()) { emitAnalysis( VectorizationReport() << "loop control flow is not understood by vectorizer"); return false; } // We need to have a loop header. DEBUG(dbgs() << "LV: Found a loop: " << TheLoop->getHeader()->getName() << '\n'); // Check if we can if-convert non-single-bb loops. unsigned NumBlocks = TheLoop->getNumBlocks(); if (NumBlocks != 1 && !canVectorizeWithIfConvert()) { DEBUG(dbgs() << "LV: Can't if-convert the loop.\n"); return false; } // ScalarEvolution needs to be able to find the exit count. const SCEV *ExitCount = PSE.getSE()->getBackedgeTakenCount(TheLoop); if (ExitCount == PSE.getSE()->getCouldNotCompute()) { emitAnalysis(VectorizationReport() << "could not determine number of loop iterations"); DEBUG(dbgs() << "LV: SCEV could not compute the loop exit count.\n"); return false; } // Check if we can vectorize the instructions and CFG in this loop. if (!canVectorizeInstrs()) { DEBUG(dbgs() << "LV: Can't vectorize the instructions or CFG\n"); return false; } // Go over each instruction and look at memory deps. if (!canVectorizeMemory()) { DEBUG(dbgs() << "LV: Can't vectorize due to memory conflicts\n"); return false; } // Collect all of the variables that remain uniform after vectorization. collectLoopUniforms(); DEBUG(dbgs() << "LV: We can vectorize this loop" << (LAI->getRuntimePointerChecking()->Need ? " (with a runtime bound check)" : "") << "!\n"); bool UseInterleaved = TTI->enableInterleavedAccessVectorization(); // If an override option has been passed in for interleaved accesses, use it. if (EnableInterleavedMemAccesses.getNumOccurrences() > 0) UseInterleaved = EnableInterleavedMemAccesses; // Analyze interleaved memory accesses. if (UseInterleaved) InterleaveInfo.analyzeInterleaving(Strides); unsigned SCEVThreshold = VectorizeSCEVCheckThreshold; if (Hints->getForce() == LoopVectorizeHints::FK_Enabled) SCEVThreshold = PragmaVectorizeSCEVCheckThreshold; if (PSE.getUnionPredicate().getComplexity() > SCEVThreshold) { emitAnalysis(VectorizationReport() << "Too many SCEV assumptions need to be made and checked " << "at runtime"); DEBUG(dbgs() << "LV: Too many SCEV checks needed.\n"); return false; } // Okay! We can vectorize. At this point we don't have any other mem analysis // which may limit our maximum vectorization factor, so just return true with // no restrictions. return true; } static Type *convertPointerToIntegerType(const DataLayout &DL, Type *Ty) { if (Ty->isPointerTy()) return DL.getIntPtrType(Ty); // It is possible that char's or short's overflow when we ask for the loop's // trip count, work around this by changing the type size. if (Ty->getScalarSizeInBits() < 32) return Type::getInt32Ty(Ty->getContext()); return Ty; } static Type* getWiderType(const DataLayout &DL, Type *Ty0, Type *Ty1) { Ty0 = convertPointerToIntegerType(DL, Ty0); Ty1 = convertPointerToIntegerType(DL, Ty1); if (Ty0->getScalarSizeInBits() > Ty1->getScalarSizeInBits()) return Ty0; return Ty1; } /// \brief Check that the instruction has outside loop users and is not an /// identified reduction variable. static bool hasOutsideLoopUser(const Loop *TheLoop, Instruction *Inst, SmallPtrSetImpl &Reductions) { // Reduction instructions are allowed to have exit users. All other // instructions must not have external users. if (!Reductions.count(Inst)) //Check that all of the users of the loop are inside the BB. for (User *U : Inst->users()) { Instruction *UI = cast(U); // This user may be a reduction exit value. if (!TheLoop->contains(UI)) { DEBUG(dbgs() << "LV: Found an outside user for : " << *UI << '\n'); return true; } } return false; } bool LoopVectorizationLegality::canVectorizeInstrs() { BasicBlock *Header = TheLoop->getHeader(); // Look for the attribute signaling the absence of NaNs. Function &F = *Header->getParent(); const DataLayout &DL = F.getParent()->getDataLayout(); if (F.hasFnAttribute("no-nans-fp-math")) HasFunNoNaNAttr = F.getFnAttribute("no-nans-fp-math").getValueAsString() == "true"; // For each block in the loop. for (Loop::block_iterator bb = TheLoop->block_begin(), be = TheLoop->block_end(); bb != be; ++bb) { // Scan the instructions in the block and look for hazards. for (BasicBlock::iterator it = (*bb)->begin(), e = (*bb)->end(); it != e; ++it) { if (PHINode *Phi = dyn_cast(it)) { Type *PhiTy = Phi->getType(); // Check that this PHI type is allowed. if (!PhiTy->isIntegerTy() && !PhiTy->isFloatingPointTy() && !PhiTy->isPointerTy()) { emitAnalysis(VectorizationReport(&*it) << "loop control flow is not understood by vectorizer"); DEBUG(dbgs() << "LV: Found an non-int non-pointer PHI.\n"); return false; } // If this PHINode is not in the header block, then we know that we // can convert it to select during if-conversion. No need to check if // the PHIs in this block are induction or reduction variables. if (*bb != Header) { // Check that this instruction has no outside users or is an // identified reduction value with an outside user. if (!hasOutsideLoopUser(TheLoop, &*it, AllowedExit)) continue; emitAnalysis(VectorizationReport(&*it) << "value could not be identified as " "an induction or reduction variable"); return false; } // We only allow if-converted PHIs with exactly two incoming values. if (Phi->getNumIncomingValues() != 2) { emitAnalysis(VectorizationReport(&*it) << "control flow not understood by vectorizer"); DEBUG(dbgs() << "LV: Found an invalid PHI.\n"); return false; } InductionDescriptor ID; if (InductionDescriptor::isInductionPHI(Phi, PSE.getSE(), ID)) { Inductions[Phi] = ID; // Get the widest type. if (!WidestIndTy) WidestIndTy = convertPointerToIntegerType(DL, PhiTy); else WidestIndTy = getWiderType(DL, PhiTy, WidestIndTy); // Int inductions are special because we only allow one IV. if (ID.getKind() == InductionDescriptor::IK_IntInduction && ID.getStepValue()->isOne() && isa(ID.getStartValue()) && cast(ID.getStartValue())->isNullValue()) { // Use the phi node with the widest type as induction. Use the last // one if there are multiple (no good reason for doing this other // than it is expedient). We've checked that it begins at zero and // steps by one, so this is a canonical induction variable. if (!Induction || PhiTy == WidestIndTy) Induction = Phi; } DEBUG(dbgs() << "LV: Found an induction variable.\n"); // Until we explicitly handle the case of an induction variable with // an outside loop user we have to give up vectorizing this loop. if (hasOutsideLoopUser(TheLoop, &*it, AllowedExit)) { emitAnalysis(VectorizationReport(&*it) << "use of induction value outside of the " "loop is not handled by vectorizer"); return false; } continue; } RecurrenceDescriptor RedDes; if (RecurrenceDescriptor::isReductionPHI(Phi, TheLoop, RedDes)) { if (RedDes.hasUnsafeAlgebra()) Requirements->addUnsafeAlgebraInst(RedDes.getUnsafeAlgebraInst()); AllowedExit.insert(RedDes.getLoopExitInstr()); Reductions[Phi] = RedDes; continue; } emitAnalysis(VectorizationReport(&*it) << "value that could not be identified as " "reduction is used outside the loop"); DEBUG(dbgs() << "LV: Found an unidentified PHI."<< *Phi <<"\n"); return false; }// end of PHI handling // We handle calls that: // * Are debug info intrinsics. // * Have a mapping to an IR intrinsic. // * Have a vector version available. CallInst *CI = dyn_cast(it); if (CI && !getIntrinsicIDForCall(CI, TLI) && !isa(CI) && !(CI->getCalledFunction() && TLI && TLI->isFunctionVectorizable(CI->getCalledFunction()->getName()))) { emitAnalysis(VectorizationReport(&*it) << "call instruction cannot be vectorized"); DEBUG(dbgs() << "LV: Found a non-intrinsic, non-libfunc callsite.\n"); return false; } // Intrinsics such as powi,cttz and ctlz are legal to vectorize if the // second argument is the same (i.e. loop invariant) if (CI && hasVectorInstrinsicScalarOpd(getIntrinsicIDForCall(CI, TLI), 1)) { auto *SE = PSE.getSE(); if (!SE->isLoopInvariant(PSE.getSCEV(CI->getOperand(1)), TheLoop)) { emitAnalysis(VectorizationReport(&*it) << "intrinsic instruction cannot be vectorized"); DEBUG(dbgs() << "LV: Found unvectorizable intrinsic " << *CI << "\n"); return false; } } // Check that the instruction return type is vectorizable. // Also, we can't vectorize extractelement instructions. if ((!VectorType::isValidElementType(it->getType()) && !it->getType()->isVoidTy()) || isa(it)) { emitAnalysis(VectorizationReport(&*it) << "instruction return type cannot be vectorized"); DEBUG(dbgs() << "LV: Found unvectorizable type.\n"); return false; } // Check that the stored type is vectorizable. if (StoreInst *ST = dyn_cast(it)) { Type *T = ST->getValueOperand()->getType(); if (!VectorType::isValidElementType(T)) { emitAnalysis(VectorizationReport(ST) << "store instruction cannot be vectorized"); return false; } if (EnableMemAccessVersioning) collectStridedAccess(ST); } if (EnableMemAccessVersioning) if (LoadInst *LI = dyn_cast(it)) collectStridedAccess(LI); // Reduction instructions are allowed to have exit users. // All other instructions must not have external users. if (hasOutsideLoopUser(TheLoop, &*it, AllowedExit)) { emitAnalysis(VectorizationReport(&*it) << "value cannot be used outside the loop"); return false; } } // next instr. } if (!Induction) { DEBUG(dbgs() << "LV: Did not find one integer induction var.\n"); if (Inductions.empty()) { emitAnalysis(VectorizationReport() << "loop induction variable could not be identified"); return false; } } // Now we know the widest induction type, check if our found induction // is the same size. If it's not, unset it here and InnerLoopVectorizer // will create another. if (Induction && WidestIndTy != Induction->getType()) Induction = nullptr; return true; } void LoopVectorizationLegality::collectStridedAccess(Value *MemAccess) { Value *Ptr = nullptr; if (LoadInst *LI = dyn_cast(MemAccess)) Ptr = LI->getPointerOperand(); else if (StoreInst *SI = dyn_cast(MemAccess)) Ptr = SI->getPointerOperand(); else return; Value *Stride = getStrideFromPointer(Ptr, PSE.getSE(), TheLoop); if (!Stride) return; DEBUG(dbgs() << "LV: Found a strided access that we can version"); DEBUG(dbgs() << " Ptr: " << *Ptr << " Stride: " << *Stride << "\n"); Strides[Ptr] = Stride; StrideSet.insert(Stride); } void LoopVectorizationLegality::collectLoopUniforms() { // We now know that the loop is vectorizable! // Collect variables that will remain uniform after vectorization. std::vector Worklist; BasicBlock *Latch = TheLoop->getLoopLatch(); // Start with the conditional branch and walk up the block. Worklist.push_back(Latch->getTerminator()->getOperand(0)); // Also add all consecutive pointer values; these values will be uniform // after vectorization (and subsequent cleanup) and, until revectorization is // supported, all dependencies must also be uniform. for (Loop::block_iterator B = TheLoop->block_begin(), BE = TheLoop->block_end(); B != BE; ++B) for (BasicBlock::iterator I = (*B)->begin(), IE = (*B)->end(); I != IE; ++I) if (I->getType()->isPointerTy() && isConsecutivePtr(&*I)) Worklist.insert(Worklist.end(), I->op_begin(), I->op_end()); while (!Worklist.empty()) { Instruction *I = dyn_cast(Worklist.back()); Worklist.pop_back(); // Look at instructions inside this loop. // Stop when reaching PHI nodes. // TODO: we need to follow values all over the loop, not only in this block. if (!I || !TheLoop->contains(I) || isa(I)) continue; // This is a known uniform. Uniforms.insert(I); // Insert all operands. Worklist.insert(Worklist.end(), I->op_begin(), I->op_end()); } } bool LoopVectorizationLegality::canVectorizeMemory() { LAI = &LAA->getInfo(TheLoop, Strides); auto &OptionalReport = LAI->getReport(); if (OptionalReport) emitAnalysis(VectorizationReport(*OptionalReport)); if (!LAI->canVectorizeMemory()) return false; if (LAI->hasStoreToLoopInvariantAddress()) { emitAnalysis( VectorizationReport() << "write to a loop invariant address could not be vectorized"); DEBUG(dbgs() << "LV: We don't allow storing to uniform addresses\n"); return false; } Requirements->addRuntimePointerChecks(LAI->getNumRuntimePointerChecks()); PSE.addPredicate(LAI->PSE.getUnionPredicate()); return true; } bool LoopVectorizationLegality::isInductionVariable(const Value *V) { Value *In0 = const_cast(V); PHINode *PN = dyn_cast_or_null(In0); if (!PN) return false; return Inductions.count(PN); } bool LoopVectorizationLegality::blockNeedsPredication(BasicBlock *BB) { return LoopAccessInfo::blockNeedsPredication(BB, TheLoop, DT); } bool LoopVectorizationLegality::blockCanBePredicated(BasicBlock *BB, SmallPtrSetImpl &SafePtrs) { for (BasicBlock::iterator it = BB->begin(), e = BB->end(); it != e; ++it) { // Check that we don't have a constant expression that can trap as operand. for (Instruction::op_iterator OI = it->op_begin(), OE = it->op_end(); OI != OE; ++OI) { if (Constant *C = dyn_cast(*OI)) if (C->canTrap()) return false; } // We might be able to hoist the load. if (it->mayReadFromMemory()) { LoadInst *LI = dyn_cast(it); if (!LI) return false; if (!SafePtrs.count(LI->getPointerOperand())) { if (isLegalMaskedLoad(LI->getType(), LI->getPointerOperand())) { MaskedOp.insert(LI); continue; } return false; } } // We don't predicate stores at the moment. if (it->mayWriteToMemory()) { StoreInst *SI = dyn_cast(it); // We only support predication of stores in basic blocks with one // predecessor. if (!SI) return false; bool isSafePtr = (SafePtrs.count(SI->getPointerOperand()) != 0); bool isSinglePredecessor = SI->getParent()->getSinglePredecessor(); if (++NumPredStores > NumberOfStoresToPredicate || !isSafePtr || !isSinglePredecessor) { // Build a masked store if it is legal for the target, otherwise // scalarize the block. bool isLegalMaskedOp = isLegalMaskedStore(SI->getValueOperand()->getType(), SI->getPointerOperand()); if (isLegalMaskedOp) { --NumPredStores; MaskedOp.insert(SI); continue; } return false; } } if (it->mayThrow()) return false; // The instructions below can trap. switch (it->getOpcode()) { default: continue; case Instruction::UDiv: case Instruction::SDiv: case Instruction::URem: case Instruction::SRem: return false; } } return true; } void InterleavedAccessInfo::collectConstStridedAccesses( MapVector &StrideAccesses, const ValueToValueMap &Strides) { // Holds load/store instructions in program order. SmallVector AccessList; for (auto *BB : TheLoop->getBlocks()) { bool IsPred = LoopAccessInfo::blockNeedsPredication(BB, TheLoop, DT); for (auto &I : *BB) { if (!isa(&I) && !isa(&I)) continue; // FIXME: Currently we can't handle mixed accesses and predicated accesses if (IsPred) return; AccessList.push_back(&I); } } if (AccessList.empty()) return; auto &DL = TheLoop->getHeader()->getModule()->getDataLayout(); for (auto I : AccessList) { LoadInst *LI = dyn_cast(I); StoreInst *SI = dyn_cast(I); Value *Ptr = LI ? LI->getPointerOperand() : SI->getPointerOperand(); int Stride = isStridedPtr(PSE, Ptr, TheLoop, Strides); // The factor of the corresponding interleave group. unsigned Factor = std::abs(Stride); // Ignore the access if the factor is too small or too large. if (Factor < 2 || Factor > MaxInterleaveGroupFactor) continue; const SCEV *Scev = replaceSymbolicStrideSCEV(PSE, Strides, Ptr); PointerType *PtrTy = dyn_cast(Ptr->getType()); unsigned Size = DL.getTypeAllocSize(PtrTy->getElementType()); // An alignment of 0 means target ABI alignment. unsigned Align = LI ? LI->getAlignment() : SI->getAlignment(); if (!Align) Align = DL.getABITypeAlignment(PtrTy->getElementType()); StrideAccesses[I] = StrideDescriptor(Stride, Scev, Size, Align); } } // Analyze interleaved accesses and collect them into interleave groups. // // Notice that the vectorization on interleaved groups will change instruction // orders and may break dependences. But the memory dependence check guarantees // that there is no overlap between two pointers of different strides, element // sizes or underlying bases. // // For pointers sharing the same stride, element size and underlying base, no // need to worry about Read-After-Write dependences and Write-After-Read // dependences. // // E.g. The RAW dependence: A[i] = a; // b = A[i]; // This won't exist as it is a store-load forwarding conflict, which has // already been checked and forbidden in the dependence check. // // E.g. The WAR dependence: a = A[i]; // (1) // A[i] = b; // (2) // The store group of (2) is always inserted at or below (2), and the load group // of (1) is always inserted at or above (1). The dependence is safe. void InterleavedAccessInfo::analyzeInterleaving( const ValueToValueMap &Strides) { DEBUG(dbgs() << "LV: Analyzing interleaved accesses...\n"); // Holds all the stride accesses. MapVector StrideAccesses; collectConstStridedAccesses(StrideAccesses, Strides); if (StrideAccesses.empty()) return; // Holds all interleaved store groups temporarily. SmallSetVector StoreGroups; + // Holds all interleaved load groups temporarily. + SmallSetVector LoadGroups; // Search the load-load/write-write pair B-A in bottom-up order and try to // insert B into the interleave group of A according to 3 rules: // 1. A and B have the same stride. // 2. A and B have the same memory object size. // 3. B belongs to the group according to the distance. // // The bottom-up order can avoid breaking the Write-After-Write dependences // between two pointers of the same base. // E.g. A[i] = a; (1) // A[i] = b; (2) // A[i+1] = c (3) // We form the group (2)+(3) in front, so (1) has to form groups with accesses // above (1), which guarantees that (1) is always above (2). for (auto I = StrideAccesses.rbegin(), E = StrideAccesses.rend(); I != E; ++I) { Instruction *A = I->first; StrideDescriptor DesA = I->second; InterleaveGroup *Group = getInterleaveGroup(A); if (!Group) { DEBUG(dbgs() << "LV: Creating an interleave group with:" << *A << '\n'); Group = createInterleaveGroup(A, DesA.Stride, DesA.Align); } if (A->mayWriteToMemory()) StoreGroups.insert(Group); + else + LoadGroups.insert(Group); for (auto II = std::next(I); II != E; ++II) { Instruction *B = II->first; StrideDescriptor DesB = II->second; // Ignore if B is already in a group or B is a different memory operation. if (isInterleaved(B) || A->mayReadFromMemory() != B->mayReadFromMemory()) continue; // Check the rule 1 and 2. if (DesB.Stride != DesA.Stride || DesB.Size != DesA.Size) continue; // Calculate the distance and prepare for the rule 3. const SCEVConstant *DistToA = dyn_cast( PSE.getSE()->getMinusSCEV(DesB.Scev, DesA.Scev)); if (!DistToA) continue; int DistanceToA = DistToA->getAPInt().getSExtValue(); // Skip if the distance is not multiple of size as they are not in the // same group. if (DistanceToA % static_cast(DesA.Size)) continue; // The index of B is the index of A plus the related index to A. int IndexB = Group->getIndex(A) + DistanceToA / static_cast(DesA.Size); // Try to insert B into the group. if (Group->insertMember(B, IndexB, DesB.Align)) { DEBUG(dbgs() << "LV: Inserted:" << *B << '\n' << " into the interleave group with" << *A << '\n'); InterleaveGroupMap[B] = Group; // Set the first load in program order as the insert position. if (B->mayReadFromMemory()) Group->setInsertPos(B); } } // Iteration on instruction B } // Iteration on instruction A // Remove interleaved store groups with gaps. for (InterleaveGroup *Group : StoreGroups) if (Group->getNumMembers() != Group->getFactor()) releaseGroup(Group); + + // Remove interleaved load groups that don't have the first and last member. + // This guarantees that we won't do speculative out of bounds loads. + for (InterleaveGroup *Group : LoadGroups) + if (!Group->getMember(0) || !Group->getMember(Group->getFactor() - 1)) + releaseGroup(Group); } LoopVectorizationCostModel::VectorizationFactor LoopVectorizationCostModel::selectVectorizationFactor(bool OptForSize) { // Width 1 means no vectorize VectorizationFactor Factor = { 1U, 0U }; if (OptForSize && Legal->getRuntimePointerChecking()->Need) { emitAnalysis(VectorizationReport() << "runtime pointer checks needed. Enable vectorization of this " "loop with '#pragma clang loop vectorize(enable)' when " "compiling with -Os/-Oz"); DEBUG(dbgs() << "LV: Aborting. Runtime ptr check is required with -Os/-Oz.\n"); return Factor; } if (!EnableCondStoresVectorization && Legal->getNumPredStores()) { emitAnalysis(VectorizationReport() << "store that is conditionally executed prevents vectorization"); DEBUG(dbgs() << "LV: No vectorization. There are conditional stores.\n"); return Factor; } // Find the trip count. - unsigned TC = PSE.getSE()->getSmallConstantTripCount(TheLoop); + unsigned TC = SE->getSmallConstantTripCount(TheLoop); DEBUG(dbgs() << "LV: Found trip count: " << TC << '\n'); MinBWs = computeMinimumValueSizes(TheLoop->getBlocks(), *DB, &TTI); unsigned SmallestType, WidestType; std::tie(SmallestType, WidestType) = getSmallestAndWidestTypes(); unsigned WidestRegister = TTI.getRegisterBitWidth(true); unsigned MaxSafeDepDist = -1U; if (Legal->getMaxSafeDepDistBytes() != -1U) MaxSafeDepDist = Legal->getMaxSafeDepDistBytes() * 8; WidestRegister = ((WidestRegister < MaxSafeDepDist) ? WidestRegister : MaxSafeDepDist); unsigned MaxVectorSize = WidestRegister / WidestType; DEBUG(dbgs() << "LV: The Smallest and Widest types: " << SmallestType << " / " << WidestType << " bits.\n"); DEBUG(dbgs() << "LV: The Widest register is: " << WidestRegister << " bits.\n"); if (MaxVectorSize == 0) { DEBUG(dbgs() << "LV: The target has no vector registers.\n"); MaxVectorSize = 1; } assert(MaxVectorSize <= 64 && "Did not expect to pack so many elements" " into one vector!"); unsigned VF = MaxVectorSize; if (MaximizeBandwidth && !OptForSize) { // Collect all viable vectorization factors. SmallVector VFs; unsigned NewMaxVectorSize = WidestRegister / SmallestType; for (unsigned VS = MaxVectorSize; VS <= NewMaxVectorSize; VS *= 2) VFs.push_back(VS); // For each VF calculate its register usage. auto RUs = calculateRegisterUsage(VFs); // Select the largest VF which doesn't require more registers than existing // ones. unsigned TargetNumRegisters = TTI.getNumberOfRegisters(true); for (int i = RUs.size() - 1; i >= 0; --i) { if (RUs[i].MaxLocalUsers <= TargetNumRegisters) { VF = VFs[i]; break; } } } // If we optimize the program for size, avoid creating the tail loop. if (OptForSize) { // If we are unable to calculate the trip count then don't try to vectorize. if (TC < 2) { emitAnalysis (VectorizationReport() << "unable to calculate the loop count due to complex control flow"); DEBUG(dbgs() << "LV: Aborting. A tail loop is required with -Os/-Oz.\n"); return Factor; } // Find the maximum SIMD width that can fit within the trip count. VF = TC % MaxVectorSize; if (VF == 0) VF = MaxVectorSize; else { // If the trip count that we found modulo the vectorization factor is not // zero then we require a tail. emitAnalysis(VectorizationReport() << "cannot optimize for size and vectorize at the " "same time. Enable vectorization of this loop " "with '#pragma clang loop vectorize(enable)' " "when compiling with -Os/-Oz"); DEBUG(dbgs() << "LV: Aborting. A tail loop is required with -Os/-Oz.\n"); return Factor; } } int UserVF = Hints->getWidth(); if (UserVF != 0) { assert(isPowerOf2_32(UserVF) && "VF needs to be a power of two"); DEBUG(dbgs() << "LV: Using user VF " << UserVF << ".\n"); Factor.Width = UserVF; return Factor; } float Cost = expectedCost(1); #ifndef NDEBUG const float ScalarCost = Cost; #endif /* NDEBUG */ unsigned Width = 1; DEBUG(dbgs() << "LV: Scalar loop costs: " << (int)ScalarCost << ".\n"); bool ForceVectorization = Hints->getForce() == LoopVectorizeHints::FK_Enabled; // Ignore scalar width, because the user explicitly wants vectorization. if (ForceVectorization && VF > 1) { Width = 2; Cost = expectedCost(Width) / (float)Width; } for (unsigned i=2; i <= VF; i*=2) { // Notice that the vector loop needs to be executed less times, so // we need to divide the cost of the vector loops by the width of // the vector elements. float VectorCost = expectedCost(i) / (float)i; DEBUG(dbgs() << "LV: Vector loop of width " << i << " costs: " << (int)VectorCost << ".\n"); if (VectorCost < Cost) { Cost = VectorCost; Width = i; } } DEBUG(if (ForceVectorization && Width > 1 && Cost >= ScalarCost) dbgs() << "LV: Vectorization seems to be not beneficial, " << "but was forced by a user.\n"); DEBUG(dbgs() << "LV: Selecting VF: "<< Width << ".\n"); Factor.Width = Width; Factor.Cost = Width * Cost; return Factor; } std::pair LoopVectorizationCostModel::getSmallestAndWidestTypes() { unsigned MinWidth = -1U; unsigned MaxWidth = 8; const DataLayout &DL = TheFunction->getParent()->getDataLayout(); // For each block. for (Loop::block_iterator bb = TheLoop->block_begin(), be = TheLoop->block_end(); bb != be; ++bb) { BasicBlock *BB = *bb; // For each instruction in the loop. for (BasicBlock::iterator it = BB->begin(), e = BB->end(); it != e; ++it) { Type *T = it->getType(); // Skip ignored values. if (ValuesToIgnore.count(&*it)) continue; // Only examine Loads, Stores and PHINodes. if (!isa(it) && !isa(it) && !isa(it)) continue; // Examine PHI nodes that are reduction variables. Update the type to // account for the recurrence type. if (PHINode *PN = dyn_cast(it)) { if (!Legal->isReductionVariable(PN)) continue; RecurrenceDescriptor RdxDesc = (*Legal->getReductionVars())[PN]; T = RdxDesc.getRecurrenceType(); } // Examine the stored values. if (StoreInst *ST = dyn_cast(it)) T = ST->getValueOperand()->getType(); // Ignore loaded pointer types and stored pointer types that are not // consecutive. However, we do want to take consecutive stores/loads of // pointer vectors into account. if (T->isPointerTy() && !isConsecutiveLoadOrStore(&*it)) continue; MinWidth = std::min(MinWidth, (unsigned)DL.getTypeSizeInBits(T->getScalarType())); MaxWidth = std::max(MaxWidth, (unsigned)DL.getTypeSizeInBits(T->getScalarType())); } } return {MinWidth, MaxWidth}; } unsigned LoopVectorizationCostModel::selectInterleaveCount(bool OptForSize, unsigned VF, unsigned LoopCost) { // -- The interleave heuristics -- // We interleave the loop in order to expose ILP and reduce the loop overhead. // There are many micro-architectural considerations that we can't predict // at this level. For example, frontend pressure (on decode or fetch) due to // code size, or the number and capabilities of the execution ports. // // We use the following heuristics to select the interleave count: // 1. If the code has reductions, then we interleave to break the cross // iteration dependency. // 2. If the loop is really small, then we interleave to reduce the loop // overhead. // 3. We don't interleave if we think that we will spill registers to memory // due to the increased register pressure. // When we optimize for size, we don't interleave. if (OptForSize) return 1; // We used the distance for the interleave count. if (Legal->getMaxSafeDepDistBytes() != -1U) return 1; // Do not interleave loops with a relatively small trip count. - unsigned TC = PSE.getSE()->getSmallConstantTripCount(TheLoop); + unsigned TC = SE->getSmallConstantTripCount(TheLoop); if (TC > 1 && TC < TinyTripCountInterleaveThreshold) return 1; unsigned TargetNumRegisters = TTI.getNumberOfRegisters(VF > 1); DEBUG(dbgs() << "LV: The target has " << TargetNumRegisters << " registers\n"); if (VF == 1) { if (ForceTargetNumScalarRegs.getNumOccurrences() > 0) TargetNumRegisters = ForceTargetNumScalarRegs; } else { if (ForceTargetNumVectorRegs.getNumOccurrences() > 0) TargetNumRegisters = ForceTargetNumVectorRegs; } RegisterUsage R = calculateRegisterUsage({VF})[0]; // We divide by these constants so assume that we have at least one // instruction that uses at least one register. R.MaxLocalUsers = std::max(R.MaxLocalUsers, 1U); R.NumInstructions = std::max(R.NumInstructions, 1U); // We calculate the interleave count using the following formula. // Subtract the number of loop invariants from the number of available // registers. These registers are used by all of the interleaved instances. // Next, divide the remaining registers by the number of registers that is // required by the loop, in order to estimate how many parallel instances // fit without causing spills. All of this is rounded down if necessary to be // a power of two. We want power of two interleave count to simplify any // addressing operations or alignment considerations. unsigned IC = PowerOf2Floor((TargetNumRegisters - R.LoopInvariantRegs) / R.MaxLocalUsers); // Don't count the induction variable as interleaved. if (EnableIndVarRegisterHeur) IC = PowerOf2Floor((TargetNumRegisters - R.LoopInvariantRegs - 1) / std::max(1U, (R.MaxLocalUsers - 1))); // Clamp the interleave ranges to reasonable counts. unsigned MaxInterleaveCount = TTI.getMaxInterleaveFactor(VF); // Check if the user has overridden the max. if (VF == 1) { if (ForceTargetMaxScalarInterleaveFactor.getNumOccurrences() > 0) MaxInterleaveCount = ForceTargetMaxScalarInterleaveFactor; } else { if (ForceTargetMaxVectorInterleaveFactor.getNumOccurrences() > 0) MaxInterleaveCount = ForceTargetMaxVectorInterleaveFactor; } // If we did not calculate the cost for VF (because the user selected the VF) // then we calculate the cost of VF here. if (LoopCost == 0) LoopCost = expectedCost(VF); // Clamp the calculated IC to be between the 1 and the max interleave count // that the target allows. if (IC > MaxInterleaveCount) IC = MaxInterleaveCount; else if (IC < 1) IC = 1; // Interleave if we vectorized this loop and there is a reduction that could // benefit from interleaving. if (VF > 1 && Legal->getReductionVars()->size()) { DEBUG(dbgs() << "LV: Interleaving because of reductions.\n"); return IC; } // Note that if we've already vectorized the loop we will have done the // runtime check and so interleaving won't require further checks. bool InterleavingRequiresRuntimePointerCheck = (VF == 1 && Legal->getRuntimePointerChecking()->Need); // We want to interleave small loops in order to reduce the loop overhead and // potentially expose ILP opportunities. DEBUG(dbgs() << "LV: Loop cost is " << LoopCost << '\n'); if (!InterleavingRequiresRuntimePointerCheck && LoopCost < SmallLoopCost) { // We assume that the cost overhead is 1 and we use the cost model // to estimate the cost of the loop and interleave until the cost of the // loop overhead is about 5% of the cost of the loop. unsigned SmallIC = std::min(IC, (unsigned)PowerOf2Floor(SmallLoopCost / LoopCost)); // Interleave until store/load ports (estimated by max interleave count) are // saturated. unsigned NumStores = Legal->getNumStores(); unsigned NumLoads = Legal->getNumLoads(); unsigned StoresIC = IC / (NumStores ? NumStores : 1); unsigned LoadsIC = IC / (NumLoads ? NumLoads : 1); // If we have a scalar reduction (vector reductions are already dealt with // by this point), we can increase the critical path length if the loop // we're interleaving is inside another loop. Limit, by default to 2, so the // critical path only gets increased by one reduction operation. if (Legal->getReductionVars()->size() && TheLoop->getLoopDepth() > 1) { unsigned F = static_cast(MaxNestedScalarReductionIC); SmallIC = std::min(SmallIC, F); StoresIC = std::min(StoresIC, F); LoadsIC = std::min(LoadsIC, F); } if (EnableLoadStoreRuntimeInterleave && std::max(StoresIC, LoadsIC) > SmallIC) { DEBUG(dbgs() << "LV: Interleaving to saturate store or load ports.\n"); return std::max(StoresIC, LoadsIC); } DEBUG(dbgs() << "LV: Interleaving to reduce branch cost.\n"); return SmallIC; } // Interleave if this is a large loop (small loops are already dealt with by // this point) that could benefit from interleaving. bool HasReductions = (Legal->getReductionVars()->size() > 0); if (TTI.enableAggressiveInterleaving(HasReductions)) { DEBUG(dbgs() << "LV: Interleaving to expose ILP.\n"); return IC; } DEBUG(dbgs() << "LV: Not Interleaving.\n"); return 1; } SmallVector LoopVectorizationCostModel::calculateRegisterUsage( const SmallVector &VFs) { // This function calculates the register usage by measuring the highest number // of values that are alive at a single location. Obviously, this is a very // rough estimation. We scan the loop in a topological order in order and // assign a number to each instruction. We use RPO to ensure that defs are // met before their users. We assume that each instruction that has in-loop // users starts an interval. We record every time that an in-loop value is // used, so we have a list of the first and last occurrences of each // instruction. Next, we transpose this data structure into a multi map that // holds the list of intervals that *end* at a specific location. This multi // map allows us to perform a linear search. We scan the instructions linearly // and record each time that a new interval starts, by placing it in a set. // If we find this value in the multi-map then we remove it from the set. // The max register usage is the maximum size of the set. // We also search for instructions that are defined outside the loop, but are // used inside the loop. We need this number separately from the max-interval // usage number because when we unroll, loop-invariant values do not take // more register. LoopBlocksDFS DFS(TheLoop); DFS.perform(LI); RegisterUsage RU; RU.NumInstructions = 0; // Each 'key' in the map opens a new interval. The values // of the map are the index of the 'last seen' usage of the // instruction that is the key. typedef DenseMap IntervalMap; // Maps instruction to its index. DenseMap IdxToInstr; // Marks the end of each interval. IntervalMap EndPoint; // Saves the list of instruction indices that are used in the loop. SmallSet Ends; // Saves the list of values that are used in the loop but are // defined outside the loop, such as arguments and constants. SmallPtrSet LoopInvariants; unsigned Index = 0; for (LoopBlocksDFS::RPOIterator bb = DFS.beginRPO(), be = DFS.endRPO(); bb != be; ++bb) { RU.NumInstructions += (*bb)->size(); for (Instruction &I : **bb) { IdxToInstr[Index++] = &I; // Save the end location of each USE. for (unsigned i = 0; i < I.getNumOperands(); ++i) { Value *U = I.getOperand(i); Instruction *Instr = dyn_cast(U); // Ignore non-instruction values such as arguments, constants, etc. if (!Instr) continue; // If this instruction is outside the loop then record it and continue. if (!TheLoop->contains(Instr)) { LoopInvariants.insert(Instr); continue; } // Overwrite previous end points. EndPoint[Instr] = Index; Ends.insert(Instr); } } } // Saves the list of intervals that end with the index in 'key'. typedef SmallVector InstrList; DenseMap TransposeEnds; // Transpose the EndPoints to a list of values that end at each index. for (IntervalMap::iterator it = EndPoint.begin(), e = EndPoint.end(); it != e; ++it) TransposeEnds[it->second].push_back(it->first); SmallSet OpenIntervals; // Get the size of the widest register. unsigned MaxSafeDepDist = -1U; if (Legal->getMaxSafeDepDistBytes() != -1U) MaxSafeDepDist = Legal->getMaxSafeDepDistBytes() * 8; unsigned WidestRegister = std::min(TTI.getRegisterBitWidth(true), MaxSafeDepDist); const DataLayout &DL = TheFunction->getParent()->getDataLayout(); SmallVector RUs(VFs.size()); SmallVector MaxUsages(VFs.size(), 0); DEBUG(dbgs() << "LV(REG): Calculating max register usage:\n"); // A lambda that gets the register usage for the given type and VF. auto GetRegUsage = [&DL, WidestRegister](Type *Ty, unsigned VF) { unsigned TypeSize = DL.getTypeSizeInBits(Ty->getScalarType()); return std::max(1, VF * TypeSize / WidestRegister); }; for (unsigned int i = 0; i < Index; ++i) { Instruction *I = IdxToInstr[i]; // Ignore instructions that are never used within the loop. if (!Ends.count(I)) continue; + // Skip ignored values. + if (ValuesToIgnore.count(I)) + continue; + // Remove all of the instructions that end at this location. InstrList &List = TransposeEnds[i]; for (unsigned int j = 0, e = List.size(); j < e; ++j) OpenIntervals.erase(List[j]); - // Skip ignored values. - if (ValuesToIgnore.count(I)) - continue; - // For each VF find the maximum usage of registers. for (unsigned j = 0, e = VFs.size(); j < e; ++j) { if (VFs[j] == 1) { MaxUsages[j] = std::max(MaxUsages[j], OpenIntervals.size()); continue; } // Count the number of live intervals. unsigned RegUsage = 0; - for (auto Inst : OpenIntervals) { - // Skip ignored values for VF > 1. - if (VecValuesToIgnore.count(Inst)) - continue; + for (auto Inst : OpenIntervals) RegUsage += GetRegUsage(Inst->getType(), VFs[j]); - } MaxUsages[j] = std::max(MaxUsages[j], RegUsage); } DEBUG(dbgs() << "LV(REG): At #" << i << " Interval # " << OpenIntervals.size() << '\n'); // Add the current instruction to the list of open intervals. OpenIntervals.insert(I); } for (unsigned i = 0, e = VFs.size(); i < e; ++i) { unsigned Invariant = 0; if (VFs[i] == 1) Invariant = LoopInvariants.size(); else { for (auto Inst : LoopInvariants) Invariant += GetRegUsage(Inst->getType(), VFs[i]); } DEBUG(dbgs() << "LV(REG): VF = " << VFs[i] << '\n'); DEBUG(dbgs() << "LV(REG): Found max usage: " << MaxUsages[i] << '\n'); DEBUG(dbgs() << "LV(REG): Found invariant usage: " << Invariant << '\n'); DEBUG(dbgs() << "LV(REG): LoopSize: " << RU.NumInstructions << '\n'); RU.LoopInvariantRegs = Invariant; RU.MaxLocalUsers = MaxUsages[i]; RUs[i] = RU; } return RUs; } unsigned LoopVectorizationCostModel::expectedCost(unsigned VF) { unsigned Cost = 0; // For each block. for (Loop::block_iterator bb = TheLoop->block_begin(), be = TheLoop->block_end(); bb != be; ++bb) { unsigned BlockCost = 0; BasicBlock *BB = *bb; // For each instruction in the old loop. for (BasicBlock::iterator it = BB->begin(), e = BB->end(); it != e; ++it) { // Skip dbg intrinsics. if (isa(it)) continue; // Skip ignored values. if (ValuesToIgnore.count(&*it)) continue; unsigned C = getInstructionCost(&*it, VF); // Check if we should override the cost. if (ForceTargetInstructionCost.getNumOccurrences() > 0) C = ForceTargetInstructionCost; BlockCost += C; DEBUG(dbgs() << "LV: Found an estimated cost of " << C << " for VF " << VF << " For instruction: " << *it << '\n'); } // We assume that if-converted blocks have a 50% chance of being executed. // When the code is scalar then some of the blocks are avoided due to CF. // When the code is vectorized we execute all code paths. if (VF == 1 && Legal->blockNeedsPredication(*bb)) BlockCost /= 2; Cost += BlockCost; } return Cost; } /// \brief Check whether the address computation for a non-consecutive memory /// access looks like an unlikely candidate for being merged into the indexing /// mode. /// /// We look for a GEP which has one index that is an induction variable and all /// other indices are loop invariant. If the stride of this access is also /// within a small bound we decide that this address computation can likely be /// merged into the addressing mode. /// In all other cases, we identify the address computation as complex. static bool isLikelyComplexAddressComputation(Value *Ptr, LoopVectorizationLegality *Legal, ScalarEvolution *SE, const Loop *TheLoop) { GetElementPtrInst *Gep = dyn_cast(Ptr); if (!Gep) return true; // We are looking for a gep with all loop invariant indices except for one // which should be an induction variable. unsigned NumOperands = Gep->getNumOperands(); for (unsigned i = 1; i < NumOperands; ++i) { Value *Opd = Gep->getOperand(i); if (!SE->isLoopInvariant(SE->getSCEV(Opd), TheLoop) && !Legal->isInductionVariable(Opd)) return true; } // Now we know we have a GEP ptr, %inv, %ind, %inv. Make sure that the step // can likely be merged into the address computation. unsigned MaxMergeDistance = 64; const SCEVAddRecExpr *AddRec = dyn_cast(SE->getSCEV(Ptr)); if (!AddRec) return true; // Check the step is constant. const SCEV *Step = AddRec->getStepRecurrence(*SE); // Calculate the pointer stride and check if it is consecutive. const SCEVConstant *C = dyn_cast(Step); if (!C) return true; const APInt &APStepVal = C->getAPInt(); // Huge step value - give up. if (APStepVal.getBitWidth() > 64) return true; int64_t StepVal = APStepVal.getSExtValue(); return StepVal > MaxMergeDistance; } static bool isStrideMul(Instruction *I, LoopVectorizationLegality *Legal) { return Legal->hasStride(I->getOperand(0)) || Legal->hasStride(I->getOperand(1)); } unsigned LoopVectorizationCostModel::getInstructionCost(Instruction *I, unsigned VF) { // If we know that this instruction will remain uniform, check the cost of // the scalar version. if (Legal->isUniformAfterVectorization(I)) VF = 1; Type *RetTy = I->getType(); if (VF > 1 && MinBWs.count(I)) RetTy = IntegerType::get(RetTy->getContext(), MinBWs[I]); Type *VectorTy = ToVectorTy(RetTy, VF); - auto SE = PSE.getSE(); // TODO: We need to estimate the cost of intrinsic calls. switch (I->getOpcode()) { case Instruction::GetElementPtr: // We mark this instruction as zero-cost because the cost of GEPs in // vectorized code depends on whether the corresponding memory instruction // is scalarized or not. Therefore, we handle GEPs with the memory // instruction cost. return 0; case Instruction::Br: { return TTI.getCFInstrCost(I->getOpcode()); } case Instruction::PHI: //TODO: IF-converted IFs become selects. return 0; case Instruction::Add: case Instruction::FAdd: case Instruction::Sub: case Instruction::FSub: case Instruction::Mul: case Instruction::FMul: case Instruction::UDiv: case Instruction::SDiv: case Instruction::FDiv: case Instruction::URem: case Instruction::SRem: case Instruction::FRem: case Instruction::Shl: case Instruction::LShr: case Instruction::AShr: case Instruction::And: case Instruction::Or: case Instruction::Xor: { // Since we will replace the stride by 1 the multiplication should go away. if (I->getOpcode() == Instruction::Mul && isStrideMul(I, Legal)) return 0; // Certain instructions can be cheaper to vectorize if they have a constant // second vector operand. One example of this are shifts on x86. TargetTransformInfo::OperandValueKind Op1VK = TargetTransformInfo::OK_AnyValue; TargetTransformInfo::OperandValueKind Op2VK = TargetTransformInfo::OK_AnyValue; TargetTransformInfo::OperandValueProperties Op1VP = TargetTransformInfo::OP_None; TargetTransformInfo::OperandValueProperties Op2VP = TargetTransformInfo::OP_None; Value *Op2 = I->getOperand(1); // Check for a splat of a constant or for a non uniform vector of constants. if (isa(Op2)) { ConstantInt *CInt = cast(Op2); if (CInt && CInt->getValue().isPowerOf2()) Op2VP = TargetTransformInfo::OP_PowerOf2; Op2VK = TargetTransformInfo::OK_UniformConstantValue; } else if (isa(Op2) || isa(Op2)) { Op2VK = TargetTransformInfo::OK_NonUniformConstantValue; Constant *SplatValue = cast(Op2)->getSplatValue(); if (SplatValue) { ConstantInt *CInt = dyn_cast(SplatValue); if (CInt && CInt->getValue().isPowerOf2()) Op2VP = TargetTransformInfo::OP_PowerOf2; Op2VK = TargetTransformInfo::OK_UniformConstantValue; } } return TTI.getArithmeticInstrCost(I->getOpcode(), VectorTy, Op1VK, Op2VK, Op1VP, Op2VP); } case Instruction::Select: { SelectInst *SI = cast(I); const SCEV *CondSCEV = SE->getSCEV(SI->getCondition()); bool ScalarCond = (SE->isLoopInvariant(CondSCEV, TheLoop)); Type *CondTy = SI->getCondition()->getType(); if (!ScalarCond) CondTy = VectorType::get(CondTy, VF); return TTI.getCmpSelInstrCost(I->getOpcode(), VectorTy, CondTy); } case Instruction::ICmp: case Instruction::FCmp: { Type *ValTy = I->getOperand(0)->getType(); Instruction *Op0AsInstruction = dyn_cast(I->getOperand(0)); auto It = MinBWs.find(Op0AsInstruction); if (VF > 1 && It != MinBWs.end()) ValTy = IntegerType::get(ValTy->getContext(), It->second); VectorTy = ToVectorTy(ValTy, VF); return TTI.getCmpSelInstrCost(I->getOpcode(), VectorTy); } case Instruction::Store: case Instruction::Load: { StoreInst *SI = dyn_cast(I); LoadInst *LI = dyn_cast(I); Type *ValTy = (SI ? SI->getValueOperand()->getType() : LI->getType()); VectorTy = ToVectorTy(ValTy, VF); unsigned Alignment = SI ? SI->getAlignment() : LI->getAlignment(); unsigned AS = SI ? SI->getPointerAddressSpace() : LI->getPointerAddressSpace(); Value *Ptr = SI ? SI->getPointerOperand() : LI->getPointerOperand(); // We add the cost of address computation here instead of with the gep // instruction because only here we know whether the operation is // scalarized. if (VF == 1) return TTI.getAddressComputationCost(VectorTy) + TTI.getMemoryOpCost(I->getOpcode(), VectorTy, Alignment, AS); // For an interleaved access, calculate the total cost of the whole // interleave group. if (Legal->isAccessInterleaved(I)) { auto Group = Legal->getInterleavedAccessGroup(I); assert(Group && "Fail to get an interleaved access group."); // Only calculate the cost once at the insert position. if (Group->getInsertPos() != I) return 0; unsigned InterleaveFactor = Group->getFactor(); Type *WideVecTy = VectorType::get(VectorTy->getVectorElementType(), VectorTy->getVectorNumElements() * InterleaveFactor); // Holds the indices of existing members in an interleaved load group. // An interleaved store group doesn't need this as it dones't allow gaps. SmallVector Indices; if (LI) { for (unsigned i = 0; i < InterleaveFactor; i++) if (Group->getMember(i)) Indices.push_back(i); } // Calculate the cost of the whole interleaved group. unsigned Cost = TTI.getInterleavedMemoryOpCost( I->getOpcode(), WideVecTy, Group->getFactor(), Indices, Group->getAlignment(), AS); if (Group->isReverse()) Cost += Group->getNumMembers() * TTI.getShuffleCost(TargetTransformInfo::SK_Reverse, VectorTy, 0); // FIXME: The interleaved load group with a huge gap could be even more // expensive than scalar operations. Then we could ignore such group and // use scalar operations instead. return Cost; } // Scalarized loads/stores. int ConsecutiveStride = Legal->isConsecutivePtr(Ptr); bool Reverse = ConsecutiveStride < 0; const DataLayout &DL = I->getModule()->getDataLayout(); unsigned ScalarAllocatedSize = DL.getTypeAllocSize(ValTy); unsigned VectorElementSize = DL.getTypeStoreSize(VectorTy) / VF; if (!ConsecutiveStride || ScalarAllocatedSize != VectorElementSize) { bool IsComplexComputation = isLikelyComplexAddressComputation(Ptr, Legal, SE, TheLoop); unsigned Cost = 0; // The cost of extracting from the value vector and pointer vector. Type *PtrTy = ToVectorTy(Ptr->getType(), VF); for (unsigned i = 0; i < VF; ++i) { // The cost of extracting the pointer operand. Cost += TTI.getVectorInstrCost(Instruction::ExtractElement, PtrTy, i); // In case of STORE, the cost of ExtractElement from the vector. // In case of LOAD, the cost of InsertElement into the returned // vector. Cost += TTI.getVectorInstrCost(SI ? Instruction::ExtractElement : Instruction::InsertElement, VectorTy, i); } // The cost of the scalar loads/stores. Cost += VF * TTI.getAddressComputationCost(PtrTy, IsComplexComputation); Cost += VF * TTI.getMemoryOpCost(I->getOpcode(), ValTy->getScalarType(), Alignment, AS); return Cost; } // Wide load/stores. unsigned Cost = TTI.getAddressComputationCost(VectorTy); if (Legal->isMaskRequired(I)) Cost += TTI.getMaskedMemoryOpCost(I->getOpcode(), VectorTy, Alignment, AS); else Cost += TTI.getMemoryOpCost(I->getOpcode(), VectorTy, Alignment, AS); if (Reverse) Cost += TTI.getShuffleCost(TargetTransformInfo::SK_Reverse, VectorTy, 0); return Cost; } case Instruction::ZExt: case Instruction::SExt: case Instruction::FPToUI: case Instruction::FPToSI: case Instruction::FPExt: case Instruction::PtrToInt: case Instruction::IntToPtr: case Instruction::SIToFP: case Instruction::UIToFP: case Instruction::Trunc: case Instruction::FPTrunc: case Instruction::BitCast: { // We optimize the truncation of induction variable. // The cost of these is the same as the scalar operation. if (I->getOpcode() == Instruction::Trunc && Legal->isInductionVariable(I->getOperand(0))) return TTI.getCastInstrCost(I->getOpcode(), I->getType(), I->getOperand(0)->getType()); Type *SrcScalarTy = I->getOperand(0)->getType(); Type *SrcVecTy = ToVectorTy(SrcScalarTy, VF); if (VF > 1 && MinBWs.count(I)) { // This cast is going to be shrunk. This may remove the cast or it might // turn it into slightly different cast. For example, if MinBW == 16, // "zext i8 %1 to i32" becomes "zext i8 %1 to i16". // // Calculate the modified src and dest types. Type *MinVecTy = VectorTy; if (I->getOpcode() == Instruction::Trunc) { SrcVecTy = smallestIntegerVectorType(SrcVecTy, MinVecTy); VectorTy = largestIntegerVectorType(ToVectorTy(I->getType(), VF), MinVecTy); } else if (I->getOpcode() == Instruction::ZExt || I->getOpcode() == Instruction::SExt) { SrcVecTy = largestIntegerVectorType(SrcVecTy, MinVecTy); VectorTy = smallestIntegerVectorType(ToVectorTy(I->getType(), VF), MinVecTy); } } return TTI.getCastInstrCost(I->getOpcode(), VectorTy, SrcVecTy); } case Instruction::Call: { bool NeedToScalarize; CallInst *CI = cast(I); unsigned CallCost = getVectorCallCost(CI, VF, TTI, TLI, NeedToScalarize); if (getIntrinsicIDForCall(CI, TLI)) return std::min(CallCost, getVectorIntrinsicCost(CI, VF, TTI, TLI)); return CallCost; } default: { // We are scalarizing the instruction. Return the cost of the scalar // instruction, plus the cost of insert and extract into vector // elements, times the vector width. unsigned Cost = 0; if (!RetTy->isVoidTy() && VF != 1) { unsigned InsCost = TTI.getVectorInstrCost(Instruction::InsertElement, VectorTy); unsigned ExtCost = TTI.getVectorInstrCost(Instruction::ExtractElement, VectorTy); // The cost of inserting the results plus extracting each one of the // operands. Cost += VF * (InsCost + ExtCost * I->getNumOperands()); } // The cost of executing VF copies of the scalar instruction. This opcode // is unknown. Assume that it is the same as 'mul'. Cost += VF * TTI.getArithmeticInstrCost(Instruction::Mul, VectorTy); return Cost; } }// end of switch. } char LoopVectorize::ID = 0; static const char lv_name[] = "Loop Vectorization"; INITIALIZE_PASS_BEGIN(LoopVectorize, LV_NAME, lv_name, false, false) INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(BasicAAWrapperPass) INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) INITIALIZE_PASS_DEPENDENCY(GlobalsAAWrapperPass) INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass) INITIALIZE_PASS_DEPENDENCY(LCSSA) INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(LoopSimplify) INITIALIZE_PASS_DEPENDENCY(LoopAccessAnalysis) INITIALIZE_PASS_DEPENDENCY(DemandedBits) INITIALIZE_PASS_END(LoopVectorize, LV_NAME, lv_name, false, false) namespace llvm { Pass *createLoopVectorizePass(bool NoUnrolling, bool AlwaysVectorize) { return new LoopVectorize(NoUnrolling, AlwaysVectorize); } } bool LoopVectorizationCostModel::isConsecutiveLoadOrStore(Instruction *Inst) { // Check for a store. if (StoreInst *ST = dyn_cast(Inst)) return Legal->isConsecutivePtr(ST->getPointerOperand()) != 0; // Check for a load. if (LoadInst *LI = dyn_cast(Inst)) return Legal->isConsecutivePtr(LI->getPointerOperand()) != 0; return false; } -void LoopVectorizationCostModel::collectValuesToIgnore() { - // Ignore ephemeral values. - CodeMetrics::collectEphemeralValues(TheLoop, AC, ValuesToIgnore); - - // Ignore type-promoting instructions we identified during reduction - // detection. - for (auto &Reduction : *Legal->getReductionVars()) { - RecurrenceDescriptor &RedDes = Reduction.second; - SmallPtrSetImpl &Casts = RedDes.getCastInsts(); - VecValuesToIgnore.insert(Casts.begin(), Casts.end()); - } - - // Ignore induction phis that are only used in either GetElementPtr or ICmp - // instruction to exit loop. Induction variables usually have large types and - // can have big impact when estimating register usage. - // This is for when VF > 1. - for (auto &Induction : *Legal->getInductionVars()) { - auto *PN = Induction.first; - auto *UpdateV = PN->getIncomingValueForBlock(TheLoop->getLoopLatch()); - - // Check that the PHI is only used by the induction increment (UpdateV) or - // by GEPs. Then check that UpdateV is only used by a compare instruction or - // the loop header PHI. - // FIXME: Need precise def-use analysis to determine if this instruction - // variable will be vectorized. - if (std::all_of(PN->user_begin(), PN->user_end(), - [&](const User *U) -> bool { - return U == UpdateV || isa(U); - }) && - std::all_of(UpdateV->user_begin(), UpdateV->user_end(), - [&](const User *U) -> bool { - return U == PN || isa(U); - })) { - VecValuesToIgnore.insert(PN); - VecValuesToIgnore.insert(UpdateV); - } - } - - // Ignore instructions that will not be vectorized. - // This is for when VF > 1. - for (auto bb = TheLoop->block_begin(), be = TheLoop->block_end(); bb != be; - ++bb) { - for (auto &Inst : **bb) { - switch (Inst.getOpcode()) { - case Instruction::GetElementPtr: { - // Ignore GEP if its last operand is an induction variable so that it is - // a consecutive load/store and won't be vectorized as scatter/gather - // pattern. - - GetElementPtrInst *Gep = cast(&Inst); - unsigned NumOperands = Gep->getNumOperands(); - unsigned InductionOperand = getGEPInductionOperand(Gep); - bool GepToIgnore = true; - - // Check that all of the gep indices are uniform except for the - // induction operand. - for (unsigned i = 0; i != NumOperands; ++i) { - if (i != InductionOperand && - !PSE.getSE()->isLoopInvariant(PSE.getSCEV(Gep->getOperand(i)), - TheLoop)) { - GepToIgnore = false; - break; - } - } - - if (GepToIgnore) - VecValuesToIgnore.insert(&Inst); - break; - } - } - } - } -} void InnerLoopUnroller::scalarizeInstruction(Instruction *Instr, bool IfPredicateStore) { assert(!Instr->getType()->isAggregateType() && "Can't handle vectors"); // Holds vector parameters or scalars, in case of uniform vals. SmallVector Params; setDebugLocFromInst(Builder, Instr); // Find all of the vectorized parameters. for (unsigned op = 0, e = Instr->getNumOperands(); op != e; ++op) { Value *SrcOp = Instr->getOperand(op); // If we are accessing the old induction variable, use the new one. if (SrcOp == OldInduction) { Params.push_back(getVectorValue(SrcOp)); continue; } // Try using previously calculated values. Instruction *SrcInst = dyn_cast(SrcOp); // If the src is an instruction that appeared earlier in the basic block // then it should already be vectorized. if (SrcInst && OrigLoop->contains(SrcInst)) { assert(WidenMap.has(SrcInst) && "Source operand is unavailable"); // The parameter is a vector value from earlier. Params.push_back(WidenMap.get(SrcInst)); } else { // The parameter is a scalar from outside the loop. Maybe even a constant. VectorParts Scalars; Scalars.append(UF, SrcOp); Params.push_back(Scalars); } } assert(Params.size() == Instr->getNumOperands() && "Invalid number of operands"); // Does this instruction return a value ? bool IsVoidRetTy = Instr->getType()->isVoidTy(); Value *UndefVec = IsVoidRetTy ? nullptr : UndefValue::get(Instr->getType()); // Create a new entry in the WidenMap and initialize it to Undef or Null. VectorParts &VecResults = WidenMap.splat(Instr, UndefVec); VectorParts Cond; if (IfPredicateStore) { assert(Instr->getParent()->getSinglePredecessor() && "Only support single predecessor blocks"); Cond = createEdgeMask(Instr->getParent()->getSinglePredecessor(), Instr->getParent()); } // For each vector unroll 'part': for (unsigned Part = 0; Part < UF; ++Part) { // For each scalar that we create: // Start an "if (pred) a[i] = ..." block. Value *Cmp = nullptr; if (IfPredicateStore) { if (Cond[Part]->getType()->isVectorTy()) Cond[Part] = Builder.CreateExtractElement(Cond[Part], Builder.getInt32(0)); Cmp = Builder.CreateICmp(ICmpInst::ICMP_EQ, Cond[Part], ConstantInt::get(Cond[Part]->getType(), 1)); } Instruction *Cloned = Instr->clone(); if (!IsVoidRetTy) Cloned->setName(Instr->getName() + ".cloned"); // Replace the operands of the cloned instructions with extracted scalars. for (unsigned op = 0, e = Instr->getNumOperands(); op != e; ++op) { Value *Op = Params[op][Part]; Cloned->setOperand(op, Op); } // Place the cloned scalar in the new loop. Builder.Insert(Cloned); // If the original scalar returns a value we need to place it in a vector // so that future users will be able to use it. if (!IsVoidRetTy) VecResults[Part] = Cloned; // End if-block. if (IfPredicateStore) PredicatedStores.push_back(std::make_pair(cast(Cloned), Cmp)); } } void InnerLoopUnroller::vectorizeMemoryInstruction(Instruction *Instr) { StoreInst *SI = dyn_cast(Instr); bool IfPredicateStore = (SI && Legal->blockNeedsPredication(SI->getParent())); return scalarizeInstruction(Instr, IfPredicateStore); } Value *InnerLoopUnroller::reverseVector(Value *Vec) { return Vec; } Value *InnerLoopUnroller::getBroadcastInstrs(Value *V) { return V; } Value *InnerLoopUnroller::getStepVector(Value *Val, int StartIdx, Value *Step) { // When unrolling and the VF is 1, we only need to add a simple scalar. Type *ITy = Val->getType(); assert(!ITy->isVectorTy() && "Val must be a scalar"); Constant *C = ConstantInt::get(ITy, StartIdx); return Builder.CreateAdd(Val, Builder.CreateMul(C, Step), "induction"); } Index: projects/clang380-import/contrib/llvm/tools/clang/lib/Basic/Targets.cpp =================================================================== --- projects/clang380-import/contrib/llvm/tools/clang/lib/Basic/Targets.cpp (revision 295858) +++ projects/clang380-import/contrib/llvm/tools/clang/lib/Basic/Targets.cpp (revision 295859) @@ -1,7986 +1,7986 @@ //===--- Targets.cpp - Implement target feature support -------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements construction of a TargetInfo object from a // target triple. // //===----------------------------------------------------------------------===// #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/MacroBuilder.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetOptions.h" #include "clang/Basic/Version.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TargetParser.h" #include #include using namespace clang; //===----------------------------------------------------------------------===// // Common code shared among targets. //===----------------------------------------------------------------------===// /// DefineStd - Define a macro name and standard variants. For example if /// MacroName is "unix", then this will define "__unix", "__unix__", and "unix" /// when in GNU mode. static void DefineStd(MacroBuilder &Builder, StringRef MacroName, const LangOptions &Opts) { assert(MacroName[0] != '_' && "Identifier should be in the user's namespace"); // If in GNU mode (e.g. -std=gnu99 but not -std=c99) define the raw identifier // in the user's namespace. if (Opts.GNUMode) Builder.defineMacro(MacroName); // Define __unix. Builder.defineMacro("__" + MacroName); // Define __unix__. Builder.defineMacro("__" + MacroName + "__"); } static void defineCPUMacros(MacroBuilder &Builder, StringRef CPUName, bool Tuning = true) { Builder.defineMacro("__" + CPUName); Builder.defineMacro("__" + CPUName + "__"); if (Tuning) Builder.defineMacro("__tune_" + CPUName + "__"); } //===----------------------------------------------------------------------===// // Defines specific to certain operating systems. //===----------------------------------------------------------------------===// namespace { template class OSTargetInfo : public TgtInfo { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const=0; public: OSTargetInfo(const llvm::Triple &Triple) : TgtInfo(Triple) {} void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { TgtInfo::getTargetDefines(Opts, Builder); getOSDefines(Opts, TgtInfo::getTriple(), Builder); } }; // CloudABI Target template class CloudABITargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { Builder.defineMacro("__CloudABI__"); Builder.defineMacro("__ELF__"); // CloudABI uses ISO/IEC 10646:2012 for wchar_t, char16_t and char32_t. Builder.defineMacro("__STDC_ISO_10646__", "201206L"); Builder.defineMacro("__STDC_UTF_16__"); Builder.defineMacro("__STDC_UTF_32__"); } public: CloudABITargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) { this->UserLabelPrefix = ""; } }; static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, const llvm::Triple &Triple, StringRef &PlatformName, VersionTuple &PlatformMinVersion) { Builder.defineMacro("__APPLE_CC__", "6000"); Builder.defineMacro("__APPLE__"); Builder.defineMacro("OBJC_NEW_PROPERTIES"); // AddressSanitizer doesn't play well with source fortification, which is on // by default on Darwin. if (Opts.Sanitize.has(SanitizerKind::Address)) Builder.defineMacro("_FORTIFY_SOURCE", "0"); // Darwin defines __weak, __strong, and __unsafe_unretained even in C mode. if (!Opts.ObjC1) { // __weak is always defined, for use in blocks and with objc pointers. Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))"); Builder.defineMacro("__strong", ""); Builder.defineMacro("__unsafe_unretained", ""); } if (Opts.Static) Builder.defineMacro("__STATIC__"); else Builder.defineMacro("__DYNAMIC__"); if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); // Get the platform type and version number from the triple. unsigned Maj, Min, Rev; if (Triple.isMacOSX()) { Triple.getMacOSXVersion(Maj, Min, Rev); PlatformName = "macosx"; } else { Triple.getOSVersion(Maj, Min, Rev); PlatformName = llvm::Triple::getOSTypeName(Triple.getOS()); } // If -target arch-pc-win32-macho option specified, we're // generating code for Win32 ABI. No need to emit // __ENVIRONMENT_XX_OS_VERSION_MIN_REQUIRED__. if (PlatformName == "win32") { PlatformMinVersion = VersionTuple(Maj, Min, Rev); return; } // Set the appropriate OS version define. if (Triple.isiOS()) { assert(Maj < 10 && Min < 100 && Rev < 100 && "Invalid version!"); char Str[6]; Str[0] = '0' + Maj; Str[1] = '0' + (Min / 10); Str[2] = '0' + (Min % 10); Str[3] = '0' + (Rev / 10); Str[4] = '0' + (Rev % 10); Str[5] = '\0'; if (Triple.isTvOS()) Builder.defineMacro("__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__", Str); else Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", Str); } else if (Triple.isWatchOS()) { assert(Maj < 10 && Min < 100 && Rev < 100 && "Invalid version!"); char Str[6]; Str[0] = '0' + Maj; Str[1] = '0' + (Min / 10); Str[2] = '0' + (Min % 10); Str[3] = '0' + (Rev / 10); Str[4] = '0' + (Rev % 10); Str[5] = '\0'; Builder.defineMacro("__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__", Str); } else if (Triple.isMacOSX()) { // Note that the Driver allows versions which aren't representable in the // define (because we only get a single digit for the minor and micro // revision numbers). So, we limit them to the maximum representable // version. assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!"); char Str[7]; if (Maj < 10 || (Maj == 10 && Min < 10)) { Str[0] = '0' + (Maj / 10); Str[1] = '0' + (Maj % 10); Str[2] = '0' + std::min(Min, 9U); Str[3] = '0' + std::min(Rev, 9U); Str[4] = '\0'; } else { // Handle versions > 10.9. Str[0] = '0' + (Maj / 10); Str[1] = '0' + (Maj % 10); Str[2] = '0' + (Min / 10); Str[3] = '0' + (Min % 10); Str[4] = '0' + (Rev / 10); Str[5] = '0' + (Rev % 10); Str[6] = '\0'; } Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str); } // Tell users about the kernel if there is one. if (Triple.isOSDarwin()) Builder.defineMacro("__MACH__"); PlatformMinVersion = VersionTuple(Maj, Min, Rev); } template class DarwinTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { getDarwinDefines(Builder, Opts, Triple, this->PlatformName, this->PlatformMinVersion); } public: DarwinTargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) { // By default, no TLS, and we whitelist permitted architecture/OS // combinations. this->TLSSupported = false; if (Triple.isMacOSX()) this->TLSSupported = !Triple.isMacOSXVersionLT(10, 7); else if (Triple.isiOS()) { // 64-bit iOS supported it from 8 onwards, 32-bit from 9 onwards. if (Triple.getArch() == llvm::Triple::x86_64 || Triple.getArch() == llvm::Triple::aarch64) this->TLSSupported = !Triple.isOSVersionLT(8); else if (Triple.getArch() == llvm::Triple::x86 || Triple.getArch() == llvm::Triple::arm || Triple.getArch() == llvm::Triple::thumb) this->TLSSupported = !Triple.isOSVersionLT(9); } else if (Triple.isWatchOS()) this->TLSSupported = !Triple.isOSVersionLT(2); this->MCountName = "\01mcount"; } std::string isValidSectionSpecifier(StringRef SR) const override { // Let MCSectionMachO validate this. StringRef Segment, Section; unsigned TAA, StubSize; bool HasTAA; return llvm::MCSectionMachO::ParseSectionSpecifier(SR, Segment, Section, TAA, HasTAA, StubSize); } const char *getStaticInitSectionSpecifier() const override { // FIXME: We should return 0 when building kexts. return "__TEXT,__StaticInit,regular,pure_instructions"; } /// Darwin does not support protected visibility. Darwin's "default" /// is very similar to ELF's "protected"; Darwin requires a "weak" /// attribute on declarations that can be dynamically replaced. bool hasProtectedVisibility() const override { return false; } }; // DragonFlyBSD Target template class DragonFlyBSDTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // DragonFly defines; list based off of gcc output Builder.defineMacro("__DragonFly__"); Builder.defineMacro("__DragonFly_cc_version", "100001"); Builder.defineMacro("__ELF__"); Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); Builder.defineMacro("__tune_i386__"); DefineStd(Builder, "unix", Opts); } public: DragonFlyBSDTargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) { this->UserLabelPrefix = ""; switch (Triple.getArch()) { default: case llvm::Triple::x86: case llvm::Triple::x86_64: this->MCountName = ".mcount"; break; } } }; // FreeBSD Target template class FreeBSDTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // FreeBSD defines; list based off of gcc output unsigned Release = Triple.getOSMajorVersion(); if (Release == 0U) Release = 8; Builder.defineMacro("__FreeBSD__", Twine(Release)); Builder.defineMacro("__FreeBSD_cc_version", Twine(Release * 100000U + 1U)); Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); DefineStd(Builder, "unix", Opts); Builder.defineMacro("__ELF__"); // On FreeBSD, wchar_t contains the number of the code point as // used by the character set of the locale. These character sets are // not necessarily a superset of ASCII. // // FIXME: This is wrong; the macro refers to the numerical values // of wchar_t *literals*, which are not locale-dependent. However, // FreeBSD systems apparently depend on us getting this wrong, and // setting this to 1 is conforming even if all the basic source // character literals have the same encoding as char and wchar_t. Builder.defineMacro("__STDC_MB_MIGHT_NEQ_WC__", "1"); } public: FreeBSDTargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) { this->UserLabelPrefix = ""; switch (Triple.getArch()) { default: case llvm::Triple::x86: case llvm::Triple::x86_64: this->MCountName = ".mcount"; break; case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: this->MCountName = "_mcount"; break; case llvm::Triple::arm: this->MCountName = "__mcount"; break; } } }; // GNU/kFreeBSD Target template class KFreeBSDTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // GNU/kFreeBSD defines; list based off of gcc output DefineStd(Builder, "unix", Opts); Builder.defineMacro("__FreeBSD_kernel__"); Builder.defineMacro("__GLIBC__"); Builder.defineMacro("__ELF__"); if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); if (Opts.CPlusPlus) Builder.defineMacro("_GNU_SOURCE"); } public: KFreeBSDTargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) { this->UserLabelPrefix = ""; } }; // Minix Target template class MinixTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // Minix defines Builder.defineMacro("__minix", "3"); Builder.defineMacro("_EM_WSIZE", "4"); Builder.defineMacro("_EM_PSIZE", "4"); Builder.defineMacro("_EM_SSIZE", "2"); Builder.defineMacro("_EM_LSIZE", "4"); Builder.defineMacro("_EM_FSIZE", "4"); Builder.defineMacro("_EM_DSIZE", "8"); Builder.defineMacro("__ELF__"); DefineStd(Builder, "unix", Opts); } public: MinixTargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) { this->UserLabelPrefix = ""; } }; // Linux target template class LinuxTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // Linux defines; list based off of gcc output DefineStd(Builder, "unix", Opts); DefineStd(Builder, "linux", Opts); Builder.defineMacro("__gnu_linux__"); Builder.defineMacro("__ELF__"); if (Triple.isAndroid()) { Builder.defineMacro("__ANDROID__", "1"); unsigned Maj, Min, Rev; Triple.getEnvironmentVersion(Maj, Min, Rev); this->PlatformName = "android"; this->PlatformMinVersion = VersionTuple(Maj, Min, Rev); } if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); if (Opts.CPlusPlus) Builder.defineMacro("_GNU_SOURCE"); } public: LinuxTargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) { this->UserLabelPrefix = ""; this->WIntType = TargetInfo::UnsignedInt; switch (Triple.getArch()) { default: break; case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: this->MCountName = "_mcount"; break; } } const char *getStaticInitSectionSpecifier() const override { return ".text.startup"; } }; // NetBSD Target template class NetBSDTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // NetBSD defines; list based off of gcc output Builder.defineMacro("__NetBSD__"); Builder.defineMacro("__unix__"); Builder.defineMacro("__ELF__"); if (Opts.POSIXThreads) Builder.defineMacro("_POSIX_THREADS"); switch (Triple.getArch()) { default: break; case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: Builder.defineMacro("__ARM_DWARF_EH__"); break; } } public: NetBSDTargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) { this->UserLabelPrefix = ""; this->MCountName = "_mcount"; } }; // OpenBSD Target template class OpenBSDTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // OpenBSD defines; list based off of gcc output Builder.defineMacro("__OpenBSD__"); DefineStd(Builder, "unix", Opts); Builder.defineMacro("__ELF__"); if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); } public: OpenBSDTargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) { this->UserLabelPrefix = ""; this->TLSSupported = false; switch (Triple.getArch()) { default: case llvm::Triple::x86: case llvm::Triple::x86_64: case llvm::Triple::arm: case llvm::Triple::sparc: this->MCountName = "__mcount"; break; case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::ppc: case llvm::Triple::sparcv9: this->MCountName = "_mcount"; break; } } }; // Bitrig Target template class BitrigTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // Bitrig defines; list based off of gcc output Builder.defineMacro("__Bitrig__"); DefineStd(Builder, "unix", Opts); Builder.defineMacro("__ELF__"); if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); switch (Triple.getArch()) { default: break; case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: Builder.defineMacro("__ARM_DWARF_EH__"); break; } } public: BitrigTargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) { this->UserLabelPrefix = ""; this->MCountName = "__mcount"; } }; // PSP Target template class PSPTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // PSP defines; list based on the output of the pspdev gcc toolchain. Builder.defineMacro("PSP"); Builder.defineMacro("_PSP"); Builder.defineMacro("__psp__"); Builder.defineMacro("__ELF__"); } public: PSPTargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) { this->UserLabelPrefix = ""; } }; // PS3 PPU Target template class PS3PPUTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // PS3 PPU defines. Builder.defineMacro("__PPC__"); Builder.defineMacro("__PPU__"); Builder.defineMacro("__CELLOS_LV2__"); Builder.defineMacro("__ELF__"); Builder.defineMacro("__LP32__"); Builder.defineMacro("_ARCH_PPC64"); Builder.defineMacro("__powerpc64__"); } public: PS3PPUTargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) { this->UserLabelPrefix = ""; this->LongWidth = this->LongAlign = 32; this->PointerWidth = this->PointerAlign = 32; this->IntMaxType = TargetInfo::SignedLongLong; this->Int64Type = TargetInfo::SignedLongLong; this->SizeType = TargetInfo::UnsignedInt; this->DataLayoutString = "E-m:e-p:32:32-i64:64-n32:64"; } }; template class PS4OSTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { Builder.defineMacro("__FreeBSD__", "9"); Builder.defineMacro("__FreeBSD_cc_version", "900001"); Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); DefineStd(Builder, "unix", Opts); Builder.defineMacro("__ELF__"); Builder.defineMacro("__PS4__"); } public: PS4OSTargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) { this->WCharType = this->UnsignedShort; // On PS4, TLS variable cannot be aligned to more than 32 bytes (256 bits). this->MaxTLSAlign = 256; this->UserLabelPrefix = ""; switch (Triple.getArch()) { default: case llvm::Triple::x86_64: this->MCountName = ".mcount"; break; } } }; // Solaris target template class SolarisTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { DefineStd(Builder, "sun", Opts); DefineStd(Builder, "unix", Opts); Builder.defineMacro("__ELF__"); Builder.defineMacro("__svr4__"); Builder.defineMacro("__SVR4"); // Solaris headers require _XOPEN_SOURCE to be set to 600 for C99 and // newer, but to 500 for everything else. feature_test.h has a check to // ensure that you are not using C99 with an old version of X/Open or C89 // with a new version. if (Opts.C99) Builder.defineMacro("_XOPEN_SOURCE", "600"); else Builder.defineMacro("_XOPEN_SOURCE", "500"); if (Opts.CPlusPlus) Builder.defineMacro("__C99FEATURES__"); Builder.defineMacro("_LARGEFILE_SOURCE"); Builder.defineMacro("_LARGEFILE64_SOURCE"); Builder.defineMacro("__EXTENSIONS__"); Builder.defineMacro("_REENTRANT"); } public: SolarisTargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) { this->UserLabelPrefix = ""; this->WCharType = this->SignedInt; // FIXME: WIntType should be SignedLong } }; // Windows target template class WindowsTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { Builder.defineMacro("_WIN32"); } void getVisualStudioDefines(const LangOptions &Opts, MacroBuilder &Builder) const { if (Opts.CPlusPlus) { if (Opts.RTTIData) Builder.defineMacro("_CPPRTTI"); if (Opts.CXXExceptions) Builder.defineMacro("_CPPUNWIND"); } if (Opts.Bool) Builder.defineMacro("__BOOL_DEFINED"); if (!Opts.CharIsSigned) Builder.defineMacro("_CHAR_UNSIGNED"); // FIXME: POSIXThreads isn't exactly the option this should be defined for, // but it works for now. if (Opts.POSIXThreads) Builder.defineMacro("_MT"); if (Opts.MSCompatibilityVersion) { Builder.defineMacro("_MSC_VER", Twine(Opts.MSCompatibilityVersion / 100000)); Builder.defineMacro("_MSC_FULL_VER", Twine(Opts.MSCompatibilityVersion)); // FIXME We cannot encode the revision information into 32-bits Builder.defineMacro("_MSC_BUILD", Twine(1)); if (Opts.CPlusPlus11 && Opts.isCompatibleWithMSVC(LangOptions::MSVC2015)) Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", Twine(1)); } if (Opts.MicrosoftExt) { Builder.defineMacro("_MSC_EXTENSIONS"); if (Opts.CPlusPlus11) { Builder.defineMacro("_RVALUE_REFERENCES_V2_SUPPORTED"); Builder.defineMacro("_RVALUE_REFERENCES_SUPPORTED"); Builder.defineMacro("_NATIVE_NULLPTR_SUPPORTED"); } } Builder.defineMacro("_INTEGRAL_MAX_BITS", "64"); } public: WindowsTargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) {} }; template class NaClTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); if (Opts.CPlusPlus) Builder.defineMacro("_GNU_SOURCE"); DefineStd(Builder, "unix", Opts); Builder.defineMacro("__ELF__"); Builder.defineMacro("__native_client__"); } public: NaClTargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) { this->UserLabelPrefix = ""; this->LongAlign = 32; this->LongWidth = 32; this->PointerAlign = 32; this->PointerWidth = 32; this->IntMaxType = TargetInfo::SignedLongLong; this->Int64Type = TargetInfo::SignedLongLong; this->DoubleAlign = 64; this->LongDoubleWidth = 64; this->LongDoubleAlign = 64; this->LongLongWidth = 64; this->LongLongAlign = 64; this->SizeType = TargetInfo::UnsignedInt; this->PtrDiffType = TargetInfo::SignedInt; this->IntPtrType = TargetInfo::SignedInt; // RegParmMax is inherited from the underlying architecture this->LongDoubleFormat = &llvm::APFloat::IEEEdouble; if (Triple.getArch() == llvm::Triple::arm) { // Handled in ARM's setABI(). } else if (Triple.getArch() == llvm::Triple::x86) { this->DataLayoutString = "e-m:e-p:32:32-i64:64-n8:16:32-S128"; } else if (Triple.getArch() == llvm::Triple::x86_64) { this->DataLayoutString = "e-m:e-p:32:32-i64:64-n8:16:32:64-S128"; } else if (Triple.getArch() == llvm::Triple::mipsel) { // Handled on mips' setDataLayoutString. } else { assert(Triple.getArch() == llvm::Triple::le32); this->DataLayoutString = "e-p:32:32-i64:64"; } } }; // WebAssembly target template class WebAssemblyOSTargetInfo : public OSTargetInfo { void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const final { // A common platform macro. if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); // Follow g++ convention and predefine _GNU_SOURCE for C++. if (Opts.CPlusPlus) Builder.defineMacro("_GNU_SOURCE"); } // As an optimization, group static init code together in a section. const char *getStaticInitSectionSpecifier() const final { return ".text.__startup"; } public: explicit WebAssemblyOSTargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) { this->MCountName = "__mcount"; this->UserLabelPrefix = ""; this->TheCXXABI.set(TargetCXXABI::WebAssembly); } }; //===----------------------------------------------------------------------===// // Specific target implementations. //===----------------------------------------------------------------------===// // PPC abstract base class class PPCTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; static const char * const GCCRegNames[]; static const TargetInfo::GCCRegAlias GCCRegAliases[]; std::string CPU; // Target cpu features. bool HasVSX; bool HasP8Vector; bool HasP8Crypto; bool HasDirectMove; bool HasQPX; bool HasHTM; bool HasBPERMD; bool HasExtDiv; protected: std::string ABI; public: PPCTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple), HasVSX(false), HasP8Vector(false), HasP8Crypto(false), HasDirectMove(false), HasQPX(false), HasHTM(false), HasBPERMD(false), HasExtDiv(false) { BigEndian = (Triple.getArch() != llvm::Triple::ppc64le); SimdDefaultAlign = 128; LongDoubleWidth = LongDoubleAlign = 128; LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble; } /// \brief Flags for architecture specific defines. typedef enum { ArchDefineNone = 0, ArchDefineName = 1 << 0, // is substituted for arch name. ArchDefinePpcgr = 1 << 1, ArchDefinePpcsq = 1 << 2, ArchDefine440 = 1 << 3, ArchDefine603 = 1 << 4, ArchDefine604 = 1 << 5, ArchDefinePwr4 = 1 << 6, ArchDefinePwr5 = 1 << 7, ArchDefinePwr5x = 1 << 8, ArchDefinePwr6 = 1 << 9, ArchDefinePwr6x = 1 << 10, ArchDefinePwr7 = 1 << 11, ArchDefinePwr8 = 1 << 12, ArchDefineA2 = 1 << 13, ArchDefineA2q = 1 << 14 } ArchDefineTypes; // Note: GCC recognizes the following additional cpus: // 401, 403, 405, 405fp, 440fp, 464, 464fp, 476, 476fp, 505, 740, 801, // 821, 823, 8540, 8548, e300c2, e300c3, e500mc64, e6500, 860, cell, // titan, rs64. bool setCPU(const std::string &Name) override { bool CPUKnown = llvm::StringSwitch(Name) .Case("generic", true) .Case("440", true) .Case("450", true) .Case("601", true) .Case("602", true) .Case("603", true) .Case("603e", true) .Case("603ev", true) .Case("604", true) .Case("604e", true) .Case("620", true) .Case("630", true) .Case("g3", true) .Case("7400", true) .Case("g4", true) .Case("7450", true) .Case("g4+", true) .Case("750", true) .Case("970", true) .Case("g5", true) .Case("a2", true) .Case("a2q", true) .Case("e500mc", true) .Case("e5500", true) .Case("power3", true) .Case("pwr3", true) .Case("power4", true) .Case("pwr4", true) .Case("power5", true) .Case("pwr5", true) .Case("power5x", true) .Case("pwr5x", true) .Case("power6", true) .Case("pwr6", true) .Case("power6x", true) .Case("pwr6x", true) .Case("power7", true) .Case("pwr7", true) .Case("power8", true) .Case("pwr8", true) .Case("powerpc", true) .Case("ppc", true) .Case("powerpc64", true) .Case("ppc64", true) .Case("powerpc64le", true) .Case("ppc64le", true) .Default(false); if (CPUKnown) CPU = Name; return CPUKnown; } StringRef getABI() const override { return ABI; } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::PPC::LastTSBuiltin-Builtin::FirstTSBuiltin); } bool isCLZForZeroUndef() const override { return false; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; bool initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const override; bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override; bool hasFeature(StringRef Feature) const override; void setFeatureEnabled(llvm::StringMap &Features, StringRef Name, bool Enabled) const override; ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { switch (*Name) { default: return false; case 'O': // Zero break; case 'b': // Base register case 'f': // Floating point register Info.setAllowsRegister(); break; // FIXME: The following are added to allow parsing. // I just took a guess at what the actions should be. // Also, is more specific checking needed? I.e. specific registers? case 'd': // Floating point register (containing 64-bit value) case 'v': // Altivec vector register Info.setAllowsRegister(); break; case 'w': switch (Name[1]) { case 'd':// VSX vector register to hold vector double data case 'f':// VSX vector register to hold vector float data case 's':// VSX vector register to hold scalar float data case 'a':// Any VSX register case 'c':// An individual CR bit break; default: return false; } Info.setAllowsRegister(); Name++; // Skip over 'w'. break; case 'h': // `MQ', `CTR', or `LINK' register case 'q': // `MQ' register case 'c': // `CTR' register case 'l': // `LINK' register case 'x': // `CR' register (condition register) number 0 case 'y': // `CR' register (condition register) case 'z': // `XER[CA]' carry bit (part of the XER register) Info.setAllowsRegister(); break; case 'I': // Signed 16-bit constant case 'J': // Unsigned 16-bit constant shifted left 16 bits // (use `L' instead for SImode constants) case 'K': // Unsigned 16-bit constant case 'L': // Signed 16-bit constant shifted left 16 bits case 'M': // Constant larger than 31 case 'N': // Exact power of 2 case 'P': // Constant whose negation is a signed 16-bit constant case 'G': // Floating point constant that can be loaded into a // register with one instruction per word case 'H': // Integer/Floating point constant that can be loaded // into a register using three instructions break; case 'm': // Memory operand. Note that on PowerPC targets, m can // include addresses that update the base register. It // is therefore only safe to use `m' in an asm statement // if that asm statement accesses the operand exactly once. // The asm statement must also use `%U' as a // placeholder for the "update" flag in the corresponding // load or store instruction. For example: // asm ("st%U0 %1,%0" : "=m" (mem) : "r" (val)); // is correct but: // asm ("st %1,%0" : "=m" (mem) : "r" (val)); // is not. Use es rather than m if you don't want the base // register to be updated. case 'e': if (Name[1] != 's') return false; // es: A "stable" memory operand; that is, one which does not // include any automodification of the base register. Unlike // `m', this constraint can be used in asm statements that // might access the operand several times, or that might not // access it at all. Info.setAllowsMemory(); Name++; // Skip over 'e'. break; case 'Q': // Memory operand that is an offset from a register (it is // usually better to use `m' or `es' in asm statements) case 'Z': // Memory operand that is an indexed or indirect from a // register (it is usually better to use `m' or `es' in // asm statements) Info.setAllowsMemory(); Info.setAllowsRegister(); break; case 'R': // AIX TOC entry case 'a': // Address operand that is an indexed or indirect from a // register (`p' is preferable for asm statements) case 'S': // Constant suitable as a 64-bit mask operand case 'T': // Constant suitable as a 32-bit mask operand case 'U': // System V Release 4 small data area reference case 't': // AND masks that can be performed by two rldic{l, r} // instructions case 'W': // Vector constant that does not require memory case 'j': // Vector constant that is all zeros. break; // End FIXME. } return true; } std::string convertConstraint(const char *&Constraint) const override { std::string R; switch (*Constraint) { case 'e': case 'w': // Two-character constraint; add "^" hint for later parsing. R = std::string("^") + std::string(Constraint, 2); Constraint++; break; default: return TargetInfo::convertConstraint(Constraint); } return R; } const char *getClobbers() const override { return ""; } int getEHDataRegisterNumber(unsigned RegNo) const override { if (RegNo == 0) return 3; if (RegNo == 1) return 4; return -1; } bool hasSjLjLowering() const override { return true; } bool useFloat128ManglingForLongDouble() const override { return LongDoubleWidth == 128 && LongDoubleFormat == &llvm::APFloat::PPCDoubleDouble && getTriple().isOSBinFormatELF(); } }; const Builtin::Info PPCTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsPPC.def" }; /// handleTargetFeatures - Perform initialization based on the user /// configured set of features. bool PPCTargetInfo::handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) { for (const auto &Feature : Features) { if (Feature == "+vsx") { HasVSX = true; } else if (Feature == "+bpermd") { HasBPERMD = true; } else if (Feature == "+extdiv") { HasExtDiv = true; } else if (Feature == "+power8-vector") { HasP8Vector = true; } else if (Feature == "+crypto") { HasP8Crypto = true; } else if (Feature == "+direct-move") { HasDirectMove = true; } else if (Feature == "+qpx") { HasQPX = true; } else if (Feature == "+htm") { HasHTM = true; } // TODO: Finish this list and add an assert that we've handled them // all. } return true; } /// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific /// #defines that are not tied to a specific subtarget. void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { // Target identification. Builder.defineMacro("__ppc__"); Builder.defineMacro("__PPC__"); Builder.defineMacro("_ARCH_PPC"); Builder.defineMacro("__powerpc__"); Builder.defineMacro("__POWERPC__"); if (PointerWidth == 64) { Builder.defineMacro("_ARCH_PPC64"); Builder.defineMacro("__powerpc64__"); Builder.defineMacro("__ppc64__"); Builder.defineMacro("__PPC64__"); } // Target properties. if (getTriple().getArch() == llvm::Triple::ppc64le) { Builder.defineMacro("_LITTLE_ENDIAN"); } else { if (getTriple().getOS() != llvm::Triple::NetBSD && getTriple().getOS() != llvm::Triple::OpenBSD) Builder.defineMacro("_BIG_ENDIAN"); } // ABI options. if (ABI == "elfv1" || ABI == "elfv1-qpx") Builder.defineMacro("_CALL_ELF", "1"); if (ABI == "elfv2") Builder.defineMacro("_CALL_ELF", "2"); // Subtarget options. Builder.defineMacro("__NATURAL_ALIGNMENT__"); Builder.defineMacro("__REGISTER_PREFIX__", ""); // FIXME: Should be controlled by command line option. if (LongDoubleWidth == 128) Builder.defineMacro("__LONG_DOUBLE_128__"); if (Opts.AltiVec) { Builder.defineMacro("__VEC__", "10206"); Builder.defineMacro("__ALTIVEC__"); } // CPU identification. ArchDefineTypes defs = (ArchDefineTypes)llvm::StringSwitch(CPU) .Case("440", ArchDefineName) .Case("450", ArchDefineName | ArchDefine440) .Case("601", ArchDefineName) .Case("602", ArchDefineName | ArchDefinePpcgr) .Case("603", ArchDefineName | ArchDefinePpcgr) .Case("603e", ArchDefineName | ArchDefine603 | ArchDefinePpcgr) .Case("603ev", ArchDefineName | ArchDefine603 | ArchDefinePpcgr) .Case("604", ArchDefineName | ArchDefinePpcgr) .Case("604e", ArchDefineName | ArchDefine604 | ArchDefinePpcgr) .Case("620", ArchDefineName | ArchDefinePpcgr) .Case("630", ArchDefineName | ArchDefinePpcgr) .Case("7400", ArchDefineName | ArchDefinePpcgr) .Case("7450", ArchDefineName | ArchDefinePpcgr) .Case("750", ArchDefineName | ArchDefinePpcgr) .Case("970", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("a2", ArchDefineA2) .Case("a2q", ArchDefineName | ArchDefineA2 | ArchDefineA2q) .Case("pwr3", ArchDefinePpcgr) .Case("pwr4", ArchDefineName | ArchDefinePpcgr | ArchDefinePpcsq) .Case("pwr5", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("pwr5x", ArchDefineName | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("pwr6", ArchDefineName | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("pwr6x", ArchDefineName | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("pwr7", ArchDefineName | ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("pwr8", ArchDefineName | ArchDefinePwr7 | ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("power3", ArchDefinePpcgr) .Case("power4", ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("power5", ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("power5x", ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("power6", ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("power6x", ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("power7", ArchDefinePwr7 | ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("power8", ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Default(ArchDefineNone); if (defs & ArchDefineName) Builder.defineMacro(Twine("_ARCH_", StringRef(CPU).upper())); if (defs & ArchDefinePpcgr) Builder.defineMacro("_ARCH_PPCGR"); if (defs & ArchDefinePpcsq) Builder.defineMacro("_ARCH_PPCSQ"); if (defs & ArchDefine440) Builder.defineMacro("_ARCH_440"); if (defs & ArchDefine603) Builder.defineMacro("_ARCH_603"); if (defs & ArchDefine604) Builder.defineMacro("_ARCH_604"); if (defs & ArchDefinePwr4) Builder.defineMacro("_ARCH_PWR4"); if (defs & ArchDefinePwr5) Builder.defineMacro("_ARCH_PWR5"); if (defs & ArchDefinePwr5x) Builder.defineMacro("_ARCH_PWR5X"); if (defs & ArchDefinePwr6) Builder.defineMacro("_ARCH_PWR6"); if (defs & ArchDefinePwr6x) Builder.defineMacro("_ARCH_PWR6X"); if (defs & ArchDefinePwr7) Builder.defineMacro("_ARCH_PWR7"); if (defs & ArchDefinePwr8) Builder.defineMacro("_ARCH_PWR8"); if (defs & ArchDefineA2) Builder.defineMacro("_ARCH_A2"); if (defs & ArchDefineA2q) { Builder.defineMacro("_ARCH_A2Q"); Builder.defineMacro("_ARCH_QP"); } if (getTriple().getVendor() == llvm::Triple::BGQ) { Builder.defineMacro("__bg__"); Builder.defineMacro("__THW_BLUEGENE__"); Builder.defineMacro("__bgq__"); Builder.defineMacro("__TOS_BGQ__"); } if (HasVSX) Builder.defineMacro("__VSX__"); if (HasP8Vector) Builder.defineMacro("__POWER8_VECTOR__"); if (HasP8Crypto) Builder.defineMacro("__CRYPTO__"); if (HasHTM) Builder.defineMacro("__HTM__"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); if (PointerWidth == 64) Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); // FIXME: The following are not yet generated here by Clang, but are // generated by GCC: // // _SOFT_FLOAT_ // __RECIP_PRECISION__ // __APPLE_ALTIVEC__ // __RECIP__ // __RECIPF__ // __RSQRTE__ // __RSQRTEF__ // _SOFT_DOUBLE_ // __NO_LWSYNC__ // __HAVE_BSWAP__ // __LONGDOUBLE128 // __CMODEL_MEDIUM__ // __CMODEL_LARGE__ // _CALL_SYSV // _CALL_DARWIN // __NO_FPRS__ } // Handle explicit options being passed to the compiler here: if we've // explicitly turned off vsx and turned on power8-vector or direct-move then // go ahead and error since the customer has expressed a somewhat incompatible // set of options. static bool ppcUserFeaturesCheck(DiagnosticsEngine &Diags, const std::vector &FeaturesVec) { if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "-vsx") != FeaturesVec.end()) { if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+power8-vector") != FeaturesVec.end()) { Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower8-vector" << "-mno-vsx"; return false; } if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+direct-move") != FeaturesVec.end()) { Diags.Report(diag::err_opt_not_valid_with_opt) << "-mdirect-move" << "-mno-vsx"; return false; } } return true; } bool PPCTargetInfo::initFeatureMap( llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const { Features["altivec"] = llvm::StringSwitch(CPU) .Case("7400", true) .Case("g4", true) .Case("7450", true) .Case("g4+", true) .Case("970", true) .Case("g5", true) .Case("pwr6", true) .Case("pwr7", true) .Case("pwr8", true) .Case("ppc64", true) .Case("ppc64le", true) .Default(false); Features["qpx"] = (CPU == "a2q"); Features["crypto"] = llvm::StringSwitch(CPU) .Case("ppc64le", true) .Case("pwr8", true) .Default(false); Features["power8-vector"] = llvm::StringSwitch(CPU) .Case("ppc64le", true) .Case("pwr8", true) .Default(false); Features["bpermd"] = llvm::StringSwitch(CPU) .Case("ppc64le", true) .Case("pwr8", true) .Case("pwr7", true) .Default(false); Features["extdiv"] = llvm::StringSwitch(CPU) .Case("ppc64le", true) .Case("pwr8", true) .Case("pwr7", true) .Default(false); Features["direct-move"] = llvm::StringSwitch(CPU) .Case("ppc64le", true) .Case("pwr8", true) .Default(false); Features["vsx"] = llvm::StringSwitch(CPU) .Case("ppc64le", true) .Case("pwr8", true) .Case("pwr7", true) .Default(false); if (!ppcUserFeaturesCheck(Diags, FeaturesVec)) return false; return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } bool PPCTargetInfo::hasFeature(StringRef Feature) const { return llvm::StringSwitch(Feature) .Case("powerpc", true) .Case("vsx", HasVSX) .Case("power8-vector", HasP8Vector) .Case("crypto", HasP8Crypto) .Case("direct-move", HasDirectMove) .Case("qpx", HasQPX) .Case("htm", HasHTM) .Case("bpermd", HasBPERMD) .Case("extdiv", HasExtDiv) .Default(false); } void PPCTargetInfo::setFeatureEnabled(llvm::StringMap &Features, StringRef Name, bool Enabled) const { // If we're enabling direct-move or power8-vector go ahead and enable vsx // as well. Do the inverse if we're disabling vsx. We'll diagnose any user // incompatible options. if (Enabled) { if (Name == "vsx") { Features[Name] = true; } else if (Name == "direct-move") { Features[Name] = Features["vsx"] = true; } else if (Name == "power8-vector") { Features[Name] = Features["vsx"] = true; } else { Features[Name] = true; } } else { if (Name == "vsx") { Features[Name] = Features["direct-move"] = Features["power8-vector"] = false; } else { Features[Name] = false; } } } const char * const PPCTargetInfo::GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", "mq", "lr", "ctr", "ap", "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", "xer", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", "vrsave", "vscr", "spe_acc", "spefscr", "sfp" }; ArrayRef PPCTargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } const TargetInfo::GCCRegAlias PPCTargetInfo::GCCRegAliases[] = { // While some of these aliases do map to different registers // they still share the same register name. { { "0" }, "r0" }, { { "1"}, "r1" }, { { "2" }, "r2" }, { { "3" }, "r3" }, { { "4" }, "r4" }, { { "5" }, "r5" }, { { "6" }, "r6" }, { { "7" }, "r7" }, { { "8" }, "r8" }, { { "9" }, "r9" }, { { "10" }, "r10" }, { { "11" }, "r11" }, { { "12" }, "r12" }, { { "13" }, "r13" }, { { "14" }, "r14" }, { { "15" }, "r15" }, { { "16" }, "r16" }, { { "17" }, "r17" }, { { "18" }, "r18" }, { { "19" }, "r19" }, { { "20" }, "r20" }, { { "21" }, "r21" }, { { "22" }, "r22" }, { { "23" }, "r23" }, { { "24" }, "r24" }, { { "25" }, "r25" }, { { "26" }, "r26" }, { { "27" }, "r27" }, { { "28" }, "r28" }, { { "29" }, "r29" }, { { "30" }, "r30" }, { { "31" }, "r31" }, { { "fr0" }, "f0" }, { { "fr1" }, "f1" }, { { "fr2" }, "f2" }, { { "fr3" }, "f3" }, { { "fr4" }, "f4" }, { { "fr5" }, "f5" }, { { "fr6" }, "f6" }, { { "fr7" }, "f7" }, { { "fr8" }, "f8" }, { { "fr9" }, "f9" }, { { "fr10" }, "f10" }, { { "fr11" }, "f11" }, { { "fr12" }, "f12" }, { { "fr13" }, "f13" }, { { "fr14" }, "f14" }, { { "fr15" }, "f15" }, { { "fr16" }, "f16" }, { { "fr17" }, "f17" }, { { "fr18" }, "f18" }, { { "fr19" }, "f19" }, { { "fr20" }, "f20" }, { { "fr21" }, "f21" }, { { "fr22" }, "f22" }, { { "fr23" }, "f23" }, { { "fr24" }, "f24" }, { { "fr25" }, "f25" }, { { "fr26" }, "f26" }, { { "fr27" }, "f27" }, { { "fr28" }, "f28" }, { { "fr29" }, "f29" }, { { "fr30" }, "f30" }, { { "fr31" }, "f31" }, { { "cc" }, "cr0" }, }; ArrayRef PPCTargetInfo::getGCCRegAliases() const { return llvm::makeArrayRef(GCCRegAliases); } class PPC32TargetInfo : public PPCTargetInfo { public: PPC32TargetInfo(const llvm::Triple &Triple) : PPCTargetInfo(Triple) { DataLayoutString = "E-m:e-p:32:32-i64:64-n32"; switch (getTriple().getOS()) { case llvm::Triple::Linux: case llvm::Triple::FreeBSD: case llvm::Triple::NetBSD: SizeType = UnsignedInt; PtrDiffType = SignedInt; IntPtrType = SignedInt; break; default: break; } if (getTriple().getOS() == llvm::Triple::FreeBSD) { LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; } // PPC32 supports atomics up to 4 bytes. MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; } BuiltinVaListKind getBuiltinVaListKind() const override { // This is the ELF definition, and is overridden by the Darwin sub-target return TargetInfo::PowerABIBuiltinVaList; } }; // Note: ABI differences may eventually require us to have a separate // TargetInfo for little endian. class PPC64TargetInfo : public PPCTargetInfo { public: PPC64TargetInfo(const llvm::Triple &Triple) : PPCTargetInfo(Triple) { LongWidth = LongAlign = PointerWidth = PointerAlign = 64; IntMaxType = SignedLong; Int64Type = SignedLong; if ((Triple.getArch() == llvm::Triple::ppc64le)) { DataLayoutString = "e-m:e-i64:64-n32:64"; ABI = "elfv2"; } else { DataLayoutString = "E-m:e-i64:64-n32:64"; ABI = "elfv1"; } switch (getTriple().getOS()) { case llvm::Triple::FreeBSD: LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; break; case llvm::Triple::NetBSD: IntMaxType = SignedLongLong; Int64Type = SignedLongLong; break; default: break; } // PPC64 supports atomics up to 8 bytes. MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } // PPC64 Linux-specific ABI options. bool setABI(const std::string &Name) override { if (Name == "elfv1" || Name == "elfv1-qpx" || Name == "elfv2") { ABI = Name; return true; } return false; } }; class DarwinPPC32TargetInfo : public DarwinTargetInfo { public: DarwinPPC32TargetInfo(const llvm::Triple &Triple) : DarwinTargetInfo(Triple) { HasAlignMac68kSupport = true; BoolWidth = BoolAlign = 32; //XXX support -mone-byte-bool? PtrDiffType = SignedInt; // for http://llvm.org/bugs/show_bug.cgi?id=15726 LongLongAlign = 32; SuitableAlign = 128; DataLayoutString = "E-m:o-p:32:32-f64:32:64-n32"; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } }; class DarwinPPC64TargetInfo : public DarwinTargetInfo { public: DarwinPPC64TargetInfo(const llvm::Triple &Triple) : DarwinTargetInfo(Triple) { HasAlignMac68kSupport = true; SuitableAlign = 128; DataLayoutString = "E-m:o-i64:64-n32:64"; } }; static const unsigned NVPTXAddrSpaceMap[] = { 1, // opencl_global 3, // opencl_local 4, // opencl_constant // FIXME: generic has to be added to the target 0, // opencl_generic 1, // cuda_device 4, // cuda_constant 3, // cuda_shared }; class NVPTXTargetInfo : public TargetInfo { static const char *const GCCRegNames[]; static const Builtin::Info BuiltinInfo[]; // The GPU profiles supported by the NVPTX backend enum GPUKind { GK_NONE, GK_SM20, GK_SM21, GK_SM30, GK_SM35, GK_SM37, } GPU; public: NVPTXTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { BigEndian = false; TLSSupported = false; LongWidth = LongAlign = 64; AddrSpaceMap = &NVPTXAddrSpaceMap; UseAddrSpaceMapMangling = true; // Define available target features // These must be defined in sorted order! NoAsmVariants = true; // Set the default GPU to sm20 GPU = GK_SM20; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__PTX__"); Builder.defineMacro("__NVPTX__"); if (Opts.CUDAIsDevice) { // Set __CUDA_ARCH__ for the GPU specified. std::string CUDAArchCode; switch (GPU) { case GK_SM20: CUDAArchCode = "200"; break; case GK_SM21: CUDAArchCode = "210"; break; case GK_SM30: CUDAArchCode = "300"; break; case GK_SM35: CUDAArchCode = "350"; break; case GK_SM37: CUDAArchCode = "370"; break; default: llvm_unreachable("Unhandled target CPU"); } Builder.defineMacro("__CUDA_ARCH__", CUDAArchCode); } } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::NVPTX::LastTSBuiltin - Builtin::FirstTSBuiltin); } bool hasFeature(StringRef Feature) const override { return Feature == "ptx" || Feature == "nvptx"; } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override { // No aliases. return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { switch (*Name) { default: return false; case 'c': case 'h': case 'r': case 'l': case 'f': case 'd': Info.setAllowsRegister(); return true; } } const char *getClobbers() const override { // FIXME: Is this really right? return ""; } BuiltinVaListKind getBuiltinVaListKind() const override { // FIXME: implement return TargetInfo::CharPtrBuiltinVaList; } bool setCPU(const std::string &Name) override { GPU = llvm::StringSwitch(Name) .Case("sm_20", GK_SM20) .Case("sm_21", GK_SM21) .Case("sm_30", GK_SM30) .Case("sm_35", GK_SM35) .Case("sm_37", GK_SM37) .Default(GK_NONE); return GPU != GK_NONE; } }; const Builtin::Info NVPTXTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsNVPTX.def" }; const char *const NVPTXTargetInfo::GCCRegNames[] = {"r0"}; ArrayRef NVPTXTargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } class NVPTX32TargetInfo : public NVPTXTargetInfo { public: NVPTX32TargetInfo(const llvm::Triple &Triple) : NVPTXTargetInfo(Triple) { LongWidth = LongAlign = 32; PointerWidth = PointerAlign = 32; SizeType = TargetInfo::UnsignedInt; PtrDiffType = TargetInfo::SignedInt; IntPtrType = TargetInfo::SignedInt; DataLayoutString = "e-p:32:32-i64:64-v16:16-v32:32-n16:32:64"; } }; class NVPTX64TargetInfo : public NVPTXTargetInfo { public: NVPTX64TargetInfo(const llvm::Triple &Triple) : NVPTXTargetInfo(Triple) { PointerWidth = PointerAlign = 64; SizeType = TargetInfo::UnsignedLong; PtrDiffType = TargetInfo::SignedLong; IntPtrType = TargetInfo::SignedLong; DataLayoutString = "e-i64:64-v16:16-v32:32-n16:32:64"; } }; static const unsigned AMDGPUAddrSpaceMap[] = { 1, // opencl_global 3, // opencl_local 2, // opencl_constant 4, // opencl_generic 1, // cuda_device 2, // cuda_constant 3 // cuda_shared }; // If you edit the description strings, make sure you update // getPointerWidthV(). static const char *const DataLayoutStringR600 = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128" "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64"; static const char *const DataLayoutStringR600DoubleOps = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128" "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64"; static const char *const DataLayoutStringSI = "e-p:32:32-p1:64:64-p2:64:64-p3:32:32-p4:64:64-p5:32:32-p24:64:64" "-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128" "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64"; class AMDGPUTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; static const char * const GCCRegNames[]; /// \brief The GPU profiles supported by the AMDGPU target. enum GPUKind { GK_NONE, GK_R600, GK_R600_DOUBLE_OPS, GK_R700, GK_R700_DOUBLE_OPS, GK_EVERGREEN, GK_EVERGREEN_DOUBLE_OPS, GK_NORTHERN_ISLANDS, GK_CAYMAN, GK_SOUTHERN_ISLANDS, GK_SEA_ISLANDS, GK_VOLCANIC_ISLANDS } GPU; bool hasFP64:1; bool hasFMAF:1; bool hasLDEXPF:1; public: AMDGPUTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { if (Triple.getArch() == llvm::Triple::amdgcn) { DataLayoutString = DataLayoutStringSI; GPU = GK_SOUTHERN_ISLANDS; hasFP64 = true; hasFMAF = true; hasLDEXPF = true; } else { DataLayoutString = DataLayoutStringR600; GPU = GK_R600; hasFP64 = false; hasFMAF = false; hasLDEXPF = false; } AddrSpaceMap = &AMDGPUAddrSpaceMap; UseAddrSpaceMapMangling = true; } uint64_t getPointerWidthV(unsigned AddrSpace) const override { if (GPU <= GK_CAYMAN) return 32; switch(AddrSpace) { default: return 64; case 0: case 3: case 5: return 32; } } const char * getClobbers() const override { return ""; } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override { return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { switch (*Name) { default: break; case 'v': // vgpr case 's': // sgpr Info.setAllowsRegister(); return true; } return false; } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::AMDGPU::LastTSBuiltin - Builtin::FirstTSBuiltin); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__R600__"); if (hasFMAF) Builder.defineMacro("__HAS_FMAF__"); if (hasLDEXPF) Builder.defineMacro("__HAS_LDEXPF__"); if (hasFP64 && Opts.OpenCL) Builder.defineMacro("cl_khr_fp64"); if (Opts.OpenCL) { if (GPU >= GK_NORTHERN_ISLANDS) { Builder.defineMacro("cl_khr_byte_addressable_store"); Builder.defineMacro("cl_khr_global_int32_base_atomics"); Builder.defineMacro("cl_khr_global_int32_extended_atomics"); Builder.defineMacro("cl_khr_local_int32_base_atomics"); Builder.defineMacro("cl_khr_local_int32_extended_atomics"); } } } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } bool setCPU(const std::string &Name) override { GPU = llvm::StringSwitch(Name) .Case("r600" , GK_R600) .Case("rv610", GK_R600) .Case("rv620", GK_R600) .Case("rv630", GK_R600) .Case("rv635", GK_R600) .Case("rs780", GK_R600) .Case("rs880", GK_R600) .Case("rv670", GK_R600_DOUBLE_OPS) .Case("rv710", GK_R700) .Case("rv730", GK_R700) .Case("rv740", GK_R700_DOUBLE_OPS) .Case("rv770", GK_R700_DOUBLE_OPS) .Case("palm", GK_EVERGREEN) .Case("cedar", GK_EVERGREEN) .Case("sumo", GK_EVERGREEN) .Case("sumo2", GK_EVERGREEN) .Case("redwood", GK_EVERGREEN) .Case("juniper", GK_EVERGREEN) .Case("hemlock", GK_EVERGREEN_DOUBLE_OPS) .Case("cypress", GK_EVERGREEN_DOUBLE_OPS) .Case("barts", GK_NORTHERN_ISLANDS) .Case("turks", GK_NORTHERN_ISLANDS) .Case("caicos", GK_NORTHERN_ISLANDS) .Case("cayman", GK_CAYMAN) .Case("aruba", GK_CAYMAN) .Case("tahiti", GK_SOUTHERN_ISLANDS) .Case("pitcairn", GK_SOUTHERN_ISLANDS) .Case("verde", GK_SOUTHERN_ISLANDS) .Case("oland", GK_SOUTHERN_ISLANDS) .Case("hainan", GK_SOUTHERN_ISLANDS) .Case("bonaire", GK_SEA_ISLANDS) .Case("kabini", GK_SEA_ISLANDS) .Case("kaveri", GK_SEA_ISLANDS) .Case("hawaii", GK_SEA_ISLANDS) .Case("mullins", GK_SEA_ISLANDS) .Case("tonga", GK_VOLCANIC_ISLANDS) .Case("iceland", GK_VOLCANIC_ISLANDS) .Case("carrizo", GK_VOLCANIC_ISLANDS) .Default(GK_NONE); if (GPU == GK_NONE) { return false; } // Set the correct data layout switch (GPU) { case GK_NONE: case GK_R600: case GK_R700: case GK_EVERGREEN: case GK_NORTHERN_ISLANDS: DataLayoutString = DataLayoutStringR600; hasFP64 = false; hasFMAF = false; hasLDEXPF = false; break; case GK_R600_DOUBLE_OPS: case GK_R700_DOUBLE_OPS: case GK_EVERGREEN_DOUBLE_OPS: case GK_CAYMAN: DataLayoutString = DataLayoutStringR600DoubleOps; hasFP64 = true; hasFMAF = true; hasLDEXPF = false; break; case GK_SOUTHERN_ISLANDS: case GK_SEA_ISLANDS: case GK_VOLCANIC_ISLANDS: DataLayoutString = DataLayoutStringSI; hasFP64 = true; hasFMAF = true; hasLDEXPF = true; break; } return true; } }; const Builtin::Info AMDGPUTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsAMDGPU.def" }; const char * const AMDGPUTargetInfo::GCCRegNames[] = { "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", "v32", "v33", "v34", "v35", "v36", "v37", "v38", "v39", "v40", "v41", "v42", "v43", "v44", "v45", "v46", "v47", "v48", "v49", "v50", "v51", "v52", "v53", "v54", "v55", "v56", "v57", "v58", "v59", "v60", "v61", "v62", "v63", "v64", "v65", "v66", "v67", "v68", "v69", "v70", "v71", "v72", "v73", "v74", "v75", "v76", "v77", "v78", "v79", "v80", "v81", "v82", "v83", "v84", "v85", "v86", "v87", "v88", "v89", "v90", "v91", "v92", "v93", "v94", "v95", "v96", "v97", "v98", "v99", "v100", "v101", "v102", "v103", "v104", "v105", "v106", "v107", "v108", "v109", "v110", "v111", "v112", "v113", "v114", "v115", "v116", "v117", "v118", "v119", "v120", "v121", "v122", "v123", "v124", "v125", "v126", "v127", "v128", "v129", "v130", "v131", "v132", "v133", "v134", "v135", "v136", "v137", "v138", "v139", "v140", "v141", "v142", "v143", "v144", "v145", "v146", "v147", "v148", "v149", "v150", "v151", "v152", "v153", "v154", "v155", "v156", "v157", "v158", "v159", "v160", "v161", "v162", "v163", "v164", "v165", "v166", "v167", "v168", "v169", "v170", "v171", "v172", "v173", "v174", "v175", "v176", "v177", "v178", "v179", "v180", "v181", "v182", "v183", "v184", "v185", "v186", "v187", "v188", "v189", "v190", "v191", "v192", "v193", "v194", "v195", "v196", "v197", "v198", "v199", "v200", "v201", "v202", "v203", "v204", "v205", "v206", "v207", "v208", "v209", "v210", "v211", "v212", "v213", "v214", "v215", "v216", "v217", "v218", "v219", "v220", "v221", "v222", "v223", "v224", "v225", "v226", "v227", "v228", "v229", "v230", "v231", "v232", "v233", "v234", "v235", "v236", "v237", "v238", "v239", "v240", "v241", "v242", "v243", "v244", "v245", "v246", "v247", "v248", "v249", "v250", "v251", "v252", "v253", "v254", "v255", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", "s32", "s33", "s34", "s35", "s36", "s37", "s38", "s39", "s40", "s41", "s42", "s43", "s44", "s45", "s46", "s47", "s48", "s49", "s50", "s51", "s52", "s53", "s54", "s55", "s56", "s57", "s58", "s59", "s60", "s61", "s62", "s63", "s64", "s65", "s66", "s67", "s68", "s69", "s70", "s71", "s72", "s73", "s74", "s75", "s76", "s77", "s78", "s79", "s80", "s81", "s82", "s83", "s84", "s85", "s86", "s87", "s88", "s89", "s90", "s91", "s92", "s93", "s94", "s95", "s96", "s97", "s98", "s99", "s100", "s101", "s102", "s103", "s104", "s105", "s106", "s107", "s108", "s109", "s110", "s111", "s112", "s113", "s114", "s115", "s116", "s117", "s118", "s119", "s120", "s121", "s122", "s123", "s124", "s125", "s126", "s127" "exec", "vcc", "scc", "m0", "flat_scr", "exec_lo", "exec_hi", "vcc_lo", "vcc_hi", "flat_scr_lo", "flat_scr_hi" }; ArrayRef AMDGPUTargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } // Namespace for x86 abstract base class const Builtin::Info BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE }, #include "clang/Basic/BuiltinsX86.def" }; static const char* const GCCRegNames[] = { "ax", "dx", "cx", "bx", "si", "di", "bp", "sp", "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", "argp", "flags", "fpcr", "fpsr", "dirflag", "frame", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15", "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15", }; const TargetInfo::AddlRegName AddlRegNames[] = { { { "al", "ah", "eax", "rax" }, 0 }, { { "bl", "bh", "ebx", "rbx" }, 3 }, { { "cl", "ch", "ecx", "rcx" }, 2 }, { { "dl", "dh", "edx", "rdx" }, 1 }, { { "esi", "rsi" }, 4 }, { { "edi", "rdi" }, 5 }, { { "esp", "rsp" }, 7 }, { { "ebp", "rbp" }, 6 }, { { "r8d", "r8w", "r8b" }, 38 }, { { "r9d", "r9w", "r9b" }, 39 }, { { "r10d", "r10w", "r10b" }, 40 }, { { "r11d", "r11w", "r11b" }, 41 }, { { "r12d", "r12w", "r12b" }, 42 }, { { "r13d", "r13w", "r13b" }, 43 }, { { "r14d", "r14w", "r14b" }, 44 }, { { "r15d", "r15w", "r15b" }, 45 }, }; // X86 target abstract base class; x86-32 and x86-64 are very close, so // most of the implementation can be shared. class X86TargetInfo : public TargetInfo { enum X86SSEEnum { NoSSE, SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42, AVX, AVX2, AVX512F } SSELevel = NoSSE; enum MMX3DNowEnum { NoMMX3DNow, MMX, AMD3DNow, AMD3DNowAthlon } MMX3DNowLevel = NoMMX3DNow; enum XOPEnum { NoXOP, SSE4A, FMA4, XOP } XOPLevel = NoXOP; bool HasAES = false; bool HasPCLMUL = false; bool HasLZCNT = false; bool HasRDRND = false; bool HasFSGSBASE = false; bool HasBMI = false; bool HasBMI2 = false; bool HasPOPCNT = false; bool HasRTM = false; bool HasPRFCHW = false; bool HasRDSEED = false; bool HasADX = false; bool HasTBM = false; bool HasFMA = false; bool HasF16C = false; bool HasAVX512CD = false; bool HasAVX512ER = false; bool HasAVX512PF = false; bool HasAVX512DQ = false; bool HasAVX512BW = false; bool HasAVX512VL = false; bool HasSHA = false; bool HasCX16 = false; bool HasFXSR = false; bool HasXSAVE = false; bool HasXSAVEOPT = false; bool HasXSAVEC = false; bool HasXSAVES = false; bool HasPKU = false; /// \brief Enumeration of all of the X86 CPUs supported by Clang. /// /// Each enumeration represents a particular CPU supported by Clang. These /// loosely correspond to the options passed to '-march' or '-mtune' flags. enum CPUKind { CK_Generic, /// \name i386 /// i386-generation processors. //@{ CK_i386, //@} /// \name i486 /// i486-generation processors. //@{ CK_i486, CK_WinChipC6, CK_WinChip2, CK_C3, //@} /// \name i586 /// i586-generation processors, P5 microarchitecture based. //@{ CK_i586, CK_Pentium, CK_PentiumMMX, //@} /// \name i686 /// i686-generation processors, P6 / Pentium M microarchitecture based. //@{ CK_i686, CK_PentiumPro, CK_Pentium2, CK_Pentium3, CK_Pentium3M, CK_PentiumM, CK_C3_2, /// This enumerator is a bit odd, as GCC no longer accepts -march=yonah. /// Clang however has some logic to suport this. // FIXME: Warn, deprecate, and potentially remove this. CK_Yonah, //@} /// \name Netburst /// Netburst microarchitecture based processors. //@{ CK_Pentium4, CK_Pentium4M, CK_Prescott, CK_Nocona, //@} /// \name Core /// Core microarchitecture based processors. //@{ CK_Core2, /// This enumerator, like \see CK_Yonah, is a bit odd. It is another /// codename which GCC no longer accepts as an option to -march, but Clang /// has some logic for recognizing it. // FIXME: Warn, deprecate, and potentially remove this. CK_Penryn, //@} /// \name Atom /// Atom processors //@{ CK_Bonnell, CK_Silvermont, //@} /// \name Nehalem /// Nehalem microarchitecture based processors. CK_Nehalem, /// \name Westmere /// Westmere microarchitecture based processors. CK_Westmere, /// \name Sandy Bridge /// Sandy Bridge microarchitecture based processors. CK_SandyBridge, /// \name Ivy Bridge /// Ivy Bridge microarchitecture based processors. CK_IvyBridge, /// \name Haswell /// Haswell microarchitecture based processors. CK_Haswell, /// \name Broadwell /// Broadwell microarchitecture based processors. CK_Broadwell, /// \name Skylake /// Skylake microarchitecture based processors. CK_Skylake, /// \name Knights Landing /// Knights Landing processor. CK_KNL, /// \name K6 /// K6 architecture processors. //@{ CK_K6, CK_K6_2, CK_K6_3, //@} /// \name K7 /// K7 architecture processors. //@{ CK_Athlon, CK_AthlonThunderbird, CK_Athlon4, CK_AthlonXP, CK_AthlonMP, //@} /// \name K8 /// K8 architecture processors. //@{ CK_Athlon64, CK_Athlon64SSE3, CK_AthlonFX, CK_K8, CK_K8SSE3, CK_Opteron, CK_OpteronSSE3, CK_AMDFAM10, //@} /// \name Bobcat /// Bobcat architecture processors. //@{ CK_BTVER1, CK_BTVER2, //@} /// \name Bulldozer /// Bulldozer architecture processors. //@{ CK_BDVER1, CK_BDVER2, CK_BDVER3, CK_BDVER4, //@} /// This specification is deprecated and will be removed in the future. /// Users should prefer \see CK_K8. // FIXME: Warn on this when the CPU is set to it. //@{ CK_x86_64, //@} /// \name Geode /// Geode processors. //@{ CK_Geode //@} } CPU = CK_Generic; CPUKind getCPUKind(StringRef CPU) const { return llvm::StringSwitch(CPU) .Case("i386", CK_i386) .Case("i486", CK_i486) .Case("winchip-c6", CK_WinChipC6) .Case("winchip2", CK_WinChip2) .Case("c3", CK_C3) .Case("i586", CK_i586) .Case("pentium", CK_Pentium) .Case("pentium-mmx", CK_PentiumMMX) .Case("i686", CK_i686) .Case("pentiumpro", CK_PentiumPro) .Case("pentium2", CK_Pentium2) .Case("pentium3", CK_Pentium3) .Case("pentium3m", CK_Pentium3M) .Case("pentium-m", CK_PentiumM) .Case("c3-2", CK_C3_2) .Case("yonah", CK_Yonah) .Case("pentium4", CK_Pentium4) .Case("pentium4m", CK_Pentium4M) .Case("prescott", CK_Prescott) .Case("nocona", CK_Nocona) .Case("core2", CK_Core2) .Case("penryn", CK_Penryn) .Case("bonnell", CK_Bonnell) .Case("atom", CK_Bonnell) // Legacy name. .Case("silvermont", CK_Silvermont) .Case("slm", CK_Silvermont) // Legacy name. .Case("nehalem", CK_Nehalem) .Case("corei7", CK_Nehalem) // Legacy name. .Case("westmere", CK_Westmere) .Case("sandybridge", CK_SandyBridge) .Case("corei7-avx", CK_SandyBridge) // Legacy name. .Case("ivybridge", CK_IvyBridge) .Case("core-avx-i", CK_IvyBridge) // Legacy name. .Case("haswell", CK_Haswell) .Case("core-avx2", CK_Haswell) // Legacy name. .Case("broadwell", CK_Broadwell) .Case("skylake", CK_Skylake) .Case("skx", CK_Skylake) // Legacy name. .Case("knl", CK_KNL) .Case("k6", CK_K6) .Case("k6-2", CK_K6_2) .Case("k6-3", CK_K6_3) .Case("athlon", CK_Athlon) .Case("athlon-tbird", CK_AthlonThunderbird) .Case("athlon-4", CK_Athlon4) .Case("athlon-xp", CK_AthlonXP) .Case("athlon-mp", CK_AthlonMP) .Case("athlon64", CK_Athlon64) .Case("athlon64-sse3", CK_Athlon64SSE3) .Case("athlon-fx", CK_AthlonFX) .Case("k8", CK_K8) .Case("k8-sse3", CK_K8SSE3) .Case("opteron", CK_Opteron) .Case("opteron-sse3", CK_OpteronSSE3) .Case("barcelona", CK_AMDFAM10) .Case("amdfam10", CK_AMDFAM10) .Case("btver1", CK_BTVER1) .Case("btver2", CK_BTVER2) .Case("bdver1", CK_BDVER1) .Case("bdver2", CK_BDVER2) .Case("bdver3", CK_BDVER3) .Case("bdver4", CK_BDVER4) .Case("x86-64", CK_x86_64) .Case("geode", CK_Geode) .Default(CK_Generic); } enum FPMathKind { FP_Default, FP_SSE, FP_387 } FPMath = FP_Default; public: X86TargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { BigEndian = false; LongDoubleFormat = &llvm::APFloat::x87DoubleExtended; } unsigned getFloatEvalMethod() const override { // X87 evaluates with 80 bits "long double" precision. return SSELevel == NoSSE ? 2 : 0; } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::X86::LastTSBuiltin-Builtin::FirstTSBuiltin); } ArrayRef getGCCRegNames() const override { return llvm::makeArrayRef(GCCRegNames); } ArrayRef getGCCRegAliases() const override { return None; } ArrayRef getGCCAddlRegNames() const override { return llvm::makeArrayRef(AddlRegNames); } bool validateCpuSupports(StringRef Name) const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override; bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize, bool &HasSizeMismatch) const override { // esp and ebp are the only 32-bit registers the x86 backend can currently // handle. if (RegName.equals("esp") || RegName.equals("ebp")) { // Check that the register size is 32-bit. HasSizeMismatch = RegSize != 32; return true; } return false; } bool validateOutputSize(StringRef Constraint, unsigned Size) const override; bool validateInputSize(StringRef Constraint, unsigned Size) const override; virtual bool validateOperandSize(StringRef Constraint, unsigned Size) const; std::string convertConstraint(const char *&Constraint) const override; const char *getClobbers() const override { return "~{dirflag},~{fpsr},~{flags}"; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; static void setSSELevel(llvm::StringMap &Features, X86SSEEnum Level, bool Enabled); static void setMMXLevel(llvm::StringMap &Features, MMX3DNowEnum Level, bool Enabled); static void setXOPLevel(llvm::StringMap &Features, XOPEnum Level, bool Enabled); void setFeatureEnabled(llvm::StringMap &Features, StringRef Name, bool Enabled) const override { setFeatureEnabledImpl(Features, Name, Enabled); } // This exists purely to cut down on the number of virtual calls in // initFeatureMap which calls this repeatedly. static void setFeatureEnabledImpl(llvm::StringMap &Features, StringRef Name, bool Enabled); bool initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const override; bool hasFeature(StringRef Feature) const override; bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override; StringRef getABI() const override { if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX512F) return "avx512"; if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX) return "avx"; if (getTriple().getArch() == llvm::Triple::x86 && MMX3DNowLevel == NoMMX3DNow) return "no-mmx"; return ""; } bool setCPU(const std::string &Name) override { CPU = getCPUKind(Name); // Perform any per-CPU checks necessary to determine if this CPU is // acceptable. // FIXME: This results in terrible diagnostics. Clang just says the CPU is // invalid without explaining *why*. switch (CPU) { case CK_Generic: // No processor selected! return false; case CK_i386: case CK_i486: case CK_WinChipC6: case CK_WinChip2: case CK_C3: case CK_i586: case CK_Pentium: case CK_PentiumMMX: case CK_i686: case CK_PentiumPro: case CK_Pentium2: case CK_Pentium3: case CK_Pentium3M: case CK_PentiumM: case CK_Yonah: case CK_C3_2: case CK_Pentium4: case CK_Pentium4M: case CK_Prescott: case CK_K6: case CK_K6_2: case CK_K6_3: case CK_Athlon: case CK_AthlonThunderbird: case CK_Athlon4: case CK_AthlonXP: case CK_AthlonMP: case CK_Geode: // Only accept certain architectures when compiling in 32-bit mode. if (getTriple().getArch() != llvm::Triple::x86) return false; // Fallthrough case CK_Nocona: case CK_Core2: case CK_Penryn: case CK_Bonnell: case CK_Silvermont: case CK_Nehalem: case CK_Westmere: case CK_SandyBridge: case CK_IvyBridge: case CK_Haswell: case CK_Broadwell: case CK_Skylake: case CK_KNL: case CK_Athlon64: case CK_Athlon64SSE3: case CK_AthlonFX: case CK_K8: case CK_K8SSE3: case CK_Opteron: case CK_OpteronSSE3: case CK_AMDFAM10: case CK_BTVER1: case CK_BTVER2: case CK_BDVER1: case CK_BDVER2: case CK_BDVER3: case CK_BDVER4: case CK_x86_64: return true; } llvm_unreachable("Unhandled CPU kind"); } bool setFPMath(StringRef Name) override; CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { // We accept all non-ARM calling conventions return (CC == CC_X86ThisCall || CC == CC_X86FastCall || CC == CC_X86StdCall || CC == CC_X86VectorCall || CC == CC_C || CC == CC_X86Pascal || CC == CC_IntelOclBicc) ? CCCR_OK : CCCR_Warning; } CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { return MT == CCMT_Member ? CC_X86ThisCall : CC_C; } bool hasSjLjLowering() const override { return true; } }; bool X86TargetInfo::setFPMath(StringRef Name) { if (Name == "387") { FPMath = FP_387; return true; } if (Name == "sse") { FPMath = FP_SSE; return true; } return false; } bool X86TargetInfo::initFeatureMap( llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const { // FIXME: This *really* should not be here. // X86_64 always has SSE2. if (getTriple().getArch() == llvm::Triple::x86_64) setFeatureEnabledImpl(Features, "sse2", true); switch (getCPUKind(CPU)) { case CK_Generic: case CK_i386: case CK_i486: case CK_i586: case CK_Pentium: case CK_i686: case CK_PentiumPro: break; case CK_PentiumMMX: case CK_Pentium2: case CK_K6: case CK_WinChipC6: setFeatureEnabledImpl(Features, "mmx", true); break; case CK_Pentium3: case CK_Pentium3M: case CK_C3_2: setFeatureEnabledImpl(Features, "sse", true); setFeatureEnabledImpl(Features, "fxsr", true); break; case CK_PentiumM: case CK_Pentium4: case CK_Pentium4M: case CK_x86_64: setFeatureEnabledImpl(Features, "sse2", true); setFeatureEnabledImpl(Features, "fxsr", true); break; case CK_Yonah: case CK_Prescott: case CK_Nocona: setFeatureEnabledImpl(Features, "sse3", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "cx16", true); break; case CK_Core2: case CK_Bonnell: setFeatureEnabledImpl(Features, "ssse3", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "cx16", true); break; case CK_Penryn: setFeatureEnabledImpl(Features, "sse4.1", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "cx16", true); break; case CK_Skylake: setFeatureEnabledImpl(Features, "avx512f", true); setFeatureEnabledImpl(Features, "avx512cd", true); setFeatureEnabledImpl(Features, "avx512dq", true); setFeatureEnabledImpl(Features, "avx512bw", true); setFeatureEnabledImpl(Features, "avx512vl", true); setFeatureEnabledImpl(Features, "xsavec", true); setFeatureEnabledImpl(Features, "xsaves", true); setFeatureEnabledImpl(Features, "pku", true); // FALLTHROUGH case CK_Broadwell: setFeatureEnabledImpl(Features, "rdseed", true); setFeatureEnabledImpl(Features, "adx", true); // FALLTHROUGH case CK_Haswell: setFeatureEnabledImpl(Features, "avx2", true); setFeatureEnabledImpl(Features, "lzcnt", true); setFeatureEnabledImpl(Features, "bmi", true); setFeatureEnabledImpl(Features, "bmi2", true); setFeatureEnabledImpl(Features, "rtm", true); setFeatureEnabledImpl(Features, "fma", true); // FALLTHROUGH case CK_IvyBridge: setFeatureEnabledImpl(Features, "rdrnd", true); setFeatureEnabledImpl(Features, "f16c", true); setFeatureEnabledImpl(Features, "fsgsbase", true); // FALLTHROUGH case CK_SandyBridge: setFeatureEnabledImpl(Features, "avx", true); setFeatureEnabledImpl(Features, "xsave", true); setFeatureEnabledImpl(Features, "xsaveopt", true); // FALLTHROUGH case CK_Westmere: case CK_Silvermont: setFeatureEnabledImpl(Features, "aes", true); setFeatureEnabledImpl(Features, "pclmul", true); // FALLTHROUGH case CK_Nehalem: setFeatureEnabledImpl(Features, "sse4.2", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "cx16", true); break; case CK_KNL: setFeatureEnabledImpl(Features, "avx512f", true); setFeatureEnabledImpl(Features, "avx512cd", true); setFeatureEnabledImpl(Features, "avx512er", true); setFeatureEnabledImpl(Features, "avx512pf", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "rdseed", true); setFeatureEnabledImpl(Features, "adx", true); setFeatureEnabledImpl(Features, "lzcnt", true); setFeatureEnabledImpl(Features, "bmi", true); setFeatureEnabledImpl(Features, "bmi2", true); setFeatureEnabledImpl(Features, "rtm", true); setFeatureEnabledImpl(Features, "fma", true); setFeatureEnabledImpl(Features, "rdrnd", true); setFeatureEnabledImpl(Features, "f16c", true); setFeatureEnabledImpl(Features, "fsgsbase", true); setFeatureEnabledImpl(Features, "aes", true); setFeatureEnabledImpl(Features, "pclmul", true); setFeatureEnabledImpl(Features, "cx16", true); setFeatureEnabledImpl(Features, "xsaveopt", true); setFeatureEnabledImpl(Features, "xsave", true); break; case CK_K6_2: case CK_K6_3: case CK_WinChip2: case CK_C3: setFeatureEnabledImpl(Features, "3dnow", true); break; case CK_Athlon: case CK_AthlonThunderbird: case CK_Geode: setFeatureEnabledImpl(Features, "3dnowa", true); break; case CK_Athlon4: case CK_AthlonXP: case CK_AthlonMP: setFeatureEnabledImpl(Features, "sse", true); setFeatureEnabledImpl(Features, "3dnowa", true); setFeatureEnabledImpl(Features, "fxsr", true); break; case CK_K8: case CK_Opteron: case CK_Athlon64: case CK_AthlonFX: setFeatureEnabledImpl(Features, "sse2", true); setFeatureEnabledImpl(Features, "3dnowa", true); setFeatureEnabledImpl(Features, "fxsr", true); break; case CK_AMDFAM10: setFeatureEnabledImpl(Features, "sse4a", true); setFeatureEnabledImpl(Features, "lzcnt", true); setFeatureEnabledImpl(Features, "popcnt", true); // FALLTHROUGH case CK_K8SSE3: case CK_OpteronSSE3: case CK_Athlon64SSE3: setFeatureEnabledImpl(Features, "sse3", true); setFeatureEnabledImpl(Features, "3dnowa", true); setFeatureEnabledImpl(Features, "fxsr", true); break; case CK_BTVER2: setFeatureEnabledImpl(Features, "avx", true); setFeatureEnabledImpl(Features, "aes", true); setFeatureEnabledImpl(Features, "pclmul", true); setFeatureEnabledImpl(Features, "bmi", true); setFeatureEnabledImpl(Features, "f16c", true); setFeatureEnabledImpl(Features, "xsaveopt", true); // FALLTHROUGH case CK_BTVER1: setFeatureEnabledImpl(Features, "ssse3", true); setFeatureEnabledImpl(Features, "sse4a", true); setFeatureEnabledImpl(Features, "lzcnt", true); setFeatureEnabledImpl(Features, "popcnt", true); setFeatureEnabledImpl(Features, "prfchw", true); setFeatureEnabledImpl(Features, "cx16", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "xsave", true); break; case CK_BDVER4: setFeatureEnabledImpl(Features, "avx2", true); setFeatureEnabledImpl(Features, "bmi2", true); // FALLTHROUGH case CK_BDVER3: setFeatureEnabledImpl(Features, "fsgsbase", true); setFeatureEnabledImpl(Features, "xsaveopt", true); // FALLTHROUGH case CK_BDVER2: setFeatureEnabledImpl(Features, "bmi", true); setFeatureEnabledImpl(Features, "fma", true); setFeatureEnabledImpl(Features, "f16c", true); setFeatureEnabledImpl(Features, "tbm", true); // FALLTHROUGH case CK_BDVER1: // xop implies avx, sse4a and fma4. setFeatureEnabledImpl(Features, "xop", true); setFeatureEnabledImpl(Features, "lzcnt", true); setFeatureEnabledImpl(Features, "aes", true); setFeatureEnabledImpl(Features, "pclmul", true); setFeatureEnabledImpl(Features, "prfchw", true); setFeatureEnabledImpl(Features, "cx16", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "xsave", true); break; } if (!TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec)) return false; // Can't do this earlier because we need to be able to explicitly enable // or disable these features and the things that they depend upon. // Enable popcnt if sse4.2 is enabled and popcnt is not explicitly disabled. auto I = Features.find("sse4.2"); if (I != Features.end() && I->getValue() && std::find(FeaturesVec.begin(), FeaturesVec.end(), "-popcnt") == FeaturesVec.end()) Features["popcnt"] = true; // Enable prfchw if 3DNow! is enabled and prfchw is not explicitly disabled. I = Features.find("3dnow"); if (I != Features.end() && I->getValue() && std::find(FeaturesVec.begin(), FeaturesVec.end(), "-prfchw") == FeaturesVec.end()) Features["prfchw"] = true; // Additionally, if SSE is enabled and mmx is not explicitly disabled, // then enable MMX. I = Features.find("sse"); if (I != Features.end() && I->getValue() && std::find(FeaturesVec.begin(), FeaturesVec.end(), "-mmx") == FeaturesVec.end()) Features["mmx"] = true; return true; } void X86TargetInfo::setSSELevel(llvm::StringMap &Features, X86SSEEnum Level, bool Enabled) { if (Enabled) { switch (Level) { case AVX512F: Features["avx512f"] = true; case AVX2: Features["avx2"] = true; case AVX: Features["avx"] = true; Features["xsave"] = true; case SSE42: Features["sse4.2"] = true; case SSE41: Features["sse4.1"] = true; case SSSE3: Features["ssse3"] = true; case SSE3: Features["sse3"] = true; case SSE2: Features["sse2"] = true; case SSE1: Features["sse"] = true; case NoSSE: break; } return; } switch (Level) { case NoSSE: case SSE1: Features["sse"] = false; case SSE2: Features["sse2"] = Features["pclmul"] = Features["aes"] = Features["sha"] = false; case SSE3: Features["sse3"] = false; setXOPLevel(Features, NoXOP, false); case SSSE3: Features["ssse3"] = false; case SSE41: Features["sse4.1"] = false; case SSE42: Features["sse4.2"] = false; case AVX: Features["fma"] = Features["avx"] = Features["f16c"] = Features["xsave"] = Features["xsaveopt"] = false; setXOPLevel(Features, FMA4, false); case AVX2: Features["avx2"] = false; case AVX512F: Features["avx512f"] = Features["avx512cd"] = Features["avx512er"] = Features["avx512pf"] = Features["avx512dq"] = Features["avx512bw"] = Features["avx512vl"] = false; } } void X86TargetInfo::setMMXLevel(llvm::StringMap &Features, MMX3DNowEnum Level, bool Enabled) { if (Enabled) { switch (Level) { case AMD3DNowAthlon: Features["3dnowa"] = true; case AMD3DNow: Features["3dnow"] = true; case MMX: Features["mmx"] = true; case NoMMX3DNow: break; } return; } switch (Level) { case NoMMX3DNow: case MMX: Features["mmx"] = false; case AMD3DNow: Features["3dnow"] = false; case AMD3DNowAthlon: Features["3dnowa"] = false; } } void X86TargetInfo::setXOPLevel(llvm::StringMap &Features, XOPEnum Level, bool Enabled) { if (Enabled) { switch (Level) { case XOP: Features["xop"] = true; case FMA4: Features["fma4"] = true; setSSELevel(Features, AVX, true); case SSE4A: Features["sse4a"] = true; setSSELevel(Features, SSE3, true); case NoXOP: break; } return; } switch (Level) { case NoXOP: case SSE4A: Features["sse4a"] = false; case FMA4: Features["fma4"] = false; case XOP: Features["xop"] = false; } } void X86TargetInfo::setFeatureEnabledImpl(llvm::StringMap &Features, StringRef Name, bool Enabled) { // This is a bit of a hack to deal with the sse4 target feature when used // as part of the target attribute. We handle sse4 correctly everywhere // else. See below for more information on how we handle the sse4 options. if (Name != "sse4") Features[Name] = Enabled; if (Name == "mmx") { setMMXLevel(Features, MMX, Enabled); } else if (Name == "sse") { setSSELevel(Features, SSE1, Enabled); } else if (Name == "sse2") { setSSELevel(Features, SSE2, Enabled); } else if (Name == "sse3") { setSSELevel(Features, SSE3, Enabled); } else if (Name == "ssse3") { setSSELevel(Features, SSSE3, Enabled); } else if (Name == "sse4.2") { setSSELevel(Features, SSE42, Enabled); } else if (Name == "sse4.1") { setSSELevel(Features, SSE41, Enabled); } else if (Name == "3dnow") { setMMXLevel(Features, AMD3DNow, Enabled); } else if (Name == "3dnowa") { setMMXLevel(Features, AMD3DNowAthlon, Enabled); } else if (Name == "aes") { if (Enabled) setSSELevel(Features, SSE2, Enabled); } else if (Name == "pclmul") { if (Enabled) setSSELevel(Features, SSE2, Enabled); } else if (Name == "avx") { setSSELevel(Features, AVX, Enabled); } else if (Name == "avx2") { setSSELevel(Features, AVX2, Enabled); } else if (Name == "avx512f") { setSSELevel(Features, AVX512F, Enabled); } else if (Name == "avx512cd" || Name == "avx512er" || Name == "avx512pf" || Name == "avx512dq" || Name == "avx512bw" || Name == "avx512vl") { if (Enabled) setSSELevel(Features, AVX512F, Enabled); } else if (Name == "fma") { if (Enabled) setSSELevel(Features, AVX, Enabled); } else if (Name == "fma4") { setXOPLevel(Features, FMA4, Enabled); } else if (Name == "xop") { setXOPLevel(Features, XOP, Enabled); } else if (Name == "sse4a") { setXOPLevel(Features, SSE4A, Enabled); } else if (Name == "f16c") { if (Enabled) setSSELevel(Features, AVX, Enabled); } else if (Name == "sha") { if (Enabled) setSSELevel(Features, SSE2, Enabled); } else if (Name == "sse4") { // We can get here via the __target__ attribute since that's not controlled // via the -msse4/-mno-sse4 command line alias. Handle this the same way // here - turn on the sse4.2 if enabled, turn off the sse4.1 level if // disabled. if (Enabled) setSSELevel(Features, SSE42, Enabled); else setSSELevel(Features, SSE41, Enabled); } else if (Name == "xsave") { if (Enabled) setSSELevel(Features, AVX, Enabled); else Features["xsaveopt"] = false; } else if (Name == "xsaveopt" || Name == "xsavec" || Name == "xsaves") { if (Enabled) { Features["xsave"] = true; setSSELevel(Features, AVX, Enabled); } } } /// handleTargetFeatures - Perform initialization based on the user /// configured set of features. bool X86TargetInfo::handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) { for (const auto &Feature : Features) { if (Feature[0] != '+') continue; if (Feature == "+aes") { HasAES = true; } else if (Feature == "+pclmul") { HasPCLMUL = true; } else if (Feature == "+lzcnt") { HasLZCNT = true; } else if (Feature == "+rdrnd") { HasRDRND = true; } else if (Feature == "+fsgsbase") { HasFSGSBASE = true; } else if (Feature == "+bmi") { HasBMI = true; } else if (Feature == "+bmi2") { HasBMI2 = true; } else if (Feature == "+popcnt") { HasPOPCNT = true; } else if (Feature == "+rtm") { HasRTM = true; } else if (Feature == "+prfchw") { HasPRFCHW = true; } else if (Feature == "+rdseed") { HasRDSEED = true; } else if (Feature == "+adx") { HasADX = true; } else if (Feature == "+tbm") { HasTBM = true; } else if (Feature == "+fma") { HasFMA = true; } else if (Feature == "+f16c") { HasF16C = true; } else if (Feature == "+avx512cd") { HasAVX512CD = true; } else if (Feature == "+avx512er") { HasAVX512ER = true; } else if (Feature == "+avx512pf") { HasAVX512PF = true; } else if (Feature == "+avx512dq") { HasAVX512DQ = true; } else if (Feature == "+avx512bw") { HasAVX512BW = true; } else if (Feature == "+avx512vl") { HasAVX512VL = true; } else if (Feature == "+sha") { HasSHA = true; } else if (Feature == "+cx16") { HasCX16 = true; } else if (Feature == "+fxsr") { HasFXSR = true; } else if (Feature == "+xsave") { HasXSAVE = true; } else if (Feature == "+xsaveopt") { HasXSAVEOPT = true; } else if (Feature == "+xsavec") { HasXSAVEC = true; } else if (Feature == "+xsaves") { HasXSAVES = true; } else if (Feature == "+pku") { HasPKU = true; } X86SSEEnum Level = llvm::StringSwitch(Feature) .Case("+avx512f", AVX512F) .Case("+avx2", AVX2) .Case("+avx", AVX) .Case("+sse4.2", SSE42) .Case("+sse4.1", SSE41) .Case("+ssse3", SSSE3) .Case("+sse3", SSE3) .Case("+sse2", SSE2) .Case("+sse", SSE1) .Default(NoSSE); SSELevel = std::max(SSELevel, Level); MMX3DNowEnum ThreeDNowLevel = llvm::StringSwitch(Feature) .Case("+3dnowa", AMD3DNowAthlon) .Case("+3dnow", AMD3DNow) .Case("+mmx", MMX) .Default(NoMMX3DNow); MMX3DNowLevel = std::max(MMX3DNowLevel, ThreeDNowLevel); XOPEnum XLevel = llvm::StringSwitch(Feature) .Case("+xop", XOP) .Case("+fma4", FMA4) .Case("+sse4a", SSE4A) .Default(NoXOP); XOPLevel = std::max(XOPLevel, XLevel); } // LLVM doesn't have a separate switch for fpmath, so only accept it if it // matches the selected sse level. if ((FPMath == FP_SSE && SSELevel < SSE1) || (FPMath == FP_387 && SSELevel >= SSE1)) { Diags.Report(diag::err_target_unsupported_fpmath) << (FPMath == FP_SSE ? "sse" : "387"); return false; } SimdDefaultAlign = hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; return true; } /// X86TargetInfo::getTargetDefines - Return the set of the X86-specific macro /// definitions for this particular subtarget. void X86TargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { // Target identification. if (getTriple().getArch() == llvm::Triple::x86_64) { Builder.defineMacro("__amd64__"); Builder.defineMacro("__amd64"); Builder.defineMacro("__x86_64"); Builder.defineMacro("__x86_64__"); if (getTriple().getArchName() == "x86_64h") { Builder.defineMacro("__x86_64h"); Builder.defineMacro("__x86_64h__"); } } else { DefineStd(Builder, "i386", Opts); } // Subtarget options. // FIXME: We are hard-coding the tune parameters based on the CPU, but they // truly should be based on -mtune options. switch (CPU) { case CK_Generic: break; case CK_i386: // The rest are coming from the i386 define above. Builder.defineMacro("__tune_i386__"); break; case CK_i486: case CK_WinChipC6: case CK_WinChip2: case CK_C3: defineCPUMacros(Builder, "i486"); break; case CK_PentiumMMX: Builder.defineMacro("__pentium_mmx__"); Builder.defineMacro("__tune_pentium_mmx__"); // Fallthrough case CK_i586: case CK_Pentium: defineCPUMacros(Builder, "i586"); defineCPUMacros(Builder, "pentium"); break; case CK_Pentium3: case CK_Pentium3M: case CK_PentiumM: Builder.defineMacro("__tune_pentium3__"); // Fallthrough case CK_Pentium2: case CK_C3_2: Builder.defineMacro("__tune_pentium2__"); // Fallthrough case CK_PentiumPro: Builder.defineMacro("__tune_i686__"); Builder.defineMacro("__tune_pentiumpro__"); // Fallthrough case CK_i686: Builder.defineMacro("__i686"); Builder.defineMacro("__i686__"); // Strangely, __tune_i686__ isn't defined by GCC when CPU == i686. Builder.defineMacro("__pentiumpro"); Builder.defineMacro("__pentiumpro__"); break; case CK_Pentium4: case CK_Pentium4M: defineCPUMacros(Builder, "pentium4"); break; case CK_Yonah: case CK_Prescott: case CK_Nocona: defineCPUMacros(Builder, "nocona"); break; case CK_Core2: case CK_Penryn: defineCPUMacros(Builder, "core2"); break; case CK_Bonnell: defineCPUMacros(Builder, "atom"); break; case CK_Silvermont: defineCPUMacros(Builder, "slm"); break; case CK_Nehalem: case CK_Westmere: case CK_SandyBridge: case CK_IvyBridge: case CK_Haswell: case CK_Broadwell: // FIXME: Historically, we defined this legacy name, it would be nice to // remove it at some point. We've never exposed fine-grained names for // recent primary x86 CPUs, and we should keep it that way. defineCPUMacros(Builder, "corei7"); break; case CK_Skylake: // FIXME: Historically, we defined this legacy name, it would be nice to // remove it at some point. This is the only fine-grained CPU macro in the // main intel CPU line, and it would be better to not have these and force // people to use ISA macros. defineCPUMacros(Builder, "skx"); break; case CK_KNL: defineCPUMacros(Builder, "knl"); break; case CK_K6_2: Builder.defineMacro("__k6_2__"); Builder.defineMacro("__tune_k6_2__"); // Fallthrough case CK_K6_3: if (CPU != CK_K6_2) { // In case of fallthrough // FIXME: GCC may be enabling these in cases where some other k6 // architecture is specified but -m3dnow is explicitly provided. The // exact semantics need to be determined and emulated here. Builder.defineMacro("__k6_3__"); Builder.defineMacro("__tune_k6_3__"); } // Fallthrough case CK_K6: defineCPUMacros(Builder, "k6"); break; case CK_Athlon: case CK_AthlonThunderbird: case CK_Athlon4: case CK_AthlonXP: case CK_AthlonMP: defineCPUMacros(Builder, "athlon"); if (SSELevel != NoSSE) { Builder.defineMacro("__athlon_sse__"); Builder.defineMacro("__tune_athlon_sse__"); } break; case CK_K8: case CK_K8SSE3: case CK_x86_64: case CK_Opteron: case CK_OpteronSSE3: case CK_Athlon64: case CK_Athlon64SSE3: case CK_AthlonFX: defineCPUMacros(Builder, "k8"); break; case CK_AMDFAM10: defineCPUMacros(Builder, "amdfam10"); break; case CK_BTVER1: defineCPUMacros(Builder, "btver1"); break; case CK_BTVER2: defineCPUMacros(Builder, "btver2"); break; case CK_BDVER1: defineCPUMacros(Builder, "bdver1"); break; case CK_BDVER2: defineCPUMacros(Builder, "bdver2"); break; case CK_BDVER3: defineCPUMacros(Builder, "bdver3"); break; case CK_BDVER4: defineCPUMacros(Builder, "bdver4"); break; case CK_Geode: defineCPUMacros(Builder, "geode"); break; } // Target properties. Builder.defineMacro("__REGISTER_PREFIX__", ""); // Define __NO_MATH_INLINES on linux/x86 so that we don't get inline // functions in glibc header files that use FP Stack inline asm which the // backend can't deal with (PR879). Builder.defineMacro("__NO_MATH_INLINES"); if (HasAES) Builder.defineMacro("__AES__"); if (HasPCLMUL) Builder.defineMacro("__PCLMUL__"); if (HasLZCNT) Builder.defineMacro("__LZCNT__"); if (HasRDRND) Builder.defineMacro("__RDRND__"); if (HasFSGSBASE) Builder.defineMacro("__FSGSBASE__"); if (HasBMI) Builder.defineMacro("__BMI__"); if (HasBMI2) Builder.defineMacro("__BMI2__"); if (HasPOPCNT) Builder.defineMacro("__POPCNT__"); if (HasRTM) Builder.defineMacro("__RTM__"); if (HasPRFCHW) Builder.defineMacro("__PRFCHW__"); if (HasRDSEED) Builder.defineMacro("__RDSEED__"); if (HasADX) Builder.defineMacro("__ADX__"); if (HasTBM) Builder.defineMacro("__TBM__"); switch (XOPLevel) { case XOP: Builder.defineMacro("__XOP__"); case FMA4: Builder.defineMacro("__FMA4__"); case SSE4A: Builder.defineMacro("__SSE4A__"); case NoXOP: break; } if (HasFMA) Builder.defineMacro("__FMA__"); if (HasF16C) Builder.defineMacro("__F16C__"); if (HasAVX512CD) Builder.defineMacro("__AVX512CD__"); if (HasAVX512ER) Builder.defineMacro("__AVX512ER__"); if (HasAVX512PF) Builder.defineMacro("__AVX512PF__"); if (HasAVX512DQ) Builder.defineMacro("__AVX512DQ__"); if (HasAVX512BW) Builder.defineMacro("__AVX512BW__"); if (HasAVX512VL) Builder.defineMacro("__AVX512VL__"); if (HasSHA) Builder.defineMacro("__SHA__"); if (HasFXSR) Builder.defineMacro("__FXSR__"); if (HasXSAVE) Builder.defineMacro("__XSAVE__"); if (HasXSAVEOPT) Builder.defineMacro("__XSAVEOPT__"); if (HasXSAVEC) Builder.defineMacro("__XSAVEC__"); if (HasXSAVES) Builder.defineMacro("__XSAVES__"); if (HasPKU) Builder.defineMacro("__PKU__"); if (HasCX16) Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16"); // Each case falls through to the previous one here. switch (SSELevel) { case AVX512F: Builder.defineMacro("__AVX512F__"); case AVX2: Builder.defineMacro("__AVX2__"); case AVX: Builder.defineMacro("__AVX__"); case SSE42: Builder.defineMacro("__SSE4_2__"); case SSE41: Builder.defineMacro("__SSE4_1__"); case SSSE3: Builder.defineMacro("__SSSE3__"); case SSE3: Builder.defineMacro("__SSE3__"); case SSE2: Builder.defineMacro("__SSE2__"); Builder.defineMacro("__SSE2_MATH__"); // -mfp-math=sse always implied. case SSE1: Builder.defineMacro("__SSE__"); Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied. case NoSSE: break; } if (Opts.MicrosoftExt && getTriple().getArch() == llvm::Triple::x86) { switch (SSELevel) { case AVX512F: case AVX2: case AVX: case SSE42: case SSE41: case SSSE3: case SSE3: case SSE2: Builder.defineMacro("_M_IX86_FP", Twine(2)); break; case SSE1: Builder.defineMacro("_M_IX86_FP", Twine(1)); break; default: Builder.defineMacro("_M_IX86_FP", Twine(0)); } } // Each case falls through to the previous one here. switch (MMX3DNowLevel) { case AMD3DNowAthlon: Builder.defineMacro("__3dNOW_A__"); case AMD3DNow: Builder.defineMacro("__3dNOW__"); case MMX: Builder.defineMacro("__MMX__"); case NoMMX3DNow: break; } if (CPU >= CK_i486) { Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); } if (CPU >= CK_i586) Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); } bool X86TargetInfo::hasFeature(StringRef Feature) const { return llvm::StringSwitch(Feature) .Case("aes", HasAES) .Case("avx", SSELevel >= AVX) .Case("avx2", SSELevel >= AVX2) .Case("avx512f", SSELevel >= AVX512F) .Case("avx512cd", HasAVX512CD) .Case("avx512er", HasAVX512ER) .Case("avx512pf", HasAVX512PF) .Case("avx512dq", HasAVX512DQ) .Case("avx512bw", HasAVX512BW) .Case("avx512vl", HasAVX512VL) .Case("bmi", HasBMI) .Case("bmi2", HasBMI2) .Case("cx16", HasCX16) .Case("f16c", HasF16C) .Case("fma", HasFMA) .Case("fma4", XOPLevel >= FMA4) .Case("fsgsbase", HasFSGSBASE) .Case("fxsr", HasFXSR) .Case("lzcnt", HasLZCNT) .Case("mm3dnow", MMX3DNowLevel >= AMD3DNow) .Case("mm3dnowa", MMX3DNowLevel >= AMD3DNowAthlon) .Case("mmx", MMX3DNowLevel >= MMX) .Case("pclmul", HasPCLMUL) .Case("popcnt", HasPOPCNT) .Case("prfchw", HasPRFCHW) .Case("rdrnd", HasRDRND) .Case("rdseed", HasRDSEED) .Case("rtm", HasRTM) .Case("sha", HasSHA) .Case("sse", SSELevel >= SSE1) .Case("sse2", SSELevel >= SSE2) .Case("sse3", SSELevel >= SSE3) .Case("ssse3", SSELevel >= SSSE3) .Case("sse4.1", SSELevel >= SSE41) .Case("sse4.2", SSELevel >= SSE42) .Case("sse4a", XOPLevel >= SSE4A) .Case("tbm", HasTBM) .Case("x86", true) .Case("x86_32", getTriple().getArch() == llvm::Triple::x86) .Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64) .Case("xop", XOPLevel >= XOP) .Case("xsave", HasXSAVE) .Case("xsavec", HasXSAVEC) .Case("xsaves", HasXSAVES) .Case("xsaveopt", HasXSAVEOPT) .Case("pku", HasPKU) .Default(false); } // We can't use a generic validation scheme for the features accepted here // versus subtarget features accepted in the target attribute because the // bitfield structure that's initialized in the runtime only supports the // below currently rather than the full range of subtarget features. (See // X86TargetInfo::hasFeature for a somewhat comprehensive list). bool X86TargetInfo::validateCpuSupports(StringRef FeatureStr) const { return llvm::StringSwitch(FeatureStr) .Case("cmov", true) .Case("mmx", true) .Case("popcnt", true) .Case("sse", true) .Case("sse2", true) .Case("sse3", true) .Case("sse4.1", true) .Case("sse4.2", true) .Case("avx", true) .Case("avx2", true) .Case("sse4a", true) .Case("fma4", true) .Case("xop", true) .Case("fma", true) .Case("avx512f", true) .Case("bmi", true) .Case("bmi2", true) .Default(false); } bool X86TargetInfo::validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const { switch (*Name) { default: return false; // Constant constraints. case 'e': // 32-bit signed integer constant for use with sign-extending x86_64 // instructions. case 'Z': // 32-bit unsigned integer constant for use with zero-extending // x86_64 instructions. case 's': Info.setRequiresImmediate(); return true; case 'I': Info.setRequiresImmediate(0, 31); return true; case 'J': Info.setRequiresImmediate(0, 63); return true; case 'K': Info.setRequiresImmediate(-128, 127); return true; case 'L': Info.setRequiresImmediate({ int(0xff), int(0xffff), int(0xffffffff) }); return true; case 'M': Info.setRequiresImmediate(0, 3); return true; case 'N': Info.setRequiresImmediate(0, 255); return true; case 'O': Info.setRequiresImmediate(0, 127); return true; // Register constraints. case 'Y': // 'Y' is the first character for several 2-character constraints. // Shift the pointer to the second character of the constraint. Name++; switch (*Name) { default: return false; case '0': // First SSE register. case 't': // Any SSE register, when SSE2 is enabled. case 'i': // Any SSE register, when SSE2 and inter-unit moves enabled. case 'm': // Any MMX register, when inter-unit moves enabled. Info.setAllowsRegister(); return true; } case 'f': // Any x87 floating point stack register. // Constraint 'f' cannot be used for output operands. if (Info.ConstraintStr[0] == '=') return false; Info.setAllowsRegister(); return true; case 'a': // eax. case 'b': // ebx. case 'c': // ecx. case 'd': // edx. case 'S': // esi. case 'D': // edi. case 'A': // edx:eax. case 't': // Top of floating point stack. case 'u': // Second from top of floating point stack. case 'q': // Any register accessible as [r]l: a, b, c, and d. case 'y': // Any MMX register. case 'x': // Any SSE register. case 'Q': // Any register accessible as [r]h: a, b, c, and d. case 'R': // "Legacy" registers: ax, bx, cx, dx, di, si, sp, bp. case 'l': // "Index" registers: any general register that can be used as an // index in a base+index memory access. Info.setAllowsRegister(); return true; // Floating point constant constraints. case 'C': // SSE floating point constant. case 'G': // x87 floating point constant. return true; } } bool X86TargetInfo::validateOutputSize(StringRef Constraint, unsigned Size) const { // Strip off constraint modifiers. while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') Constraint = Constraint.substr(1); return validateOperandSize(Constraint, Size); } bool X86TargetInfo::validateInputSize(StringRef Constraint, unsigned Size) const { return validateOperandSize(Constraint, Size); } bool X86TargetInfo::validateOperandSize(StringRef Constraint, unsigned Size) const { switch (Constraint[0]) { default: break; case 'y': return Size <= 64; case 'f': case 't': case 'u': return Size <= 128; case 'x': if (SSELevel >= AVX512F) // 512-bit zmm registers can be used if target supports AVX512F. return Size <= 512U; else if (SSELevel >= AVX) // 256-bit ymm registers can be used if target supports AVX. return Size <= 256U; return Size <= 128U; case 'Y': // 'Y' is the first character for several 2-character constraints. switch (Constraint[1]) { default: break; case 'm': // 'Ym' is synonymous with 'y'. return Size <= 64; case 'i': case 't': // 'Yi' and 'Yt' are synonymous with 'x' when SSE2 is enabled. if (SSELevel >= AVX512F) return Size <= 512U; else if (SSELevel >= AVX) return Size <= 256U; return SSELevel >= SSE2 && Size <= 128U; } } return true; } std::string X86TargetInfo::convertConstraint(const char *&Constraint) const { switch (*Constraint) { case 'a': return std::string("{ax}"); case 'b': return std::string("{bx}"); case 'c': return std::string("{cx}"); case 'd': return std::string("{dx}"); case 'S': return std::string("{si}"); case 'D': return std::string("{di}"); case 'p': // address return std::string("im"); case 't': // top of floating point stack. return std::string("{st}"); case 'u': // second from top of floating point stack. return std::string("{st(1)}"); // second from top of floating point stack. default: return std::string(1, *Constraint); } } // X86-32 generic target class X86_32TargetInfo : public X86TargetInfo { public: X86_32TargetInfo(const llvm::Triple &Triple) : X86TargetInfo(Triple) { DoubleAlign = LongLongAlign = 32; LongDoubleWidth = 96; LongDoubleAlign = 32; SuitableAlign = 128; DataLayoutString = "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128"; SizeType = UnsignedInt; PtrDiffType = SignedInt; IntPtrType = SignedInt; RegParmMax = 3; // Use fpret for all types. RealTypeUsesObjCFPRet = ((1 << TargetInfo::Float) | (1 << TargetInfo::Double) | (1 << TargetInfo::LongDouble)); // x86-32 has atomics up to 8 bytes // FIXME: Check that we actually have cmpxchg8b before setting // MaxAtomicInlineWidth. (cmpxchg8b is an i586 instruction.) MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } int getEHDataRegisterNumber(unsigned RegNo) const override { if (RegNo == 0) return 0; if (RegNo == 1) return 2; return -1; } bool validateOperandSize(StringRef Constraint, unsigned Size) const override { switch (Constraint[0]) { default: break; case 'R': case 'q': case 'Q': case 'a': case 'b': case 'c': case 'd': case 'S': case 'D': return Size <= 32; case 'A': return Size <= 64; } return X86TargetInfo::validateOperandSize(Constraint, Size); } }; class NetBSDI386TargetInfo : public NetBSDTargetInfo { public: NetBSDI386TargetInfo(const llvm::Triple &Triple) : NetBSDTargetInfo(Triple) {} unsigned getFloatEvalMethod() const override { unsigned Major, Minor, Micro; getTriple().getOSVersion(Major, Minor, Micro); // New NetBSD uses the default rounding mode. if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 26) || Major == 0) return X86_32TargetInfo::getFloatEvalMethod(); // NetBSD before 6.99.26 defaults to "double" rounding. return 1; } }; class OpenBSDI386TargetInfo : public OpenBSDTargetInfo { public: OpenBSDI386TargetInfo(const llvm::Triple &Triple) : OpenBSDTargetInfo(Triple) { SizeType = UnsignedLong; IntPtrType = SignedLong; PtrDiffType = SignedLong; } }; class BitrigI386TargetInfo : public BitrigTargetInfo { public: BitrigI386TargetInfo(const llvm::Triple &Triple) : BitrigTargetInfo(Triple) { SizeType = UnsignedLong; IntPtrType = SignedLong; PtrDiffType = SignedLong; } }; class DarwinI386TargetInfo : public DarwinTargetInfo { public: DarwinI386TargetInfo(const llvm::Triple &Triple) : DarwinTargetInfo(Triple) { LongDoubleWidth = 128; LongDoubleAlign = 128; SuitableAlign = 128; MaxVectorAlign = 256; // The watchOS simulator uses the builtin bool type for Objective-C. llvm::Triple T = llvm::Triple(Triple); if (T.isWatchOS()) UseSignedCharForObjCBool = false; SizeType = UnsignedLong; IntPtrType = SignedLong; DataLayoutString = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"; HasAlignMac68kSupport = true; } bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override { if (!DarwinTargetInfo::handleTargetFeatures(Features, Diags)) return false; // We now know the features we have: we can decide how to align vectors. MaxVectorAlign = hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; return true; } }; // x86-32 Windows target class WindowsX86_32TargetInfo : public WindowsTargetInfo { public: WindowsX86_32TargetInfo(const llvm::Triple &Triple) : WindowsTargetInfo(Triple) { WCharType = UnsignedShort; DoubleAlign = LongLongAlign = 64; bool IsWinCOFF = getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF(); DataLayoutString = IsWinCOFF ? "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" : "e-m:e-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsTargetInfo::getTargetDefines(Opts, Builder); } }; // x86-32 Windows Visual Studio target class MicrosoftX86_32TargetInfo : public WindowsX86_32TargetInfo { public: MicrosoftX86_32TargetInfo(const llvm::Triple &Triple) : WindowsX86_32TargetInfo(Triple) { LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder); WindowsX86_32TargetInfo::getVisualStudioDefines(Opts, Builder); // The value of the following reflects processor type. // 300=386, 400=486, 500=Pentium, 600=Blend (default) // We lost the original triple, so we use the default. Builder.defineMacro("_M_IX86", "600"); } }; static void addCygMingDefines(const LangOptions &Opts, MacroBuilder &Builder) { // Mingw and cygwin define __declspec(a) to __attribute__((a)). Clang // supports __declspec natively under -fms-extensions, but we define a no-op // __declspec macro anyway for pre-processor compatibility. if (Opts.MicrosoftExt) Builder.defineMacro("__declspec", "__declspec"); else Builder.defineMacro("__declspec(a)", "__attribute__((a))"); if (!Opts.MicrosoftExt) { // Provide macros for all the calling convention keywords. Provide both // single and double underscore prefixed variants. These are available on // x64 as well as x86, even though they have no effect. const char *CCs[] = {"cdecl", "stdcall", "fastcall", "thiscall", "pascal"}; for (const char *CC : CCs) { std::string GCCSpelling = "__attribute__((__"; GCCSpelling += CC; GCCSpelling += "__))"; Builder.defineMacro(Twine("_") + CC, GCCSpelling); Builder.defineMacro(Twine("__") + CC, GCCSpelling); } } } static void addMinGWDefines(const LangOptions &Opts, MacroBuilder &Builder) { Builder.defineMacro("__MSVCRT__"); Builder.defineMacro("__MINGW32__"); addCygMingDefines(Opts, Builder); } // x86-32 MinGW target class MinGWX86_32TargetInfo : public WindowsX86_32TargetInfo { public: MinGWX86_32TargetInfo(const llvm::Triple &Triple) : WindowsX86_32TargetInfo(Triple) {} void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder); DefineStd(Builder, "WIN32", Opts); DefineStd(Builder, "WINNT", Opts); Builder.defineMacro("_X86_"); addMinGWDefines(Opts, Builder); } }; // x86-32 Cygwin target class CygwinX86_32TargetInfo : public X86_32TargetInfo { public: CygwinX86_32TargetInfo(const llvm::Triple &Triple) : X86_32TargetInfo(Triple) { WCharType = UnsignedShort; DoubleAlign = LongLongAlign = 64; DataLayoutString = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { X86_32TargetInfo::getTargetDefines(Opts, Builder); Builder.defineMacro("_X86_"); Builder.defineMacro("__CYGWIN__"); Builder.defineMacro("__CYGWIN32__"); addCygMingDefines(Opts, Builder); DefineStd(Builder, "unix", Opts); if (Opts.CPlusPlus) Builder.defineMacro("_GNU_SOURCE"); } }; // x86-32 Haiku target class HaikuX86_32TargetInfo : public X86_32TargetInfo { public: HaikuX86_32TargetInfo(const llvm::Triple &Triple) : X86_32TargetInfo(Triple) { SizeType = UnsignedLong; IntPtrType = SignedLong; PtrDiffType = SignedLong; ProcessIDType = SignedLong; this->UserLabelPrefix = ""; this->TLSSupported = false; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { X86_32TargetInfo::getTargetDefines(Opts, Builder); Builder.defineMacro("__INTEL__"); Builder.defineMacro("__HAIKU__"); } }; // X86-32 MCU target class MCUX86_32TargetInfo : public X86_32TargetInfo { public: MCUX86_32TargetInfo(const llvm::Triple &Triple) : X86_32TargetInfo(Triple) { LongDoubleWidth = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; } CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { // On MCU we support only C calling convention. return CC == CC_C ? CCCR_OK : CCCR_Warning; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { X86_32TargetInfo::getTargetDefines(Opts, Builder); Builder.defineMacro("__iamcu"); Builder.defineMacro("__iamcu__"); } }; // RTEMS Target template class RTEMSTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // RTEMS defines; list based off of gcc output Builder.defineMacro("__rtems__"); Builder.defineMacro("__ELF__"); } public: RTEMSTargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) { this->UserLabelPrefix = ""; switch (Triple.getArch()) { default: case llvm::Triple::x86: // this->MCountName = ".mcount"; break; case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: // this->MCountName = "_mcount"; break; case llvm::Triple::arm: // this->MCountName = "__mcount"; break; } } }; // x86-32 RTEMS target class RTEMSX86_32TargetInfo : public X86_32TargetInfo { public: RTEMSX86_32TargetInfo(const llvm::Triple &Triple) : X86_32TargetInfo(Triple) { SizeType = UnsignedLong; IntPtrType = SignedLong; PtrDiffType = SignedLong; this->UserLabelPrefix = ""; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { X86_32TargetInfo::getTargetDefines(Opts, Builder); Builder.defineMacro("__INTEL__"); Builder.defineMacro("__rtems__"); } }; // x86-64 generic target class X86_64TargetInfo : public X86TargetInfo { public: X86_64TargetInfo(const llvm::Triple &Triple) : X86TargetInfo(Triple) { const bool IsX32 = getTriple().getEnvironment() == llvm::Triple::GNUX32; bool IsWinCOFF = getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF(); LongWidth = LongAlign = PointerWidth = PointerAlign = IsX32 ? 32 : 64; LongDoubleWidth = 128; LongDoubleAlign = 128; LargeArrayMinWidth = 128; LargeArrayAlign = 128; SuitableAlign = 128; SizeType = IsX32 ? UnsignedInt : UnsignedLong; PtrDiffType = IsX32 ? SignedInt : SignedLong; IntPtrType = IsX32 ? SignedInt : SignedLong; IntMaxType = IsX32 ? SignedLongLong : SignedLong; Int64Type = IsX32 ? SignedLongLong : SignedLong; RegParmMax = 6; // Pointers are 32-bit in x32. DataLayoutString = IsX32 ? "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128" : IsWinCOFF ? "e-m:w-i64:64-f80:128-n8:16:32:64-S128" : "e-m:e-i64:64-f80:128-n8:16:32:64-S128"; // Use fpret only for long double. RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble); // Use fp2ret for _Complex long double. ComplexLongDoubleUsesFP2Ret = true; // Make __builtin_ms_va_list available. HasBuiltinMSVaList = true; // x86-64 has atomics up to 16 bytes. MaxAtomicPromoteWidth = 128; MaxAtomicInlineWidth = 128; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::X86_64ABIBuiltinVaList; } int getEHDataRegisterNumber(unsigned RegNo) const override { if (RegNo == 0) return 0; if (RegNo == 1) return 1; return -1; } CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { return (CC == CC_C || CC == CC_X86VectorCall || CC == CC_IntelOclBicc || CC == CC_X86_64Win64) ? CCCR_OK : CCCR_Warning; } CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { return CC_C; } // for x32 we need it here explicitly bool hasInt128Type() const override { return true; } bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize, bool &HasSizeMismatch) const override { // rsp and rbp are the only 64-bit registers the x86 backend can currently // handle. if (RegName.equals("rsp") || RegName.equals("rbp")) { // Check that the register size is 64-bit. HasSizeMismatch = RegSize != 64; return true; } // Check if the register is a 32-bit register the backend can handle. return X86TargetInfo::validateGlobalRegisterVariable(RegName, RegSize, HasSizeMismatch); } }; // x86-64 Windows target class WindowsX86_64TargetInfo : public WindowsTargetInfo { public: WindowsX86_64TargetInfo(const llvm::Triple &Triple) : WindowsTargetInfo(Triple) { WCharType = UnsignedShort; LongWidth = LongAlign = 32; DoubleAlign = LongLongAlign = 64; IntMaxType = SignedLongLong; Int64Type = SignedLongLong; SizeType = UnsignedLongLong; PtrDiffType = SignedLongLong; IntPtrType = SignedLongLong; this->UserLabelPrefix = ""; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsTargetInfo::getTargetDefines(Opts, Builder); Builder.defineMacro("_WIN64"); } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { switch (CC) { case CC_X86StdCall: case CC_X86ThisCall: case CC_X86FastCall: return CCCR_Ignore; case CC_C: case CC_X86VectorCall: case CC_IntelOclBicc: case CC_X86_64SysV: return CCCR_OK; default: return CCCR_Warning; } } }; // x86-64 Windows Visual Studio target class MicrosoftX86_64TargetInfo : public WindowsX86_64TargetInfo { public: MicrosoftX86_64TargetInfo(const llvm::Triple &Triple) : WindowsX86_64TargetInfo(Triple) { LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder); WindowsX86_64TargetInfo::getVisualStudioDefines(Opts, Builder); Builder.defineMacro("_M_X64", "100"); Builder.defineMacro("_M_AMD64", "100"); } }; // x86-64 MinGW target class MinGWX86_64TargetInfo : public WindowsX86_64TargetInfo { public: MinGWX86_64TargetInfo(const llvm::Triple &Triple) : WindowsX86_64TargetInfo(Triple) { // Mingw64 rounds long double size and alignment up to 16 bytes, but sticks // with x86 FP ops. Weird. LongDoubleWidth = LongDoubleAlign = 128; LongDoubleFormat = &llvm::APFloat::x87DoubleExtended; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder); DefineStd(Builder, "WIN64", Opts); Builder.defineMacro("__MINGW64__"); addMinGWDefines(Opts, Builder); // GCC defines this macro when it is using __gxx_personality_seh0. if (!Opts.SjLjExceptions) Builder.defineMacro("__SEH__"); } }; // x86-64 Cygwin target class CygwinX86_64TargetInfo : public X86_64TargetInfo { public: CygwinX86_64TargetInfo(const llvm::Triple &Triple) : X86_64TargetInfo(Triple) { TLSSupported = false; WCharType = UnsignedShort; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { X86_64TargetInfo::getTargetDefines(Opts, Builder); Builder.defineMacro("__x86_64__"); Builder.defineMacro("__CYGWIN__"); Builder.defineMacro("__CYGWIN64__"); addCygMingDefines(Opts, Builder); DefineStd(Builder, "unix", Opts); if (Opts.CPlusPlus) Builder.defineMacro("_GNU_SOURCE"); // GCC defines this macro when it is using __gxx_personality_seh0. if (!Opts.SjLjExceptions) Builder.defineMacro("__SEH__"); } }; class DarwinX86_64TargetInfo : public DarwinTargetInfo { public: DarwinX86_64TargetInfo(const llvm::Triple &Triple) : DarwinTargetInfo(Triple) { Int64Type = SignedLongLong; // The 64-bit iOS simulator uses the builtin bool type for Objective-C. llvm::Triple T = llvm::Triple(Triple); if (T.isiOS()) UseSignedCharForObjCBool = false; DataLayoutString = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"; } bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override { if (!DarwinTargetInfo::handleTargetFeatures(Features, Diags)) return false; // We now know the features we have: we can decide how to align vectors. MaxVectorAlign = hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; return true; } }; class OpenBSDX86_64TargetInfo : public OpenBSDTargetInfo { public: OpenBSDX86_64TargetInfo(const llvm::Triple &Triple) : OpenBSDTargetInfo(Triple) { IntMaxType = SignedLongLong; Int64Type = SignedLongLong; } }; class BitrigX86_64TargetInfo : public BitrigTargetInfo { public: BitrigX86_64TargetInfo(const llvm::Triple &Triple) : BitrigTargetInfo(Triple) { IntMaxType = SignedLongLong; Int64Type = SignedLongLong; } }; class ARMTargetInfo : public TargetInfo { // Possible FPU choices. enum FPUMode { VFP2FPU = (1 << 0), VFP3FPU = (1 << 1), VFP4FPU = (1 << 2), NeonFPU = (1 << 3), FPARMV8 = (1 << 4) }; // Possible HWDiv features. enum HWDivMode { HWDivThumb = (1 << 0), HWDivARM = (1 << 1) }; static bool FPUModeIsVFP(FPUMode Mode) { return Mode & (VFP2FPU | VFP3FPU | VFP4FPU | NeonFPU | FPARMV8); } static const TargetInfo::GCCRegAlias GCCRegAliases[]; static const char * const GCCRegNames[]; std::string ABI, CPU; StringRef CPUProfile; StringRef CPUAttr; enum { FP_Default, FP_VFP, FP_Neon } FPMath; unsigned ArchISA; unsigned ArchKind = llvm::ARM::AK_ARMV4T; unsigned ArchProfile; unsigned ArchVersion; unsigned FPU : 5; unsigned IsAAPCS : 1; unsigned HWDiv : 2; // Initialized via features. unsigned SoftFloat : 1; unsigned SoftFloatABI : 1; unsigned CRC : 1; unsigned Crypto : 1; unsigned DSP : 1; unsigned Unaligned : 1; enum { LDREX_B = (1 << 0), /// byte (8-bit) LDREX_H = (1 << 1), /// half (16-bit) LDREX_W = (1 << 2), /// word (32-bit) LDREX_D = (1 << 3), /// double (64-bit) }; uint32_t LDREX; // ACLE 6.5.1 Hardware floating point enum { HW_FP_HP = (1 << 1), /// half (16-bit) HW_FP_SP = (1 << 2), /// single (32-bit) HW_FP_DP = (1 << 3), /// double (64-bit) }; uint32_t HW_FP; static const Builtin::Info BuiltinInfo[]; void setABIAAPCS() { IsAAPCS = true; DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64; const llvm::Triple &T = getTriple(); // size_t is unsigned long on MachO-derived environments, NetBSD and Bitrig. if (T.isOSBinFormatMachO() || T.getOS() == llvm::Triple::NetBSD || T.getOS() == llvm::Triple::Bitrig) SizeType = UnsignedLong; else SizeType = UnsignedInt; switch (T.getOS()) { case llvm::Triple::NetBSD: WCharType = SignedInt; break; case llvm::Triple::Win32: WCharType = UnsignedShort; break; case llvm::Triple::Linux: default: // AAPCS 7.1.1, ARM-Linux ABI 2.4: type of wchar_t is unsigned int. WCharType = UnsignedInt; break; } UseBitFieldTypeAlignment = true; ZeroLengthBitfieldBoundary = 0; // Thumb1 add sp, #imm requires the immediate value be multiple of 4, // so set preferred for small types to 32. if (T.isOSBinFormatMachO()) { DataLayoutString = BigEndian ? "E-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" : "e-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"; } else if (T.isOSWindows()) { assert(!BigEndian && "Windows on ARM does not support big endian"); DataLayoutString = "e" "-m:w" "-p:32:32" "-i64:64" "-v128:64:128" "-a:0:32" "-n32" "-S64"; } else if (T.isOSNaCl()) { assert(!BigEndian && "NaCl on ARM does not support big endian"); DataLayoutString = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S128"; } else { DataLayoutString = BigEndian ? "E-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" : "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"; } // FIXME: Enumerated types are variable width in straight AAPCS. } void setABIAPCS(bool IsAAPCS16) { const llvm::Triple &T = getTriple(); IsAAPCS = false; if (IsAAPCS16) DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64; else DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32; // size_t is unsigned int on FreeBSD. if (T.getOS() == llvm::Triple::FreeBSD) SizeType = UnsignedInt; else SizeType = UnsignedLong; // Revert to using SignedInt on apcs-gnu to comply with existing behaviour. WCharType = SignedInt; // Do not respect the alignment of bit-field types when laying out // structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc. UseBitFieldTypeAlignment = false; /// gcc forces the alignment to 4 bytes, regardless of the type of the /// zero length bitfield. This corresponds to EMPTY_FIELD_BOUNDARY in /// gcc. ZeroLengthBitfieldBoundary = 32; if (T.isOSBinFormatMachO() && IsAAPCS16) { assert(!BigEndian && "AAPCS16 does not support big-endian"); DataLayoutString = "e-m:o-p:32:32-i64:64-a:0:32-n32-S128"; } else if (T.isOSBinFormatMachO()) DataLayoutString = BigEndian ? "E-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" : "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"; else DataLayoutString = BigEndian ? "E-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" : "e-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"; // FIXME: Override "preferred align" for double and long long. } void setArchInfo() { StringRef ArchName = getTriple().getArchName(); ArchISA = llvm::ARM::parseArchISA(ArchName); CPU = llvm::ARM::getDefaultCPU(ArchName); unsigned AK = llvm::ARM::parseArch(ArchName); if (AK != llvm::ARM::AK_INVALID) ArchKind = AK; setArchInfo(ArchKind); } void setArchInfo(unsigned Kind) { StringRef SubArch; // cache TargetParser info ArchKind = Kind; SubArch = llvm::ARM::getSubArch(ArchKind); ArchProfile = llvm::ARM::parseArchProfile(SubArch); ArchVersion = llvm::ARM::parseArchVersion(SubArch); // cache CPU related strings CPUAttr = getCPUAttr(); CPUProfile = getCPUProfile(); } void setAtomic() { // when triple does not specify a sub arch, // then we are not using inline atomics bool ShouldUseInlineAtomic = (ArchISA == llvm::ARM::IK_ARM && ArchVersion >= 6) || (ArchISA == llvm::ARM::IK_THUMB && ArchVersion >= 7); // Cortex M does not support 8 byte atomics, while general Thumb2 does. if (ArchProfile == llvm::ARM::PK_M) { MaxAtomicPromoteWidth = 32; if (ShouldUseInlineAtomic) MaxAtomicInlineWidth = 32; } else { MaxAtomicPromoteWidth = 64; if (ShouldUseInlineAtomic) MaxAtomicInlineWidth = 64; } } bool isThumb() const { return (ArchISA == llvm::ARM::IK_THUMB); } bool supportsThumb() const { return CPUAttr.count('T') || ArchVersion >= 6; } bool supportsThumb2() const { return CPUAttr.equals("6T2") || ArchVersion >= 7; } StringRef getCPUAttr() const { // For most sub-arches, the build attribute CPU name is enough. // For Cortex variants, it's slightly different. switch(ArchKind) { default: return llvm::ARM::getCPUAttr(ArchKind); case llvm::ARM::AK_ARMV6M: return "6M"; case llvm::ARM::AK_ARMV7S: return "7S"; case llvm::ARM::AK_ARMV7A: return "7A"; case llvm::ARM::AK_ARMV7R: return "7R"; case llvm::ARM::AK_ARMV7M: return "7M"; case llvm::ARM::AK_ARMV7EM: return "7EM"; case llvm::ARM::AK_ARMV8A: return "8A"; case llvm::ARM::AK_ARMV8_1A: return "8_1A"; } } StringRef getCPUProfile() const { switch(ArchProfile) { case llvm::ARM::PK_A: return "A"; case llvm::ARM::PK_R: return "R"; case llvm::ARM::PK_M: return "M"; default: return ""; } } public: ARMTargetInfo(const llvm::Triple &Triple, bool IsBigEndian) : TargetInfo(Triple), FPMath(FP_Default), IsAAPCS(true), LDREX(0), HW_FP(0) { BigEndian = IsBigEndian; switch (getTriple().getOS()) { case llvm::Triple::NetBSD: PtrDiffType = SignedLong; break; default: PtrDiffType = SignedInt; break; } // Cache arch related info. setArchInfo(); // {} in inline assembly are neon specifiers, not assembly variant // specifiers. NoAsmVariants = true; // FIXME: This duplicates code from the driver that sets the -target-abi // option - this code is used if -target-abi isn't passed and should // be unified in some way. if (Triple.isOSBinFormatMachO()) { // The backend is hardwired to assume AAPCS for M-class processors, ensure // the frontend matches that. if (Triple.getEnvironment() == llvm::Triple::EABI || Triple.getOS() == llvm::Triple::UnknownOS || StringRef(CPU).startswith("cortex-m")) { setABI("aapcs"); } else if (Triple.isWatchOS()) { setABI("aapcs16"); } else { setABI("apcs-gnu"); } } else if (Triple.isOSWindows()) { // FIXME: this is invalid for WindowsCE setABI("aapcs"); } else { // Select the default based on the platform. switch (Triple.getEnvironment()) { case llvm::Triple::Android: case llvm::Triple::GNUEABI: case llvm::Triple::GNUEABIHF: setABI("aapcs-linux"); break; case llvm::Triple::EABIHF: case llvm::Triple::EABI: setABI("aapcs"); break; case llvm::Triple::GNU: setABI("apcs-gnu"); break; default: if (Triple.getOS() == llvm::Triple::NetBSD) setABI("apcs-gnu"); else setABI("aapcs"); break; } } // ARM targets default to using the ARM C++ ABI. TheCXXABI.set(TargetCXXABI::GenericARM); // ARM has atomics up to 8 bytes setAtomic(); // Do force alignment of members that follow zero length bitfields. If // the alignment of the zero-length bitfield is greater than the member // that follows it, `bar', `bar' will be aligned as the type of the // zero length bitfield. UseZeroLengthBitfieldAlignment = true; } StringRef getABI() const override { return ABI; } bool setABI(const std::string &Name) override { ABI = Name; // The defaults (above) are for AAPCS, check if we need to change them. // // FIXME: We need support for -meabi... we could just mangle it into the // name. if (Name == "apcs-gnu" || Name == "aapcs16") { setABIAPCS(Name == "aapcs16"); return true; } if (Name == "aapcs" || Name == "aapcs-vfp" || Name == "aapcs-linux") { setABIAAPCS(); return true; } return false; } // FIXME: This should be based on Arch attributes, not CPU names. bool initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const override { std::vector TargetFeatures; unsigned Arch = llvm::ARM::parseArch(getTriple().getArchName()); // get default FPU features unsigned FPUKind = llvm::ARM::getDefaultFPU(CPU, Arch); llvm::ARM::getFPUFeatures(FPUKind, TargetFeatures); // get default Extension features unsigned Extensions = llvm::ARM::getDefaultExtensions(CPU, Arch); llvm::ARM::getExtensionFeatures(Extensions, TargetFeatures); for (const char *Feature : TargetFeatures) if (Feature[0] == '+') Features[Feature+1] = true; return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override { FPU = 0; CRC = 0; Crypto = 0; DSP = 0; Unaligned = 1; SoftFloat = SoftFloatABI = false; HWDiv = 0; // This does not diagnose illegal cases like having both // "+vfpv2" and "+vfpv3" or having "+neon" and "+fp-only-sp". uint32_t HW_FP_remove = 0; for (const auto &Feature : Features) { if (Feature == "+soft-float") { SoftFloat = true; } else if (Feature == "+soft-float-abi") { SoftFloatABI = true; } else if (Feature == "+vfp2") { FPU |= VFP2FPU; HW_FP |= HW_FP_SP | HW_FP_DP; } else if (Feature == "+vfp3") { FPU |= VFP3FPU; HW_FP |= HW_FP_SP | HW_FP_DP; } else if (Feature == "+vfp4") { FPU |= VFP4FPU; HW_FP |= HW_FP_SP | HW_FP_DP | HW_FP_HP; } else if (Feature == "+fp-armv8") { FPU |= FPARMV8; HW_FP |= HW_FP_SP | HW_FP_DP | HW_FP_HP; } else if (Feature == "+neon") { FPU |= NeonFPU; HW_FP |= HW_FP_SP | HW_FP_DP; } else if (Feature == "+hwdiv") { HWDiv |= HWDivThumb; } else if (Feature == "+hwdiv-arm") { HWDiv |= HWDivARM; } else if (Feature == "+crc") { CRC = 1; } else if (Feature == "+crypto") { Crypto = 1; } else if (Feature == "+dsp") { DSP = 1; } else if (Feature == "+fp-only-sp") { HW_FP_remove |= HW_FP_DP; } else if (Feature == "+strict-align") { Unaligned = 0; } else if (Feature == "+fp16") { HW_FP |= HW_FP_HP; } } HW_FP &= ~HW_FP_remove; switch (ArchVersion) { case 6: if (ArchProfile == llvm::ARM::PK_M) LDREX = 0; else if (ArchKind == llvm::ARM::AK_ARMV6K) LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B ; else LDREX = LDREX_W; break; case 7: if (ArchProfile == llvm::ARM::PK_M) LDREX = LDREX_W | LDREX_H | LDREX_B ; else LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B ; break; case 8: LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B ; } if (!(FPU & NeonFPU) && FPMath == FP_Neon) { Diags.Report(diag::err_target_unsupported_fpmath) << "neon"; return false; } if (FPMath == FP_Neon) Features.push_back("+neonfp"); else if (FPMath == FP_VFP) Features.push_back("-neonfp"); // Remove front-end specific options which the backend handles differently. auto Feature = std::find(Features.begin(), Features.end(), "+soft-float-abi"); if (Feature != Features.end()) Features.erase(Feature); return true; } bool hasFeature(StringRef Feature) const override { return llvm::StringSwitch(Feature) .Case("arm", true) .Case("aarch32", true) .Case("softfloat", SoftFloat) .Case("thumb", isThumb()) .Case("neon", (FPU & NeonFPU) && !SoftFloat) .Case("hwdiv", HWDiv & HWDivThumb) .Case("hwdiv-arm", HWDiv & HWDivARM) .Default(false); } bool setCPU(const std::string &Name) override { if (Name != "generic") setArchInfo(llvm::ARM::parseCPUArch(Name)); if (ArchKind == llvm::ARM::AK_INVALID) return false; setAtomic(); CPU = Name; return true; } bool setFPMath(StringRef Name) override; void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { // Target identification. Builder.defineMacro("__arm"); Builder.defineMacro("__arm__"); // Target properties. Builder.defineMacro("__REGISTER_PREFIX__", ""); // Unfortunately, __ARM_ARCH_7K__ is now more of an ABI descriptor. The CPU // happens to be Cortex-A7 though, so it should still get __ARM_ARCH_7A__. if (getTriple().isWatchOS()) Builder.defineMacro("__ARM_ARCH_7K__", "2"); if (!CPUAttr.empty()) Builder.defineMacro("__ARM_ARCH_" + CPUAttr + "__"); // ACLE 6.4.1 ARM/Thumb instruction set architecture // __ARM_ARCH is defined as an integer value indicating the current ARM ISA Builder.defineMacro("__ARM_ARCH", Twine(ArchVersion)); if (ArchVersion >= 8) { // ACLE 6.5.7 Crypto Extension if (Crypto) Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1"); // ACLE 6.5.8 CRC32 Extension if (CRC) Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); // ACLE 6.5.10 Numeric Maximum and Minimum Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1"); // ACLE 6.5.9 Directed Rounding Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1"); } // __ARM_ARCH_ISA_ARM is defined to 1 if the core supports the ARM ISA. It // is not defined for the M-profile. // NOTE that the deffault profile is assumed to be 'A' if (CPUProfile.empty() || CPUProfile != "M") Builder.defineMacro("__ARM_ARCH_ISA_ARM", "1"); // __ARM_ARCH_ISA_THUMB is defined to 1 if the core supporst the original // Thumb ISA (including v6-M). It is set to 2 if the core supports the // Thumb-2 ISA as found in the v6T2 architecture and all v7 architecture. if (supportsThumb2()) Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "2"); else if (supportsThumb()) Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "1"); // __ARM_32BIT_STATE is defined to 1 if code is being generated for a 32-bit // instruction set such as ARM or Thumb. Builder.defineMacro("__ARM_32BIT_STATE", "1"); // ACLE 6.4.2 Architectural Profile (A, R, M or pre-Cortex) // __ARM_ARCH_PROFILE is defined as 'A', 'R', 'M' or 'S', or unset. if (!CPUProfile.empty()) Builder.defineMacro("__ARM_ARCH_PROFILE", "'" + CPUProfile + "'"); // ACLE 6.4.3 Unaligned access supported in hardware if (Unaligned) Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); // ACLE 6.4.4 LDREX/STREX if (LDREX) Builder.defineMacro("__ARM_FEATURE_LDREX", "0x" + llvm::utohexstr(LDREX)); // ACLE 6.4.5 CLZ if (ArchVersion == 5 || (ArchVersion == 6 && CPUProfile != "M") || ArchVersion > 6) Builder.defineMacro("__ARM_FEATURE_CLZ", "1"); // ACLE 6.5.1 Hardware Floating Point if (HW_FP) Builder.defineMacro("__ARM_FP", "0x" + llvm::utohexstr(HW_FP)); // ACLE predefines. Builder.defineMacro("__ARM_ACLE", "200"); // FP16 support (we currently only support IEEE format). Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1"); Builder.defineMacro("__ARM_FP16_ARGS", "1"); // ACLE 6.5.3 Fused multiply-accumulate (FMA) if (ArchVersion >= 7 && (CPUProfile != "M" || CPUAttr == "7EM")) Builder.defineMacro("__ARM_FEATURE_FMA", "1"); // Subtarget options. // FIXME: It's more complicated than this and we don't really support // interworking. // Windows on ARM does not "support" interworking if (5 <= ArchVersion && ArchVersion <= 8 && !getTriple().isOSWindows()) Builder.defineMacro("__THUMB_INTERWORK__"); if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") { // Embedded targets on Darwin follow AAPCS, but not EABI. // Windows on ARM follows AAPCS VFP, but does not conform to EABI. if (!getTriple().isOSDarwin() && !getTriple().isOSWindows()) Builder.defineMacro("__ARM_EABI__"); Builder.defineMacro("__ARM_PCS", "1"); if ((!SoftFloat && !SoftFloatABI) || ABI == "aapcs-vfp") Builder.defineMacro("__ARM_PCS_VFP", "1"); } if (SoftFloat) Builder.defineMacro("__SOFTFP__"); if (CPU == "xscale") Builder.defineMacro("__XSCALE__"); if (isThumb()) { Builder.defineMacro("__THUMBEL__"); Builder.defineMacro("__thumb__"); if (supportsThumb2()) Builder.defineMacro("__thumb2__"); } // ACLE 6.4.9 32-bit SIMD instructions if (ArchVersion >= 6 && (CPUProfile != "M" || CPUAttr == "7EM")) Builder.defineMacro("__ARM_FEATURE_SIMD32", "1"); // ACLE 6.4.10 Hardware Integer Divide if (((HWDiv & HWDivThumb) && isThumb()) || ((HWDiv & HWDivARM) && !isThumb())) { Builder.defineMacro("__ARM_FEATURE_IDIV", "1"); Builder.defineMacro("__ARM_ARCH_EXT_IDIV__", "1"); } // Note, this is always on in gcc, even though it doesn't make sense. Builder.defineMacro("__APCS_32__"); if (FPUModeIsVFP((FPUMode) FPU)) { Builder.defineMacro("__VFP_FP__"); if (FPU & VFP2FPU) Builder.defineMacro("__ARM_VFPV2__"); if (FPU & VFP3FPU) Builder.defineMacro("__ARM_VFPV3__"); if (FPU & VFP4FPU) Builder.defineMacro("__ARM_VFPV4__"); } // This only gets set when Neon instructions are actually available, unlike // the VFP define, hence the soft float and arch check. This is subtly // different from gcc, we follow the intent which was that it should be set // when Neon instructions are actually available. if ((FPU & NeonFPU) && !SoftFloat && ArchVersion >= 7) { Builder.defineMacro("__ARM_NEON", "1"); Builder.defineMacro("__ARM_NEON__"); // current AArch32 NEON implementations do not support double-precision // floating-point even when it is present in VFP. Builder.defineMacro("__ARM_NEON_FP", "0x" + llvm::utohexstr(HW_FP & ~HW_FP_DP)); } Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", Opts.ShortWChar ? "2" : "4"); Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", Opts.ShortEnums ? "1" : "4"); if (ArchVersion >= 6 && CPUAttr != "6M") { Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); } // ACLE 6.4.7 DSP instructions if (DSP) { Builder.defineMacro("__ARM_FEATURE_DSP", "1"); } // ACLE 6.4.8 Saturation instructions bool SAT = false; if ((ArchVersion == 6 && CPUProfile != "M") || ArchVersion > 6 ) { Builder.defineMacro("__ARM_FEATURE_SAT", "1"); SAT = true; } // ACLE 6.4.6 Q (saturation) flag if (DSP || SAT) Builder.defineMacro("__ARM_FEATURE_QBIT", "1"); if (Opts.UnsafeFPMath) Builder.defineMacro("__ARM_FP_FAST", "1"); if (ArchKind == llvm::ARM::AK_ARMV8_1A) Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::ARM::LastTSBuiltin-Builtin::FirstTSBuiltin); } bool isCLZForZeroUndef() const override { return false; } BuiltinVaListKind getBuiltinVaListKind() const override { return IsAAPCS ? AAPCSABIBuiltinVaList : (getTriple().isWatchOS() ? TargetInfo::CharPtrBuiltinVaList : TargetInfo::VoidPtrBuiltinVaList); } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { switch (*Name) { default: break; case 'l': // r0-r7 case 'h': // r8-r15 - case 'w': // VFP Floating point register single precision - case 'P': // VFP Floating point register double precision + case 't': // VFP Floating point register single precision + case 'w': // VFP Floating point register double precision Info.setAllowsRegister(); return true; case 'I': case 'J': case 'K': case 'L': case 'M': // FIXME return true; case 'Q': // A memory address that is a single base register. Info.setAllowsMemory(); return true; case 'U': // a memory reference... switch (Name[1]) { case 'q': // ...ARMV4 ldrsb case 'v': // ...VFP load/store (reg+constant offset) case 'y': // ...iWMMXt load/store case 't': // address valid for load/store opaque types wider // than 128-bits case 'n': // valid address for Neon doubleword vector load/store case 'm': // valid address for Neon element and structure load/store case 's': // valid address for non-offset loads/stores of quad-word // values in four ARM registers Info.setAllowsMemory(); Name++; return true; } } return false; } std::string convertConstraint(const char *&Constraint) const override { std::string R; switch (*Constraint) { case 'U': // Two-character constraint; add "^" hint for later parsing. R = std::string("^") + std::string(Constraint, 2); Constraint++; break; case 'p': // 'p' should be translated to 'r' by default. R = std::string("r"); break; default: return std::string(1, *Constraint); } return R; } bool validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size, std::string &SuggestedModifier) const override { bool isOutput = (Constraint[0] == '='); bool isInOut = (Constraint[0] == '+'); // Strip off constraint modifiers. while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') Constraint = Constraint.substr(1); switch (Constraint[0]) { default: break; case 'r': { switch (Modifier) { default: return (isInOut || isOutput || Size <= 64); case 'q': // A register of size 32 cannot fit a vector type. return false; } } } return true; } const char *getClobbers() const override { // FIXME: Is this really right? return ""; } CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { return (CC == CC_AAPCS || CC == CC_AAPCS_VFP) ? CCCR_OK : CCCR_Warning; } int getEHDataRegisterNumber(unsigned RegNo) const override { if (RegNo == 0) return 0; if (RegNo == 1) return 1; return -1; } bool hasSjLjLowering() const override { return true; } }; bool ARMTargetInfo::setFPMath(StringRef Name) { if (Name == "neon") { FPMath = FP_Neon; return true; } else if (Name == "vfp" || Name == "vfp2" || Name == "vfp3" || Name == "vfp4") { FPMath = FP_VFP; return true; } return false; } const char * const ARMTargetInfo::GCCRegNames[] = { // Integer registers "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", // Float registers "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", // Double registers "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", // Quad registers "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" }; ArrayRef ARMTargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } const TargetInfo::GCCRegAlias ARMTargetInfo::GCCRegAliases[] = { { { "a1" }, "r0" }, { { "a2" }, "r1" }, { { "a3" }, "r2" }, { { "a4" }, "r3" }, { { "v1" }, "r4" }, { { "v2" }, "r5" }, { { "v3" }, "r6" }, { { "v4" }, "r7" }, { { "v5" }, "r8" }, { { "v6", "rfp" }, "r9" }, { { "sl" }, "r10" }, { { "fp" }, "r11" }, { { "ip" }, "r12" }, { { "r13" }, "sp" }, { { "r14" }, "lr" }, { { "r15" }, "pc" }, // The S, D and Q registers overlap, but aren't really aliases; we // don't want to substitute one of these for a different-sized one. }; ArrayRef ARMTargetInfo::getGCCRegAliases() const { return llvm::makeArrayRef(GCCRegAliases); } const Builtin::Info ARMTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsNEON.def" #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define LANGBUILTIN(ID, TYPE, ATTRS, LANG) \ { #ID, TYPE, ATTRS, nullptr, LANG, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsARM.def" }; class ARMleTargetInfo : public ARMTargetInfo { public: ARMleTargetInfo(const llvm::Triple &Triple) : ARMTargetInfo(Triple, false) { } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__ARMEL__"); ARMTargetInfo::getTargetDefines(Opts, Builder); } }; class ARMbeTargetInfo : public ARMTargetInfo { public: ARMbeTargetInfo(const llvm::Triple &Triple) : ARMTargetInfo(Triple, true) { } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__ARMEB__"); Builder.defineMacro("__ARM_BIG_ENDIAN"); ARMTargetInfo::getTargetDefines(Opts, Builder); } }; class WindowsARMTargetInfo : public WindowsTargetInfo { const llvm::Triple Triple; public: WindowsARMTargetInfo(const llvm::Triple &Triple) : WindowsTargetInfo(Triple), Triple(Triple) { TLSSupported = false; WCharType = UnsignedShort; SizeType = UnsignedInt; UserLabelPrefix = ""; } void getVisualStudioDefines(const LangOptions &Opts, MacroBuilder &Builder) const { WindowsTargetInfo::getVisualStudioDefines(Opts, Builder); // FIXME: this is invalid for WindowsCE Builder.defineMacro("_M_ARM_NT", "1"); Builder.defineMacro("_M_ARMT", "_M_ARM"); Builder.defineMacro("_M_THUMB", "_M_ARM"); assert((Triple.getArch() == llvm::Triple::arm || Triple.getArch() == llvm::Triple::thumb) && "invalid architecture for Windows ARM target info"); unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6; Builder.defineMacro("_M_ARM", Triple.getArchName().substr(Offset)); // TODO map the complete set of values // 31: VFPv3 40: VFPv4 Builder.defineMacro("_M_ARM_FP", "31"); } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { switch (CC) { case CC_X86StdCall: case CC_X86ThisCall: case CC_X86FastCall: case CC_X86VectorCall: return CCCR_Ignore; case CC_C: return CCCR_OK; default: return CCCR_Warning; } } }; // Windows ARM + Itanium C++ ABI Target class ItaniumWindowsARMleTargetInfo : public WindowsARMTargetInfo { public: ItaniumWindowsARMleTargetInfo(const llvm::Triple &Triple) : WindowsARMTargetInfo(Triple) { TheCXXABI.set(TargetCXXABI::GenericARM); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsARMTargetInfo::getTargetDefines(Opts, Builder); if (Opts.MSVCCompat) WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder); } }; // Windows ARM, MS (C++) ABI class MicrosoftARMleTargetInfo : public WindowsARMTargetInfo { public: MicrosoftARMleTargetInfo(const llvm::Triple &Triple) : WindowsARMTargetInfo(Triple) { TheCXXABI.set(TargetCXXABI::Microsoft); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsARMTargetInfo::getTargetDefines(Opts, Builder); WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder); } }; // ARM MinGW target class MinGWARMTargetInfo : public WindowsARMTargetInfo { public: MinGWARMTargetInfo(const llvm::Triple &Triple) : WindowsARMTargetInfo(Triple) { TheCXXABI.set(TargetCXXABI::GenericARM); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsARMTargetInfo::getTargetDefines(Opts, Builder); DefineStd(Builder, "WIN32", Opts); DefineStd(Builder, "WINNT", Opts); Builder.defineMacro("_ARM_"); addMinGWDefines(Opts, Builder); } }; // ARM Cygwin target class CygwinARMTargetInfo : public ARMleTargetInfo { public: CygwinARMTargetInfo(const llvm::Triple &Triple) : ARMleTargetInfo(Triple) { TLSSupported = false; WCharType = UnsignedShort; DoubleAlign = LongLongAlign = 64; DataLayoutString = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { ARMleTargetInfo::getTargetDefines(Opts, Builder); Builder.defineMacro("_ARM_"); Builder.defineMacro("__CYGWIN__"); Builder.defineMacro("__CYGWIN32__"); DefineStd(Builder, "unix", Opts); if (Opts.CPlusPlus) Builder.defineMacro("_GNU_SOURCE"); } }; class DarwinARMTargetInfo : public DarwinTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion); } public: DarwinARMTargetInfo(const llvm::Triple &Triple) : DarwinTargetInfo(Triple) { HasAlignMac68kSupport = true; // iOS always has 64-bit atomic instructions. // FIXME: This should be based off of the target features in // ARMleTargetInfo. MaxAtomicInlineWidth = 64; if (Triple.isWatchOS()) { // Darwin on iOS uses a variant of the ARM C++ ABI. TheCXXABI.set(TargetCXXABI::WatchOS); // The 32-bit ABI is silent on what ptrdiff_t should be, but given that // size_t is long, it's a bit weird for it to be int. PtrDiffType = SignedLong; // BOOL should be a real boolean on the new ABI UseSignedCharForObjCBool = false; } else TheCXXABI.set(TargetCXXABI::iOS); } }; class AArch64TargetInfo : public TargetInfo { virtual void setDataLayoutString() = 0; static const TargetInfo::GCCRegAlias GCCRegAliases[]; static const char *const GCCRegNames[]; enum FPUModeEnum { FPUMode, NeonMode }; unsigned FPU; unsigned CRC; unsigned Crypto; unsigned Unaligned; unsigned V8_1A; static const Builtin::Info BuiltinInfo[]; std::string ABI; public: AArch64TargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple), ABI("aapcs") { if (getTriple().getOS() == llvm::Triple::NetBSD) { WCharType = SignedInt; // NetBSD apparently prefers consistency across ARM targets to consistency // across 64-bit targets. Int64Type = SignedLongLong; IntMaxType = SignedLongLong; } else { WCharType = UnsignedInt; Int64Type = SignedLong; IntMaxType = SignedLong; } LongWidth = LongAlign = PointerWidth = PointerAlign = 64; MaxVectorAlign = 128; MaxAtomicInlineWidth = 128; MaxAtomicPromoteWidth = 128; LongDoubleWidth = LongDoubleAlign = SuitableAlign = 128; LongDoubleFormat = &llvm::APFloat::IEEEquad; // {} in inline assembly are neon specifiers, not assembly variant // specifiers. NoAsmVariants = true; // AAPCS gives rules for bitfields. 7.1.7 says: "The container type // contributes to the alignment of the containing aggregate in the same way // a plain (non bit-field) member of that type would, without exception for // zero-sized or anonymous bit-fields." assert(UseBitFieldTypeAlignment && "bitfields affect type alignment"); UseZeroLengthBitfieldAlignment = true; // AArch64 targets default to using the ARM C++ ABI. TheCXXABI.set(TargetCXXABI::GenericAArch64); } StringRef getABI() const override { return ABI; } bool setABI(const std::string &Name) override { if (Name != "aapcs" && Name != "darwinpcs") return false; ABI = Name; return true; } bool setCPU(const std::string &Name) override { bool CPUKnown = llvm::StringSwitch(Name) .Case("generic", true) .Cases("cortex-a53", "cortex-a57", "cortex-a72", "cortex-a35", "exynos-m1", true) .Case("cyclone", true) .Default(false); return CPUKnown; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { // Target identification. Builder.defineMacro("__aarch64__"); // Target properties. Builder.defineMacro("_LP64"); Builder.defineMacro("__LP64__"); // ACLE predefines. Many can only have one possible value on v8 AArch64. Builder.defineMacro("__ARM_ACLE", "200"); Builder.defineMacro("__ARM_ARCH", "8"); Builder.defineMacro("__ARM_ARCH_PROFILE", "'A'"); Builder.defineMacro("__ARM_64BIT_STATE", "1"); Builder.defineMacro("__ARM_PCS_AAPCS64", "1"); Builder.defineMacro("__ARM_ARCH_ISA_A64", "1"); Builder.defineMacro("__ARM_FEATURE_CLZ", "1"); Builder.defineMacro("__ARM_FEATURE_FMA", "1"); Builder.defineMacro("__ARM_FEATURE_LDREX", "0xF"); Builder.defineMacro("__ARM_FEATURE_IDIV", "1"); // As specified in ACLE Builder.defineMacro("__ARM_FEATURE_DIV"); // For backwards compatibility Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1"); Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1"); Builder.defineMacro("__ARM_ALIGN_MAX_STACK_PWR", "4"); // 0xe implies support for half, single and double precision operations. Builder.defineMacro("__ARM_FP", "0xE"); // PCS specifies this for SysV variants, which is all we support. Other ABIs // may choose __ARM_FP16_FORMAT_ALTERNATIVE. Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1"); Builder.defineMacro("__ARM_FP16_ARGS", "1"); if (Opts.UnsafeFPMath) Builder.defineMacro("__ARM_FP_FAST", "1"); Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", Opts.ShortWChar ? "2" : "4"); Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", Opts.ShortEnums ? "1" : "4"); if (FPU == NeonMode) { Builder.defineMacro("__ARM_NEON", "1"); // 64-bit NEON supports half, single and double precision operations. Builder.defineMacro("__ARM_NEON_FP", "0xE"); } if (CRC) Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); if (Crypto) Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1"); if (Unaligned) Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); if (V8_1A) Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); // All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work. Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::AArch64::LastTSBuiltin - Builtin::FirstTSBuiltin); } bool hasFeature(StringRef Feature) const override { return Feature == "aarch64" || Feature == "arm64" || Feature == "arm" || (Feature == "neon" && FPU == NeonMode); } bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override { FPU = FPUMode; CRC = 0; Crypto = 0; Unaligned = 1; V8_1A = 0; for (const auto &Feature : Features) { if (Feature == "+neon") FPU = NeonMode; if (Feature == "+crc") CRC = 1; if (Feature == "+crypto") Crypto = 1; if (Feature == "+strict-align") Unaligned = 0; if (Feature == "+v8.1a") V8_1A = 1; } setDataLayoutString(); return true; } bool isCLZForZeroUndef() const override { return false; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::AArch64ABIBuiltinVaList; } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { switch (*Name) { default: return false; case 'w': // Floating point and SIMD registers (V0-V31) Info.setAllowsRegister(); return true; case 'I': // Constant that can be used with an ADD instruction case 'J': // Constant that can be used with a SUB instruction case 'K': // Constant that can be used with a 32-bit logical instruction case 'L': // Constant that can be used with a 64-bit logical instruction case 'M': // Constant that can be used as a 32-bit MOV immediate case 'N': // Constant that can be used as a 64-bit MOV immediate case 'Y': // Floating point constant zero case 'Z': // Integer constant zero return true; case 'Q': // A memory reference with base register and no offset Info.setAllowsMemory(); return true; case 'S': // A symbolic address Info.setAllowsRegister(); return true; case 'U': // Ump: A memory address suitable for ldp/stp in SI, DI, SF and DF modes. // Utf: A memory address suitable for ldp/stp in TF mode. // Usa: An absolute symbolic address. // Ush: The high part (bits 32:12) of a pc-relative symbolic address. llvm_unreachable("FIXME: Unimplemented support for U* constraints."); case 'z': // Zero register, wzr or xzr Info.setAllowsRegister(); return true; case 'x': // Floating point and SIMD registers (V0-V15) Info.setAllowsRegister(); return true; } return false; } bool validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size, std::string &SuggestedModifier) const override { // Strip off constraint modifiers. while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') Constraint = Constraint.substr(1); switch (Constraint[0]) { default: return true; case 'z': case 'r': { switch (Modifier) { case 'x': case 'w': // For now assume that the person knows what they're // doing with the modifier. return true; default: // By default an 'r' constraint will be in the 'x' // registers. if (Size == 64) return true; SuggestedModifier = "w"; return false; } } } } const char *getClobbers() const override { return ""; } int getEHDataRegisterNumber(unsigned RegNo) const override { if (RegNo == 0) return 0; if (RegNo == 1) return 1; return -1; } }; const char *const AArch64TargetInfo::GCCRegNames[] = { // 32-bit Integer registers "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15", "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23", "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wsp", // 64-bit Integer registers "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "fp", "lr", "sp", // 32-bit floating point regsisters "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", // 64-bit floating point regsisters "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", // Vector registers "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" }; ArrayRef AArch64TargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = { { { "w31" }, "wsp" }, { { "x29" }, "fp" }, { { "x30" }, "lr" }, { { "x31" }, "sp" }, // The S/D/Q and W/X registers overlap, but aren't really aliases; we // don't want to substitute one of these for a different-sized one. }; ArrayRef AArch64TargetInfo::getGCCRegAliases() const { return llvm::makeArrayRef(GCCRegAliases); } const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsNEON.def" #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsAArch64.def" }; class AArch64leTargetInfo : public AArch64TargetInfo { void setDataLayoutString() override { if (getTriple().isOSBinFormatMachO()) DataLayoutString = "e-m:o-i64:64-i128:128-n32:64-S128"; else DataLayoutString = "e-m:e-i64:64-i128:128-n32:64-S128"; } public: AArch64leTargetInfo(const llvm::Triple &Triple) : AArch64TargetInfo(Triple) { BigEndian = false; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__AARCH64EL__"); AArch64TargetInfo::getTargetDefines(Opts, Builder); } }; class AArch64beTargetInfo : public AArch64TargetInfo { void setDataLayoutString() override { assert(!getTriple().isOSBinFormatMachO()); DataLayoutString = "E-m:e-i64:64-i128:128-n32:64-S128"; } public: AArch64beTargetInfo(const llvm::Triple &Triple) : AArch64TargetInfo(Triple) { } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__AARCH64EB__"); Builder.defineMacro("__AARCH_BIG_ENDIAN"); Builder.defineMacro("__ARM_BIG_ENDIAN"); AArch64TargetInfo::getTargetDefines(Opts, Builder); } }; class DarwinAArch64TargetInfo : public DarwinTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { Builder.defineMacro("__AARCH64_SIMD__"); Builder.defineMacro("__ARM64_ARCH_8__"); Builder.defineMacro("__ARM_NEON__"); Builder.defineMacro("__LITTLE_ENDIAN__"); Builder.defineMacro("__REGISTER_PREFIX__", ""); Builder.defineMacro("__arm64", "1"); Builder.defineMacro("__arm64__", "1"); getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion); } public: DarwinAArch64TargetInfo(const llvm::Triple &Triple) : DarwinTargetInfo(Triple) { Int64Type = SignedLongLong; WCharType = SignedInt; UseSignedCharForObjCBool = false; LongDoubleWidth = LongDoubleAlign = SuitableAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; TheCXXABI.set(TargetCXXABI::iOS64); } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } }; // Hexagon abstract base class class HexagonTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; static const char * const GCCRegNames[]; static const TargetInfo::GCCRegAlias GCCRegAliases[]; std::string CPU; bool HasHVX, HasHVXDouble; public: HexagonTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { BigEndian = false; DataLayoutString = "e-m:e-p:32:32:32-" "i64:64:64-i32:32:32-i16:16:16-i1:8:8-" "f64:64:64-f32:32:32-v64:64:64-v32:32:32-a:0-n16:32"; SizeType = UnsignedInt; PtrDiffType = SignedInt; IntPtrType = SignedInt; // {} in inline assembly are packet specifiers, not assembly variant // specifiers. NoAsmVariants = true; LargeArrayMinWidth = 64; LargeArrayAlign = 64; UseBitFieldTypeAlignment = true; ZeroLengthBitfieldBoundary = 32; HasHVX = HasHVXDouble = false; } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::Hexagon::LastTSBuiltin-Builtin::FirstTSBuiltin); } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { return true; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; bool isCLZForZeroUndef() const override { return false; } bool hasFeature(StringRef Feature) const override { return llvm::StringSwitch(Feature) .Case("hexagon", true) .Case("hvx", HasHVX) .Case("hvx-double", HasHVXDouble) .Default(false); } bool initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const override; bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override; BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override; const char *getClobbers() const override { return ""; } static const char *getHexagonCPUSuffix(StringRef Name) { return llvm::StringSwitch(Name) .Case("hexagonv4", "4") .Case("hexagonv5", "5") .Case("hexagonv55", "55") .Case("hexagonv60", "60") .Default(nullptr); } bool setCPU(const std::string &Name) override { if (!getHexagonCPUSuffix(Name)) return false; CPU = Name; return true; } int getEHDataRegisterNumber(unsigned RegNo) const override { return RegNo < 2 ? RegNo : -1; } }; void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { Builder.defineMacro("__qdsp6__", "1"); Builder.defineMacro("__hexagon__", "1"); if (CPU == "hexagonv4") { Builder.defineMacro("__HEXAGON_V4__"); Builder.defineMacro("__HEXAGON_ARCH__", "4"); if (Opts.HexagonQdsp6Compat) { Builder.defineMacro("__QDSP6_V4__"); Builder.defineMacro("__QDSP6_ARCH__", "4"); } } else if (CPU == "hexagonv5") { Builder.defineMacro("__HEXAGON_V5__"); Builder.defineMacro("__HEXAGON_ARCH__", "5"); if(Opts.HexagonQdsp6Compat) { Builder.defineMacro("__QDSP6_V5__"); Builder.defineMacro("__QDSP6_ARCH__", "5"); } } else if (CPU == "hexagonv60") { Builder.defineMacro("__HEXAGON_V60__"); Builder.defineMacro("__HEXAGON_ARCH__", "60"); Builder.defineMacro("__QDSP6_V60__"); Builder.defineMacro("__QDSP6_ARCH__", "60"); } } bool HexagonTargetInfo::handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) { for (auto &F : Features) { if (F == "+hvx") HasHVX = true; else if (F == "-hvx") HasHVX = HasHVXDouble = false; else if (F == "+hvx-double") HasHVX = HasHVXDouble = true; else if (F == "-hvx-double") HasHVXDouble = false; } return true; } bool HexagonTargetInfo::initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const { // Default for v60: -hvx, -hvx-double. Features["hvx"] = false; Features["hvx-double"] = false; return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } const char *const HexagonTargetInfo::GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", "p0", "p1", "p2", "p3", "sa0", "lc0", "sa1", "lc1", "m0", "m1", "usr", "ugp" }; ArrayRef HexagonTargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } const TargetInfo::GCCRegAlias HexagonTargetInfo::GCCRegAliases[] = { { { "sp" }, "r29" }, { { "fp" }, "r30" }, { { "lr" }, "r31" }, }; ArrayRef HexagonTargetInfo::getGCCRegAliases() const { return llvm::makeArrayRef(GCCRegAliases); } const Builtin::Info HexagonTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsHexagon.def" }; // Shared base class for SPARC v8 (32-bit) and SPARC v9 (64-bit). class SparcTargetInfo : public TargetInfo { static const TargetInfo::GCCRegAlias GCCRegAliases[]; static const char * const GCCRegNames[]; bool SoftFloat; public: SparcTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple), SoftFloat(false) {} bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override { // The backend doesn't actually handle soft float yet, but in case someone // is using the support for the front end continue to support it. auto Feature = std::find(Features.begin(), Features.end(), "+soft-float"); if (Feature != Features.end()) { SoftFloat = true; Features.erase(Feature); } return true; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { DefineStd(Builder, "sparc", Opts); Builder.defineMacro("__REGISTER_PREFIX__", ""); if (SoftFloat) Builder.defineMacro("SOFT_FLOAT", "1"); } bool hasFeature(StringRef Feature) const override { return llvm::StringSwitch(Feature) .Case("softfloat", SoftFloat) .Case("sparc", true) .Default(false); } ArrayRef getTargetBuiltins() const override { // FIXME: Implement! return None; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { // FIXME: Implement! switch (*Name) { case 'I': // Signed 13-bit constant case 'J': // Zero case 'K': // 32-bit constant with the low 12 bits clear case 'L': // A constant in the range supported by movcc (11-bit signed imm) case 'M': // A constant in the range supported by movrcc (19-bit signed imm) case 'N': // Same as 'K' but zext (required for SIMode) case 'O': // The constant 4096 return true; } return false; } const char *getClobbers() const override { // FIXME: Implement! return ""; } // No Sparc V7 for now, the backend doesn't support it anyway. enum CPUKind { CK_GENERIC, CK_V8, CK_SUPERSPARC, CK_SPARCLITE, CK_F934, CK_HYPERSPARC, CK_SPARCLITE86X, CK_SPARCLET, CK_TSC701, CK_V9, CK_ULTRASPARC, CK_ULTRASPARC3, CK_NIAGARA, CK_NIAGARA2, CK_NIAGARA3, CK_NIAGARA4 } CPU = CK_GENERIC; enum CPUGeneration { CG_V8, CG_V9, }; CPUGeneration getCPUGeneration(CPUKind Kind) const { switch (Kind) { case CK_GENERIC: case CK_V8: case CK_SUPERSPARC: case CK_SPARCLITE: case CK_F934: case CK_HYPERSPARC: case CK_SPARCLITE86X: case CK_SPARCLET: case CK_TSC701: return CG_V8; case CK_V9: case CK_ULTRASPARC: case CK_ULTRASPARC3: case CK_NIAGARA: case CK_NIAGARA2: case CK_NIAGARA3: case CK_NIAGARA4: return CG_V9; } llvm_unreachable("Unexpected CPU kind"); } CPUKind getCPUKind(StringRef Name) const { return llvm::StringSwitch(Name) .Case("v8", CK_V8) .Case("supersparc", CK_SUPERSPARC) .Case("sparclite", CK_SPARCLITE) .Case("f934", CK_F934) .Case("hypersparc", CK_HYPERSPARC) .Case("sparclite86x", CK_SPARCLITE86X) .Case("sparclet", CK_SPARCLET) .Case("tsc701", CK_TSC701) .Case("v9", CK_V9) .Case("ultrasparc", CK_ULTRASPARC) .Case("ultrasparc3", CK_ULTRASPARC3) .Case("niagara", CK_NIAGARA) .Case("niagara2", CK_NIAGARA2) .Case("niagara3", CK_NIAGARA3) .Case("niagara4", CK_NIAGARA4) .Default(CK_GENERIC); } bool setCPU(const std::string &Name) override { CPU = getCPUKind(Name); return CPU != CK_GENERIC; } }; const char * const SparcTargetInfo::GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" }; ArrayRef SparcTargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } const TargetInfo::GCCRegAlias SparcTargetInfo::GCCRegAliases[] = { { { "g0" }, "r0" }, { { "g1" }, "r1" }, { { "g2" }, "r2" }, { { "g3" }, "r3" }, { { "g4" }, "r4" }, { { "g5" }, "r5" }, { { "g6" }, "r6" }, { { "g7" }, "r7" }, { { "o0" }, "r8" }, { { "o1" }, "r9" }, { { "o2" }, "r10" }, { { "o3" }, "r11" }, { { "o4" }, "r12" }, { { "o5" }, "r13" }, { { "o6", "sp" }, "r14" }, { { "o7" }, "r15" }, { { "l0" }, "r16" }, { { "l1" }, "r17" }, { { "l2" }, "r18" }, { { "l3" }, "r19" }, { { "l4" }, "r20" }, { { "l5" }, "r21" }, { { "l6" }, "r22" }, { { "l7" }, "r23" }, { { "i0" }, "r24" }, { { "i1" }, "r25" }, { { "i2" }, "r26" }, { { "i3" }, "r27" }, { { "i4" }, "r28" }, { { "i5" }, "r29" }, { { "i6", "fp" }, "r30" }, { { "i7" }, "r31" }, }; ArrayRef SparcTargetInfo::getGCCRegAliases() const { return llvm::makeArrayRef(GCCRegAliases); } // SPARC v8 is the 32-bit mode selected by Triple::sparc. class SparcV8TargetInfo : public SparcTargetInfo { public: SparcV8TargetInfo(const llvm::Triple &Triple) : SparcTargetInfo(Triple) { DataLayoutString = "E-m:e-p:32:32-i64:64-f128:64-n32-S64"; // NetBSD / OpenBSD use long (same as llvm default); everyone else uses int. switch (getTriple().getOS()) { default: SizeType = UnsignedInt; IntPtrType = SignedInt; PtrDiffType = SignedInt; break; case llvm::Triple::NetBSD: case llvm::Triple::OpenBSD: SizeType = UnsignedLong; IntPtrType = SignedLong; PtrDiffType = SignedLong; break; } } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { SparcTargetInfo::getTargetDefines(Opts, Builder); switch (getCPUGeneration(CPU)) { case CG_V8: Builder.defineMacro("__sparcv8"); if (getTriple().getOS() != llvm::Triple::Solaris) Builder.defineMacro("__sparcv8__"); break; case CG_V9: Builder.defineMacro("__sparcv9"); if (getTriple().getOS() != llvm::Triple::Solaris) { Builder.defineMacro("__sparcv9__"); Builder.defineMacro("__sparc_v9__"); } break; } } }; // SPARCV8el is the 32-bit little-endian mode selected by Triple::sparcel. class SparcV8elTargetInfo : public SparcV8TargetInfo { public: SparcV8elTargetInfo(const llvm::Triple &Triple) : SparcV8TargetInfo(Triple) { DataLayoutString = "e-m:e-p:32:32-i64:64-f128:64-n32-S64"; BigEndian = false; } }; // SPARC v9 is the 64-bit mode selected by Triple::sparcv9. class SparcV9TargetInfo : public SparcTargetInfo { public: SparcV9TargetInfo(const llvm::Triple &Triple) : SparcTargetInfo(Triple) { // FIXME: Support Sparc quad-precision long double? DataLayoutString = "E-m:e-i64:64-n32:64-S128"; // This is an LP64 platform. LongWidth = LongAlign = PointerWidth = PointerAlign = 64; // OpenBSD uses long long for int64_t and intmax_t. if (getTriple().getOS() == llvm::Triple::OpenBSD) IntMaxType = SignedLongLong; else IntMaxType = SignedLong; Int64Type = IntMaxType; // The SPARCv8 System V ABI has long double 128-bits in size, but 64-bit // aligned. The SPARCv9 SCD 2.4.1 says 16-byte aligned. LongDoubleWidth = 128; LongDoubleAlign = 128; LongDoubleFormat = &llvm::APFloat::IEEEquad; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { SparcTargetInfo::getTargetDefines(Opts, Builder); Builder.defineMacro("__sparcv9"); Builder.defineMacro("__arch64__"); // Solaris doesn't need these variants, but the BSDs do. if (getTriple().getOS() != llvm::Triple::Solaris) { Builder.defineMacro("__sparc64__"); Builder.defineMacro("__sparc_v9__"); Builder.defineMacro("__sparcv9__"); } } bool setCPU(const std::string &Name) override { if (!SparcTargetInfo::setCPU(Name)) return false; return getCPUGeneration(CPU) == CG_V9; } }; class SystemZTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; static const char *const GCCRegNames[]; std::string CPU; bool HasTransactionalExecution; bool HasVector; public: SystemZTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple), CPU("z10"), HasTransactionalExecution(false), HasVector(false) { IntMaxType = SignedLong; Int64Type = SignedLong; TLSSupported = true; IntWidth = IntAlign = 32; LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64; PointerWidth = PointerAlign = 64; LongDoubleWidth = 128; LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEquad; DefaultAlignForAttributeAligned = 64; MinGlobalAlign = 16; DataLayoutString = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64"; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__s390__"); Builder.defineMacro("__s390x__"); Builder.defineMacro("__zarch__"); Builder.defineMacro("__LONG_DOUBLE_128__"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); if (HasTransactionalExecution) Builder.defineMacro("__HTM__"); if (Opts.ZVector) Builder.defineMacro("__VEC__", "10301"); } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::SystemZ::LastTSBuiltin-Builtin::FirstTSBuiltin); } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override { // No aliases. return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override; const char *getClobbers() const override { // FIXME: Is this really right? return ""; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::SystemZBuiltinVaList; } bool setCPU(const std::string &Name) override { CPU = Name; bool CPUKnown = llvm::StringSwitch(Name) .Case("z10", true) .Case("z196", true) .Case("zEC12", true) .Case("z13", true) .Default(false); return CPUKnown; } bool initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const override { if (CPU == "zEC12") Features["transactional-execution"] = true; if (CPU == "z13") { Features["transactional-execution"] = true; Features["vector"] = true; } return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override { HasTransactionalExecution = false; for (const auto &Feature : Features) { if (Feature == "+transactional-execution") HasTransactionalExecution = true; else if (Feature == "+vector") HasVector = true; } // If we use the vector ABI, vector types are 64-bit aligned. if (HasVector) { MaxVectorAlign = 64; DataLayoutString = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64" "-v128:64-a:8:16-n32:64"; } return true; } bool hasFeature(StringRef Feature) const override { return llvm::StringSwitch(Feature) .Case("systemz", true) .Case("htm", HasTransactionalExecution) .Case("vx", HasVector) .Default(false); } StringRef getABI() const override { if (HasVector) return "vector"; return ""; } bool useFloat128ManglingForLongDouble() const override { return true; } }; const Builtin::Info SystemZTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsSystemZ.def" }; const char *const SystemZTargetInfo::GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "f0", "f2", "f4", "f6", "f1", "f3", "f5", "f7", "f8", "f10", "f12", "f14", "f9", "f11", "f13", "f15" }; ArrayRef SystemZTargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } bool SystemZTargetInfo:: validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const { switch (*Name) { default: return false; case 'a': // Address register case 'd': // Data register (equivalent to 'r') case 'f': // Floating-point register Info.setAllowsRegister(); return true; case 'I': // Unsigned 8-bit constant case 'J': // Unsigned 12-bit constant case 'K': // Signed 16-bit constant case 'L': // Signed 20-bit displacement (on all targets we support) case 'M': // 0x7fffffff return true; case 'Q': // Memory with base and unsigned 12-bit displacement case 'R': // Likewise, plus an index case 'S': // Memory with base and signed 20-bit displacement case 'T': // Likewise, plus an index Info.setAllowsMemory(); return true; } } class MSP430TargetInfo : public TargetInfo { static const char *const GCCRegNames[]; public: MSP430TargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { BigEndian = false; TLSSupported = false; IntWidth = 16; IntAlign = 16; LongWidth = 32; LongLongWidth = 64; LongAlign = LongLongAlign = 16; PointerWidth = 16; PointerAlign = 16; SuitableAlign = 16; SizeType = UnsignedInt; IntMaxType = SignedLongLong; IntPtrType = SignedInt; PtrDiffType = SignedInt; SigAtomicType = SignedLong; DataLayoutString = "e-m:e-p:16:16-i32:16:32-a:16-n8:16"; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("MSP430"); Builder.defineMacro("__MSP430__"); // FIXME: defines for different 'flavours' of MCU } ArrayRef getTargetBuiltins() const override { // FIXME: Implement. return None; } bool hasFeature(StringRef Feature) const override { return Feature == "msp430"; } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override { // No aliases. return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { // FIXME: implement switch (*Name) { case 'K': // the constant 1 case 'L': // constant -1^20 .. 1^19 case 'M': // constant 1-4: return true; } // No target constraints for now. return false; } const char *getClobbers() const override { // FIXME: Is this really right? return ""; } BuiltinVaListKind getBuiltinVaListKind() const override { // FIXME: implement return TargetInfo::CharPtrBuiltinVaList; } }; const char *const MSP430TargetInfo::GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}; ArrayRef MSP430TargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } // LLVM and Clang cannot be used directly to output native binaries for // target, but is used to compile C code to llvm bitcode with correct // type and alignment information. // // TCE uses the llvm bitcode as input and uses it for generating customized // target processor and program binary. TCE co-design environment is // publicly available in http://tce.cs.tut.fi static const unsigned TCEOpenCLAddrSpaceMap[] = { 3, // opencl_global 4, // opencl_local 5, // opencl_constant // FIXME: generic has to be added to the target 0, // opencl_generic 0, // cuda_device 0, // cuda_constant 0 // cuda_shared }; class TCETargetInfo : public TargetInfo { public: TCETargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { TLSSupported = false; IntWidth = 32; LongWidth = LongLongWidth = 32; PointerWidth = 32; IntAlign = 32; LongAlign = LongLongAlign = 32; PointerAlign = 32; SuitableAlign = 32; SizeType = UnsignedInt; IntMaxType = SignedLong; IntPtrType = SignedInt; PtrDiffType = SignedInt; FloatWidth = 32; FloatAlign = 32; DoubleWidth = 32; DoubleAlign = 32; LongDoubleWidth = 32; LongDoubleAlign = 32; FloatFormat = &llvm::APFloat::IEEEsingle; DoubleFormat = &llvm::APFloat::IEEEsingle; LongDoubleFormat = &llvm::APFloat::IEEEsingle; DataLayoutString = "E-p:32:32-i8:8:32-i16:16:32-i64:32" "-f64:32-v64:32-v128:32-a:0:32-n32"; AddrSpaceMap = &TCEOpenCLAddrSpaceMap; UseAddrSpaceMapMangling = true; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { DefineStd(Builder, "tce", Opts); Builder.defineMacro("__TCE__"); Builder.defineMacro("__TCE_V1__"); } bool hasFeature(StringRef Feature) const override { return Feature == "tce"; } ArrayRef getTargetBuiltins() const override { return None; } const char *getClobbers() const override { return ""; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; } ArrayRef getGCCRegNames() const override { return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { return true; } ArrayRef getGCCRegAliases() const override { return None; } }; class BPFTargetInfo : public TargetInfo { public: BPFTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { LongWidth = LongAlign = PointerWidth = PointerAlign = 64; SizeType = UnsignedLong; PtrDiffType = SignedLong; IntPtrType = SignedLong; IntMaxType = SignedLong; Int64Type = SignedLong; RegParmMax = 5; if (Triple.getArch() == llvm::Triple::bpfeb) { BigEndian = true; DataLayoutString = "E-m:e-p:64:64-i64:64-n32:64-S128"; } else { BigEndian = false; DataLayoutString = "e-m:e-p:64:64-i64:64-n32:64-S128"; } MaxAtomicPromoteWidth = 64; MaxAtomicInlineWidth = 64; TLSSupported = false; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { DefineStd(Builder, "bpf", Opts); Builder.defineMacro("__BPF__"); } bool hasFeature(StringRef Feature) const override { return Feature == "bpf"; } ArrayRef getTargetBuiltins() const override { return None; } const char *getClobbers() const override { return ""; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; } ArrayRef getGCCRegNames() const override { return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { return true; } ArrayRef getGCCRegAliases() const override { return None; } }; class MipsTargetInfoBase : public TargetInfo { virtual void setDataLayoutString() = 0; static const Builtin::Info BuiltinInfo[]; std::string CPU; bool IsMips16; bool IsMicromips; bool IsNan2008; bool IsSingleFloat; enum MipsFloatABI { HardFloat, SoftFloat } FloatABI; enum DspRevEnum { NoDSP, DSP1, DSP2 } DspRev; bool HasMSA; protected: bool HasFP64; std::string ABI; public: MipsTargetInfoBase(const llvm::Triple &Triple, const std::string &ABIStr, const std::string &CPUStr) : TargetInfo(Triple), CPU(CPUStr), IsMips16(false), IsMicromips(false), IsNan2008(false), IsSingleFloat(false), FloatABI(HardFloat), DspRev(NoDSP), HasMSA(false), HasFP64(false), ABI(ABIStr) { TheCXXABI.set(TargetCXXABI::GenericMIPS); } bool isNaN2008Default() const { return CPU == "mips32r6" || CPU == "mips64r6"; } bool isFP64Default() const { return CPU == "mips32r6" || ABI == "n32" || ABI == "n64" || ABI == "64"; } bool isNan2008() const override { return IsNan2008; } StringRef getABI() const override { return ABI; } bool setCPU(const std::string &Name) override { bool IsMips32 = getTriple().getArch() == llvm::Triple::mips || getTriple().getArch() == llvm::Triple::mipsel; CPU = Name; return llvm::StringSwitch(Name) .Case("mips1", IsMips32) .Case("mips2", IsMips32) .Case("mips3", true) .Case("mips4", true) .Case("mips5", true) .Case("mips32", IsMips32) .Case("mips32r2", IsMips32) .Case("mips32r3", IsMips32) .Case("mips32r5", IsMips32) .Case("mips32r6", IsMips32) .Case("mips64", true) .Case("mips64r2", true) .Case("mips64r3", true) .Case("mips64r5", true) .Case("mips64r6", true) .Case("octeon", true) .Case("p5600", true) .Default(false); } const std::string& getCPU() const { return CPU; } bool initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const override { if (CPU == "octeon") Features["mips64r2"] = Features["cnmips"] = true; else Features[CPU] = true; return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__mips__"); Builder.defineMacro("_mips"); if (Opts.GNUMode) Builder.defineMacro("mips"); Builder.defineMacro("__REGISTER_PREFIX__", ""); switch (FloatABI) { case HardFloat: Builder.defineMacro("__mips_hard_float", Twine(1)); break; case SoftFloat: Builder.defineMacro("__mips_soft_float", Twine(1)); break; } if (IsSingleFloat) Builder.defineMacro("__mips_single_float", Twine(1)); Builder.defineMacro("__mips_fpr", HasFP64 ? Twine(64) : Twine(32)); Builder.defineMacro("_MIPS_FPSET", Twine(32 / (HasFP64 || IsSingleFloat ? 1 : 2))); if (IsMips16) Builder.defineMacro("__mips16", Twine(1)); if (IsMicromips) Builder.defineMacro("__mips_micromips", Twine(1)); if (IsNan2008) Builder.defineMacro("__mips_nan2008", Twine(1)); switch (DspRev) { default: break; case DSP1: Builder.defineMacro("__mips_dsp_rev", Twine(1)); Builder.defineMacro("__mips_dsp", Twine(1)); break; case DSP2: Builder.defineMacro("__mips_dsp_rev", Twine(2)); Builder.defineMacro("__mips_dspr2", Twine(1)); Builder.defineMacro("__mips_dsp", Twine(1)); break; } if (HasMSA) Builder.defineMacro("__mips_msa", Twine(1)); Builder.defineMacro("_MIPS_SZPTR", Twine(getPointerWidth(0))); Builder.defineMacro("_MIPS_SZINT", Twine(getIntWidth())); Builder.defineMacro("_MIPS_SZLONG", Twine(getLongWidth())); Builder.defineMacro("_MIPS_ARCH", "\"" + CPU + "\""); Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper()); // These shouldn't be defined for MIPS-I but there's no need to check // for that since MIPS-I isn't supported. Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::Mips::LastTSBuiltin - Builtin::FirstTSBuiltin); } bool hasFeature(StringRef Feature) const override { return llvm::StringSwitch(Feature) .Case("mips", true) .Case("fp64", HasFP64) .Default(false); } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; } ArrayRef getGCCRegNames() const override { static const char *const GCCRegNames[] = { // CPU register names // Must match second column of GCCRegAliases "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31", // Floating point register names "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", // Hi/lo and condition register names "hi", "lo", "", "$fcc0","$fcc1","$fcc2","$fcc3","$fcc4", "$fcc5","$fcc6","$fcc7", // MSA register names "$w0", "$w1", "$w2", "$w3", "$w4", "$w5", "$w6", "$w7", "$w8", "$w9", "$w10", "$w11", "$w12", "$w13", "$w14", "$w15", "$w16", "$w17", "$w18", "$w19", "$w20", "$w21", "$w22", "$w23", "$w24", "$w25", "$w26", "$w27", "$w28", "$w29", "$w30", "$w31", // MSA control register names "$msair", "$msacsr", "$msaaccess", "$msasave", "$msamodify", "$msarequest", "$msamap", "$msaunmap" }; return llvm::makeArrayRef(GCCRegNames); } ArrayRef getGCCRegAliases() const override = 0; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { switch (*Name) { default: return false; case 'r': // CPU registers. case 'd': // Equivalent to "r" unless generating MIPS16 code. case 'y': // Equivalent to "r", backward compatibility only. case 'f': // floating-point registers. case 'c': // $25 for indirect jumps case 'l': // lo register case 'x': // hilo register pair Info.setAllowsRegister(); return true; case 'I': // Signed 16-bit constant case 'J': // Integer 0 case 'K': // Unsigned 16-bit constant case 'L': // Signed 32-bit constant, lower 16-bit zeros (for lui) case 'M': // Constants not loadable via lui, addiu, or ori case 'N': // Constant -1 to -65535 case 'O': // A signed 15-bit constant case 'P': // A constant between 1 go 65535 return true; case 'R': // An address that can be used in a non-macro load or store Info.setAllowsMemory(); return true; case 'Z': if (Name[1] == 'C') { // An address usable by ll, and sc. Info.setAllowsMemory(); Name++; // Skip over 'Z'. return true; } return false; } } std::string convertConstraint(const char *&Constraint) const override { std::string R; switch (*Constraint) { case 'Z': // Two-character constraint; add "^" hint for later parsing. if (Constraint[1] == 'C') { R = std::string("^") + std::string(Constraint, 2); Constraint++; return R; } break; } return TargetInfo::convertConstraint(Constraint); } const char *getClobbers() const override { // In GCC, $1 is not widely used in generated code (it's used only in a few // specific situations), so there is no real need for users to add it to // the clobbers list if they want to use it in their inline assembly code. // // In LLVM, $1 is treated as a normal GPR and is always allocatable during // code generation, so using it in inline assembly without adding it to the // clobbers list can cause conflicts between the inline assembly code and // the surrounding generated code. // // Another problem is that LLVM is allowed to choose $1 for inline assembly // operands, which will conflict with the ".set at" assembler option (which // we use only for inline assembly, in order to maintain compatibility with // GCC) and will also conflict with the user's usage of $1. // // The easiest way to avoid these conflicts and keep $1 as an allocatable // register for generated code is to automatically clobber $1 for all inline // assembly code. // // FIXME: We should automatically clobber $1 only for inline assembly code // which actually uses it. This would allow LLVM to use $1 for inline // assembly operands if the user's assembly code doesn't use it. return "~{$1}"; } bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override { IsMips16 = false; IsMicromips = false; IsNan2008 = isNaN2008Default(); IsSingleFloat = false; FloatABI = HardFloat; DspRev = NoDSP; HasFP64 = isFP64Default(); for (const auto &Feature : Features) { if (Feature == "+single-float") IsSingleFloat = true; else if (Feature == "+soft-float") FloatABI = SoftFloat; else if (Feature == "+mips16") IsMips16 = true; else if (Feature == "+micromips") IsMicromips = true; else if (Feature == "+dsp") DspRev = std::max(DspRev, DSP1); else if (Feature == "+dspr2") DspRev = std::max(DspRev, DSP2); else if (Feature == "+msa") HasMSA = true; else if (Feature == "+fp64") HasFP64 = true; else if (Feature == "-fp64") HasFP64 = false; else if (Feature == "+nan2008") IsNan2008 = true; else if (Feature == "-nan2008") IsNan2008 = false; } setDataLayoutString(); return true; } int getEHDataRegisterNumber(unsigned RegNo) const override { if (RegNo == 0) return 4; if (RegNo == 1) return 5; return -1; } bool isCLZForZeroUndef() const override { return false; } }; const Builtin::Info MipsTargetInfoBase::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsMips.def" }; class Mips32TargetInfoBase : public MipsTargetInfoBase { public: Mips32TargetInfoBase(const llvm::Triple &Triple) : MipsTargetInfoBase(Triple, "o32", "mips32r2") { SizeType = UnsignedInt; PtrDiffType = SignedInt; Int64Type = SignedLongLong; IntMaxType = Int64Type; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; } bool setABI(const std::string &Name) override { if (Name == "o32" || Name == "eabi") { ABI = Name; return true; } return false; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { MipsTargetInfoBase::getTargetDefines(Opts, Builder); Builder.defineMacro("__mips", "32"); Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS32"); const std::string& CPUStr = getCPU(); if (CPUStr == "mips32") Builder.defineMacro("__mips_isa_rev", "1"); else if (CPUStr == "mips32r2") Builder.defineMacro("__mips_isa_rev", "2"); else if (CPUStr == "mips32r3") Builder.defineMacro("__mips_isa_rev", "3"); else if (CPUStr == "mips32r5") Builder.defineMacro("__mips_isa_rev", "5"); else if (CPUStr == "mips32r6") Builder.defineMacro("__mips_isa_rev", "6"); if (ABI == "o32") { Builder.defineMacro("__mips_o32"); Builder.defineMacro("_ABIO32", "1"); Builder.defineMacro("_MIPS_SIM", "_ABIO32"); } else if (ABI == "eabi") Builder.defineMacro("__mips_eabi"); else llvm_unreachable("Invalid ABI for Mips32."); } ArrayRef getGCCRegAliases() const override { static const TargetInfo::GCCRegAlias GCCRegAliases[] = { { { "at" }, "$1" }, { { "v0" }, "$2" }, { { "v1" }, "$3" }, { { "a0" }, "$4" }, { { "a1" }, "$5" }, { { "a2" }, "$6" }, { { "a3" }, "$7" }, { { "t0" }, "$8" }, { { "t1" }, "$9" }, { { "t2" }, "$10" }, { { "t3" }, "$11" }, { { "t4" }, "$12" }, { { "t5" }, "$13" }, { { "t6" }, "$14" }, { { "t7" }, "$15" }, { { "s0" }, "$16" }, { { "s1" }, "$17" }, { { "s2" }, "$18" }, { { "s3" }, "$19" }, { { "s4" }, "$20" }, { { "s5" }, "$21" }, { { "s6" }, "$22" }, { { "s7" }, "$23" }, { { "t8" }, "$24" }, { { "t9" }, "$25" }, { { "k0" }, "$26" }, { { "k1" }, "$27" }, { { "gp" }, "$28" }, { { "sp","$sp" }, "$29" }, { { "fp","$fp" }, "$30" }, { { "ra" }, "$31" } }; return llvm::makeArrayRef(GCCRegAliases); } }; class Mips32EBTargetInfo : public Mips32TargetInfoBase { void setDataLayoutString() override { DataLayoutString = "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64"; } public: Mips32EBTargetInfo(const llvm::Triple &Triple) : Mips32TargetInfoBase(Triple) { } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { DefineStd(Builder, "MIPSEB", Opts); Builder.defineMacro("_MIPSEB"); Mips32TargetInfoBase::getTargetDefines(Opts, Builder); } }; class Mips32ELTargetInfo : public Mips32TargetInfoBase { void setDataLayoutString() override { DataLayoutString = "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64"; } public: Mips32ELTargetInfo(const llvm::Triple &Triple) : Mips32TargetInfoBase(Triple) { BigEndian = false; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { DefineStd(Builder, "MIPSEL", Opts); Builder.defineMacro("_MIPSEL"); Mips32TargetInfoBase::getTargetDefines(Opts, Builder); } }; class Mips64TargetInfoBase : public MipsTargetInfoBase { public: Mips64TargetInfoBase(const llvm::Triple &Triple) : MipsTargetInfoBase(Triple, "n64", "mips64r2") { LongDoubleWidth = LongDoubleAlign = 128; LongDoubleFormat = &llvm::APFloat::IEEEquad; if (getTriple().getOS() == llvm::Triple::FreeBSD) { LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; } setN64ABITypes(); SuitableAlign = 128; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; } void setN64ABITypes() { LongWidth = LongAlign = 64; PointerWidth = PointerAlign = 64; SizeType = UnsignedLong; PtrDiffType = SignedLong; Int64Type = SignedLong; IntMaxType = Int64Type; } void setN32ABITypes() { LongWidth = LongAlign = 32; PointerWidth = PointerAlign = 32; SizeType = UnsignedInt; PtrDiffType = SignedInt; Int64Type = SignedLongLong; IntMaxType = Int64Type; } bool setABI(const std::string &Name) override { if (Name == "n32") { setN32ABITypes(); ABI = Name; return true; } if (Name == "n64") { setN64ABITypes(); ABI = Name; return true; } return false; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { MipsTargetInfoBase::getTargetDefines(Opts, Builder); Builder.defineMacro("__mips", "64"); Builder.defineMacro("__mips64"); Builder.defineMacro("__mips64__"); Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS64"); const std::string& CPUStr = getCPU(); if (CPUStr == "mips64") Builder.defineMacro("__mips_isa_rev", "1"); else if (CPUStr == "mips64r2") Builder.defineMacro("__mips_isa_rev", "2"); else if (CPUStr == "mips64r3") Builder.defineMacro("__mips_isa_rev", "3"); else if (CPUStr == "mips64r5") Builder.defineMacro("__mips_isa_rev", "5"); else if (CPUStr == "mips64r6") Builder.defineMacro("__mips_isa_rev", "6"); if (ABI == "n32") { Builder.defineMacro("__mips_n32"); Builder.defineMacro("_ABIN32", "2"); Builder.defineMacro("_MIPS_SIM", "_ABIN32"); } else if (ABI == "n64") { Builder.defineMacro("__mips_n64"); Builder.defineMacro("_ABI64", "3"); Builder.defineMacro("_MIPS_SIM", "_ABI64"); } else llvm_unreachable("Invalid ABI for Mips64."); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); } ArrayRef getGCCRegAliases() const override { static const TargetInfo::GCCRegAlias GCCRegAliases[] = { { { "at" }, "$1" }, { { "v0" }, "$2" }, { { "v1" }, "$3" }, { { "a0" }, "$4" }, { { "a1" }, "$5" }, { { "a2" }, "$6" }, { { "a3" }, "$7" }, { { "a4" }, "$8" }, { { "a5" }, "$9" }, { { "a6" }, "$10" }, { { "a7" }, "$11" }, { { "t0" }, "$12" }, { { "t1" }, "$13" }, { { "t2" }, "$14" }, { { "t3" }, "$15" }, { { "s0" }, "$16" }, { { "s1" }, "$17" }, { { "s2" }, "$18" }, { { "s3" }, "$19" }, { { "s4" }, "$20" }, { { "s5" }, "$21" }, { { "s6" }, "$22" }, { { "s7" }, "$23" }, { { "t8" }, "$24" }, { { "t9" }, "$25" }, { { "k0" }, "$26" }, { { "k1" }, "$27" }, { { "gp" }, "$28" }, { { "sp","$sp" }, "$29" }, { { "fp","$fp" }, "$30" }, { { "ra" }, "$31" } }; return llvm::makeArrayRef(GCCRegAliases); } bool hasInt128Type() const override { return true; } }; class Mips64EBTargetInfo : public Mips64TargetInfoBase { void setDataLayoutString() override { if (ABI == "n32") DataLayoutString = "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32:64-S128"; else DataLayoutString = "E-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128"; } public: Mips64EBTargetInfo(const llvm::Triple &Triple) : Mips64TargetInfoBase(Triple) {} void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { DefineStd(Builder, "MIPSEB", Opts); Builder.defineMacro("_MIPSEB"); Mips64TargetInfoBase::getTargetDefines(Opts, Builder); } }; class Mips64ELTargetInfo : public Mips64TargetInfoBase { void setDataLayoutString() override { if (ABI == "n32") DataLayoutString = "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32:64-S128"; else DataLayoutString = "e-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128"; } public: Mips64ELTargetInfo(const llvm::Triple &Triple) : Mips64TargetInfoBase(Triple) { // Default ABI is n64. BigEndian = false; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { DefineStd(Builder, "MIPSEL", Opts); Builder.defineMacro("_MIPSEL"); Mips64TargetInfoBase::getTargetDefines(Opts, Builder); } }; class PNaClTargetInfo : public TargetInfo { public: PNaClTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { BigEndian = false; this->UserLabelPrefix = ""; this->LongAlign = 32; this->LongWidth = 32; this->PointerAlign = 32; this->PointerWidth = 32; this->IntMaxType = TargetInfo::SignedLongLong; this->Int64Type = TargetInfo::SignedLongLong; this->DoubleAlign = 64; this->LongDoubleWidth = 64; this->LongDoubleAlign = 64; this->SizeType = TargetInfo::UnsignedInt; this->PtrDiffType = TargetInfo::SignedInt; this->IntPtrType = TargetInfo::SignedInt; this->RegParmMax = 0; // Disallow regparm } void getArchDefines(const LangOptions &Opts, MacroBuilder &Builder) const { Builder.defineMacro("__le32__"); Builder.defineMacro("__pnacl__"); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { getArchDefines(Opts, Builder); } bool hasFeature(StringRef Feature) const override { return Feature == "pnacl"; } ArrayRef getTargetBuiltins() const override { return None; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::PNaClABIBuiltinVaList; } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { return false; } const char *getClobbers() const override { return ""; } }; ArrayRef PNaClTargetInfo::getGCCRegNames() const { return None; } ArrayRef PNaClTargetInfo::getGCCRegAliases() const { return None; } // We attempt to use PNaCl (le32) frontend and Mips32EL backend. class NaClMips32ELTargetInfo : public Mips32ELTargetInfo { public: NaClMips32ELTargetInfo(const llvm::Triple &Triple) : Mips32ELTargetInfo(Triple) { } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::PNaClABIBuiltinVaList; } }; class Le64TargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; public: Le64TargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { BigEndian = false; NoAsmVariants = true; LongWidth = LongAlign = PointerWidth = PointerAlign = 64; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; DataLayoutString = "e-m:e-v128:32-v16:16-v32:32-v96:32-n8:16:32:64-S128"; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { DefineStd(Builder, "unix", Opts); defineCPUMacros(Builder, "le64", /*Tuning=*/false); Builder.defineMacro("__ELF__"); } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::Le64::LastTSBuiltin - Builtin::FirstTSBuiltin); } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::PNaClABIBuiltinVaList; } const char *getClobbers() const override { return ""; } ArrayRef getGCCRegNames() const override { return None; } ArrayRef getGCCRegAliases() const override { return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { return false; } bool hasProtectedVisibility() const override { return false; } }; class WebAssemblyTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; enum SIMDEnum { NoSIMD, SIMD128, } SIMDLevel; public: explicit WebAssemblyTargetInfo(const llvm::Triple &T) : TargetInfo(T), SIMDLevel(NoSIMD) { BigEndian = false; NoAsmVariants = true; SuitableAlign = 128; LargeArrayMinWidth = 128; LargeArrayAlign = 128; SimdDefaultAlign = 128; SigAtomicType = SignedLong; LongDoubleWidth = LongDoubleAlign = 128; LongDoubleFormat = &llvm::APFloat::IEEEquad; } protected: void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { defineCPUMacros(Builder, "wasm", /*Tuning=*/false); if (SIMDLevel >= SIMD128) Builder.defineMacro("__wasm_simd128__"); } private: bool initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const override { if (CPU == "bleeding-edge") Features["simd128"] = true; return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } bool hasFeature(StringRef Feature) const final { return llvm::StringSwitch(Feature) .Case("simd128", SIMDLevel >= SIMD128) .Default(false); } bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) final { for (const auto &Feature : Features) { if (Feature == "+simd128") { SIMDLevel = std::max(SIMDLevel, SIMD128); continue; } if (Feature == "-simd128") { SIMDLevel = std::min(SIMDLevel, SIMDEnum(SIMD128 - 1)); continue; } Diags.Report(diag::err_opt_not_valid_with_opt) << Feature << "-target-feature"; return false; } return true; } bool setCPU(const std::string &Name) final { return llvm::StringSwitch(Name) .Case("mvp", true) .Case("bleeding-edge", true) .Case("generic", true) .Default(false); } ArrayRef getTargetBuiltins() const final { return llvm::makeArrayRef(BuiltinInfo, clang::WebAssembly::LastTSBuiltin - Builtin::FirstTSBuiltin); } BuiltinVaListKind getBuiltinVaListKind() const final { return VoidPtrBuiltinVaList; } ArrayRef getGCCRegNames() const final { return None; } ArrayRef getGCCRegAliases() const final { return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const final { return false; } const char *getClobbers() const final { return ""; } bool isCLZForZeroUndef() const final { return false; } bool hasInt128Type() const final { return true; } IntType getIntTypeByWidth(unsigned BitWidth, bool IsSigned) const final { // WebAssembly prefers long long for explicitly 64-bit integers. return BitWidth == 64 ? (IsSigned ? SignedLongLong : UnsignedLongLong) : TargetInfo::getIntTypeByWidth(BitWidth, IsSigned); } IntType getLeastIntTypeByWidth(unsigned BitWidth, bool IsSigned) const final { // WebAssembly uses long long for int_least64_t and int_fast64_t. return BitWidth == 64 ? (IsSigned ? SignedLongLong : UnsignedLongLong) : TargetInfo::getLeastIntTypeByWidth(BitWidth, IsSigned); } }; const Builtin::Info WebAssemblyTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsWebAssembly.def" }; class WebAssembly32TargetInfo : public WebAssemblyTargetInfo { public: explicit WebAssembly32TargetInfo(const llvm::Triple &T) : WebAssemblyTargetInfo(T) { MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; DataLayoutString = "e-m:e-p:32:32-i64:64-n32:64-S128"; } protected: void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WebAssemblyTargetInfo::getTargetDefines(Opts, Builder); defineCPUMacros(Builder, "wasm32", /*Tuning=*/false); } }; class WebAssembly64TargetInfo : public WebAssemblyTargetInfo { public: explicit WebAssembly64TargetInfo(const llvm::Triple &T) : WebAssemblyTargetInfo(T) { LongAlign = LongWidth = 64; PointerAlign = PointerWidth = 64; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; DataLayoutString = "e-m:e-p:64:64-i64:64-n32:64-S128"; } protected: void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WebAssemblyTargetInfo::getTargetDefines(Opts, Builder); defineCPUMacros(Builder, "wasm64", /*Tuning=*/false); } }; const Builtin::Info Le64TargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsLe64.def" }; static const unsigned SPIRAddrSpaceMap[] = { 1, // opencl_global 3, // opencl_local 2, // opencl_constant 4, // opencl_generic 0, // cuda_device 0, // cuda_constant 0 // cuda_shared }; class SPIRTargetInfo : public TargetInfo { public: SPIRTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { assert(getTriple().getOS() == llvm::Triple::UnknownOS && "SPIR target must use unknown OS"); assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && "SPIR target must use unknown environment type"); BigEndian = false; TLSSupported = false; LongWidth = LongAlign = 64; AddrSpaceMap = &SPIRAddrSpaceMap; UseAddrSpaceMapMangling = true; // Define available target features // These must be defined in sorted order! NoAsmVariants = true; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { DefineStd(Builder, "SPIR", Opts); } bool hasFeature(StringRef Feature) const override { return Feature == "spir"; } ArrayRef getTargetBuiltins() const override { return None; } const char *getClobbers() const override { return ""; } ArrayRef getGCCRegNames() const override { return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { return true; } ArrayRef getGCCRegAliases() const override { return None; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; } CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { return (CC == CC_SpirFunction || CC == CC_SpirKernel) ? CCCR_OK : CCCR_Warning; } CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { return CC_SpirFunction; } }; class SPIR32TargetInfo : public SPIRTargetInfo { public: SPIR32TargetInfo(const llvm::Triple &Triple) : SPIRTargetInfo(Triple) { PointerWidth = PointerAlign = 32; SizeType = TargetInfo::UnsignedInt; PtrDiffType = IntPtrType = TargetInfo::SignedInt; DataLayoutString = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-" "v96:128-v192:256-v256:256-v512:512-v1024:1024"; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { DefineStd(Builder, "SPIR32", Opts); } }; class SPIR64TargetInfo : public SPIRTargetInfo { public: SPIR64TargetInfo(const llvm::Triple &Triple) : SPIRTargetInfo(Triple) { PointerWidth = PointerAlign = 64; SizeType = TargetInfo::UnsignedLong; PtrDiffType = IntPtrType = TargetInfo::SignedLong; DataLayoutString = "e-i64:64-v16:16-v24:32-v32:32-v48:64-" "v96:128-v192:256-v256:256-v512:512-v1024:1024"; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { DefineStd(Builder, "SPIR64", Opts); } }; class XCoreTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; public: XCoreTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { BigEndian = false; NoAsmVariants = true; LongLongAlign = 32; SuitableAlign = 32; DoubleAlign = LongDoubleAlign = 32; SizeType = UnsignedInt; PtrDiffType = SignedInt; IntPtrType = SignedInt; WCharType = UnsignedChar; WIntType = UnsignedInt; UseZeroLengthBitfieldAlignment = true; DataLayoutString = "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:32" "-f64:32-a:0:32-n32"; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__XS1B__"); } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::XCore::LastTSBuiltin-Builtin::FirstTSBuiltin); } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; } const char *getClobbers() const override { return ""; } ArrayRef getGCCRegNames() const override { static const char * const GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "cp", "dp", "sp", "lr" }; return llvm::makeArrayRef(GCCRegNames); } ArrayRef getGCCRegAliases() const override { return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { return false; } int getEHDataRegisterNumber(unsigned RegNo) const override { // R0=ExceptionPointerRegister R1=ExceptionSelectorRegister return (RegNo < 2)? RegNo : -1; } }; const Builtin::Info XCoreTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsXCore.def" }; // x86_32 Android target class AndroidX86_32TargetInfo : public LinuxTargetInfo { public: AndroidX86_32TargetInfo(const llvm::Triple &Triple) : LinuxTargetInfo(Triple) { SuitableAlign = 32; LongDoubleWidth = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; } }; // x86_64 Android target class AndroidX86_64TargetInfo : public LinuxTargetInfo { public: AndroidX86_64TargetInfo(const llvm::Triple &Triple) : LinuxTargetInfo(Triple) { LongDoubleFormat = &llvm::APFloat::IEEEquad; } bool useFloat128ManglingForLongDouble() const override { return true; } }; } // end anonymous namespace //===----------------------------------------------------------------------===// // Driver code //===----------------------------------------------------------------------===// static TargetInfo *AllocateTarget(const llvm::Triple &Triple) { llvm::Triple::OSType os = Triple.getOS(); switch (Triple.getArch()) { default: return nullptr; case llvm::Triple::xcore: return new XCoreTargetInfo(Triple); case llvm::Triple::hexagon: return new HexagonTargetInfo(Triple); case llvm::Triple::aarch64: if (Triple.isOSDarwin()) return new DarwinAArch64TargetInfo(Triple); switch (os) { case llvm::Triple::CloudABI: return new CloudABITargetInfo(Triple); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple); case llvm::Triple::Linux: return new LinuxTargetInfo(Triple); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple); default: return new AArch64leTargetInfo(Triple); } case llvm::Triple::aarch64_be: switch (os) { case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple); case llvm::Triple::Linux: return new LinuxTargetInfo(Triple); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple); default: return new AArch64beTargetInfo(Triple); } case llvm::Triple::arm: case llvm::Triple::thumb: if (Triple.isOSBinFormatMachO()) return new DarwinARMTargetInfo(Triple); switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo(Triple); case llvm::Triple::Bitrig: return new BitrigTargetInfo(Triple); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple); case llvm::Triple::NaCl: return new NaClTargetInfo(Triple); case llvm::Triple::Win32: switch (Triple.getEnvironment()) { case llvm::Triple::Cygnus: return new CygwinARMTargetInfo(Triple); case llvm::Triple::GNU: return new MinGWARMTargetInfo(Triple); case llvm::Triple::Itanium: return new ItaniumWindowsARMleTargetInfo(Triple); case llvm::Triple::MSVC: default: // Assume MSVC for unknown environments return new MicrosoftARMleTargetInfo(Triple); } default: return new ARMleTargetInfo(Triple); } case llvm::Triple::armeb: case llvm::Triple::thumbeb: if (Triple.isOSDarwin()) return new DarwinARMTargetInfo(Triple); switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo(Triple); case llvm::Triple::Bitrig: return new BitrigTargetInfo(Triple); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple); case llvm::Triple::NaCl: return new NaClTargetInfo(Triple); default: return new ARMbeTargetInfo(Triple); } case llvm::Triple::bpfeb: case llvm::Triple::bpfel: return new BPFTargetInfo(Triple); case llvm::Triple::msp430: return new MSP430TargetInfo(Triple); case llvm::Triple::mips: switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple); default: return new Mips32EBTargetInfo(Triple); } case llvm::Triple::mipsel: switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple); case llvm::Triple::NaCl: return new NaClTargetInfo(Triple); default: return new Mips32ELTargetInfo(Triple); } case llvm::Triple::mips64: switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo(Triple); default: return new Mips64EBTargetInfo(Triple); } case llvm::Triple::mips64el: switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo(Triple); default: return new Mips64ELTargetInfo(Triple); } case llvm::Triple::le32: switch (os) { case llvm::Triple::NaCl: return new NaClTargetInfo(Triple); default: return nullptr; } case llvm::Triple::le64: return new Le64TargetInfo(Triple); case llvm::Triple::ppc: if (Triple.isOSDarwin()) return new DarwinPPC32TargetInfo(Triple); switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo(Triple); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple); default: return new PPC32TargetInfo(Triple); } case llvm::Triple::ppc64: if (Triple.isOSDarwin()) return new DarwinPPC64TargetInfo(Triple); switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple); case llvm::Triple::Lv2: return new PS3PPUTargetInfo(Triple); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple); default: return new PPC64TargetInfo(Triple); } case llvm::Triple::ppc64le: switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple); default: return new PPC64TargetInfo(Triple); } case llvm::Triple::nvptx: return new NVPTX32TargetInfo(Triple); case llvm::Triple::nvptx64: return new NVPTX64TargetInfo(Triple); case llvm::Triple::amdgcn: case llvm::Triple::r600: return new AMDGPUTargetInfo(Triple); case llvm::Triple::sparc: switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple); case llvm::Triple::Solaris: return new SolarisTargetInfo(Triple); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo(Triple); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple); default: return new SparcV8TargetInfo(Triple); } // The 'sparcel' architecture copies all the above cases except for Solaris. case llvm::Triple::sparcel: switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo(Triple); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple); default: return new SparcV8elTargetInfo(Triple); } case llvm::Triple::sparcv9: switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple); case llvm::Triple::Solaris: return new SolarisTargetInfo(Triple); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo(Triple); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple); default: return new SparcV9TargetInfo(Triple); } case llvm::Triple::systemz: switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple); default: return new SystemZTargetInfo(Triple); } case llvm::Triple::tce: return new TCETargetInfo(Triple); case llvm::Triple::x86: if (Triple.isOSDarwin()) return new DarwinI386TargetInfo(Triple); switch (os) { case llvm::Triple::CloudABI: return new CloudABITargetInfo(Triple); case llvm::Triple::Linux: { switch (Triple.getEnvironment()) { default: return new LinuxTargetInfo(Triple); case llvm::Triple::Android: return new AndroidX86_32TargetInfo(Triple); } } case llvm::Triple::DragonFly: return new DragonFlyBSDTargetInfo(Triple); case llvm::Triple::NetBSD: return new NetBSDI386TargetInfo(Triple); case llvm::Triple::OpenBSD: return new OpenBSDI386TargetInfo(Triple); case llvm::Triple::Bitrig: return new BitrigI386TargetInfo(Triple); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple); case llvm::Triple::KFreeBSD: return new KFreeBSDTargetInfo(Triple); case llvm::Triple::Minix: return new MinixTargetInfo(Triple); case llvm::Triple::Solaris: return new SolarisTargetInfo(Triple); case llvm::Triple::Win32: { switch (Triple.getEnvironment()) { case llvm::Triple::Cygnus: return new CygwinX86_32TargetInfo(Triple); case llvm::Triple::GNU: return new MinGWX86_32TargetInfo(Triple); case llvm::Triple::Itanium: case llvm::Triple::MSVC: default: // Assume MSVC for unknown environments return new MicrosoftX86_32TargetInfo(Triple); } } case llvm::Triple::Haiku: return new HaikuX86_32TargetInfo(Triple); case llvm::Triple::RTEMS: return new RTEMSX86_32TargetInfo(Triple); case llvm::Triple::NaCl: return new NaClTargetInfo(Triple); case llvm::Triple::ELFIAMCU: return new MCUX86_32TargetInfo(Triple); default: return new X86_32TargetInfo(Triple); } case llvm::Triple::x86_64: if (Triple.isOSDarwin() || Triple.isOSBinFormatMachO()) return new DarwinX86_64TargetInfo(Triple); switch (os) { case llvm::Triple::CloudABI: return new CloudABITargetInfo(Triple); case llvm::Triple::Linux: { switch (Triple.getEnvironment()) { default: return new LinuxTargetInfo(Triple); case llvm::Triple::Android: return new AndroidX86_64TargetInfo(Triple); } } case llvm::Triple::DragonFly: return new DragonFlyBSDTargetInfo(Triple); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple); case llvm::Triple::OpenBSD: return new OpenBSDX86_64TargetInfo(Triple); case llvm::Triple::Bitrig: return new BitrigX86_64TargetInfo(Triple); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple); case llvm::Triple::KFreeBSD: return new KFreeBSDTargetInfo(Triple); case llvm::Triple::Solaris: return new SolarisTargetInfo(Triple); case llvm::Triple::Win32: { switch (Triple.getEnvironment()) { case llvm::Triple::Cygnus: return new CygwinX86_64TargetInfo(Triple); case llvm::Triple::GNU: return new MinGWX86_64TargetInfo(Triple); case llvm::Triple::MSVC: default: // Assume MSVC for unknown environments return new MicrosoftX86_64TargetInfo(Triple); } } case llvm::Triple::NaCl: return new NaClTargetInfo(Triple); case llvm::Triple::PS4: return new PS4OSTargetInfo(Triple); default: return new X86_64TargetInfo(Triple); } case llvm::Triple::spir: { if (Triple.getOS() != llvm::Triple::UnknownOS || Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) return nullptr; return new SPIR32TargetInfo(Triple); } case llvm::Triple::spir64: { if (Triple.getOS() != llvm::Triple::UnknownOS || Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) return nullptr; return new SPIR64TargetInfo(Triple); } case llvm::Triple::wasm32: if (!(Triple == llvm::Triple("wasm32-unknown-unknown"))) return nullptr; return new WebAssemblyOSTargetInfo(Triple); case llvm::Triple::wasm64: if (!(Triple == llvm::Triple("wasm64-unknown-unknown"))) return nullptr; return new WebAssemblyOSTargetInfo(Triple); } } /// CreateTargetInfo - Return the target info object for the specified target /// options. TargetInfo * TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, const std::shared_ptr &Opts) { llvm::Triple Triple(Opts->Triple); // Construct the target std::unique_ptr Target(AllocateTarget(Triple)); if (!Target) { Diags.Report(diag::err_target_unknown_triple) << Triple.str(); return nullptr; } Target->TargetOpts = Opts; // Set the target CPU if specified. if (!Opts->CPU.empty() && !Target->setCPU(Opts->CPU)) { Diags.Report(diag::err_target_unknown_cpu) << Opts->CPU; return nullptr; } // Set the target ABI if specified. if (!Opts->ABI.empty() && !Target->setABI(Opts->ABI)) { Diags.Report(diag::err_target_unknown_abi) << Opts->ABI; return nullptr; } // Set the fp math unit. if (!Opts->FPMath.empty() && !Target->setFPMath(Opts->FPMath)) { Diags.Report(diag::err_target_unknown_fpmath) << Opts->FPMath; return nullptr; } // Compute the default target features, we need the target to handle this // because features may have dependencies on one another. llvm::StringMap Features; if (!Target->initFeatureMap(Features, Diags, Opts->CPU, Opts->FeaturesAsWritten)) return nullptr; // Add the features to the compile options. Opts->Features.clear(); for (const auto &F : Features) Opts->Features.push_back((F.getValue() ? "+" : "-") + F.getKey().str()); if (!Target->handleTargetFeatures(Opts->Features, Diags)) return nullptr; return Target.release(); } Index: projects/clang380-import/contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp =================================================================== --- projects/clang380-import/contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp (revision 295858) +++ projects/clang380-import/contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp (revision 295859) @@ -1,2653 +1,2626 @@ //===--- CGStmtOpenMP.cpp - Emit LLVM Code from Statements ----------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This contains code to emit OpenMP nodes as LLVM code. // //===----------------------------------------------------------------------===// #include "CGOpenMPRuntime.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "TargetInfo.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtOpenMP.h" using namespace clang; using namespace CodeGen; void CodeGenFunction::GenerateOpenMPCapturedVars( const CapturedStmt &S, SmallVectorImpl &CapturedVars) { const RecordDecl *RD = S.getCapturedRecordDecl(); auto CurField = RD->field_begin(); auto CurCap = S.captures().begin(); for (CapturedStmt::const_capture_init_iterator I = S.capture_init_begin(), E = S.capture_init_end(); I != E; ++I, ++CurField, ++CurCap) { if (CurField->hasCapturedVLAType()) { auto VAT = CurField->getCapturedVLAType(); auto *Val = VLASizeMap[VAT->getSizeExpr()]; CapturedVars.push_back(Val); } else if (CurCap->capturesThis()) CapturedVars.push_back(CXXThisValue); else if (CurCap->capturesVariableByCopy()) CapturedVars.push_back( EmitLoadOfLValue(EmitLValue(*I), SourceLocation()).getScalarVal()); else { assert(CurCap->capturesVariable() && "Expected capture by reference."); CapturedVars.push_back(EmitLValue(*I).getAddress().getPointer()); } } } static Address castValueFromUintptr(CodeGenFunction &CGF, QualType DstType, StringRef Name, LValue AddrLV, bool isReferenceType = false) { ASTContext &Ctx = CGF.getContext(); auto *CastedPtr = CGF.EmitScalarConversion( AddrLV.getAddress().getPointer(), Ctx.getUIntPtrType(), Ctx.getPointerType(DstType), SourceLocation()); auto TmpAddr = CGF.MakeNaturalAlignAddrLValue(CastedPtr, Ctx.getPointerType(DstType)) .getAddress(); // If we are dealing with references we need to return the address of the // reference instead of the reference of the value. if (isReferenceType) { QualType RefType = Ctx.getLValueReferenceType(DstType); auto *RefVal = TmpAddr.getPointer(); TmpAddr = CGF.CreateMemTemp(RefType, Twine(Name) + ".ref"); auto TmpLVal = CGF.MakeAddrLValue(TmpAddr, RefType); CGF.EmitScalarInit(RefVal, TmpLVal); } return TmpAddr; } llvm::Function * CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) { assert( CapturedStmtInfo && "CapturedStmtInfo should be set when generating the captured function"); const CapturedDecl *CD = S.getCapturedDecl(); const RecordDecl *RD = S.getCapturedRecordDecl(); assert(CD->hasBody() && "missing CapturedDecl body"); // Build the argument list. ASTContext &Ctx = CGM.getContext(); FunctionArgList Args; Args.append(CD->param_begin(), std::next(CD->param_begin(), CD->getContextParamPosition())); auto I = S.captures().begin(); for (auto *FD : RD->fields()) { QualType ArgType = FD->getType(); IdentifierInfo *II = nullptr; VarDecl *CapVar = nullptr; // If this is a capture by copy and the type is not a pointer, the outlined // function argument type should be uintptr and the value properly casted to // uintptr. This is necessary given that the runtime library is only able to // deal with pointers. We can pass in the same way the VLA type sizes to the // outlined function. if ((I->capturesVariableByCopy() && !ArgType->isAnyPointerType()) || I->capturesVariableArrayType()) ArgType = Ctx.getUIntPtrType(); if (I->capturesVariable() || I->capturesVariableByCopy()) { CapVar = I->getCapturedVar(); II = CapVar->getIdentifier(); } else if (I->capturesThis()) II = &getContext().Idents.get("this"); else { assert(I->capturesVariableArrayType()); II = &getContext().Idents.get("vla"); } if (ArgType->isVariablyModifiedType()) ArgType = getContext().getVariableArrayDecayedType(ArgType); Args.push_back(ImplicitParamDecl::Create(getContext(), nullptr, FD->getLocation(), II, ArgType)); ++I; } Args.append( std::next(CD->param_begin(), CD->getContextParamPosition() + 1), CD->param_end()); // Create the function declaration. FunctionType::ExtInfo ExtInfo; const CGFunctionInfo &FuncInfo = CGM.getTypes().arrangeFreeFunctionDeclaration(Ctx.VoidTy, Args, ExtInfo, /*IsVariadic=*/false); llvm::FunctionType *FuncLLVMTy = CGM.getTypes().GetFunctionType(FuncInfo); llvm::Function *F = llvm::Function::Create( FuncLLVMTy, llvm::GlobalValue::InternalLinkage, CapturedStmtInfo->getHelperName(), &CGM.getModule()); CGM.SetInternalFunctionAttributes(CD, F, FuncInfo); if (CD->isNothrow()) F->addFnAttr(llvm::Attribute::NoUnwind); // Generate the function. StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args, CD->getLocation(), CD->getBody()->getLocStart()); unsigned Cnt = CD->getContextParamPosition(); I = S.captures().begin(); for (auto *FD : RD->fields()) { // If we are capturing a pointer by copy we don't need to do anything, just // use the value that we get from the arguments. if (I->capturesVariableByCopy() && FD->getType()->isAnyPointerType()) { setAddrOfLocalVar(I->getCapturedVar(), GetAddrOfLocalVar(Args[Cnt])); ++Cnt, ++I; continue; } LValue ArgLVal = MakeAddrLValue(GetAddrOfLocalVar(Args[Cnt]), Args[Cnt]->getType(), AlignmentSource::Decl); if (FD->hasCapturedVLAType()) { LValue CastedArgLVal = MakeAddrLValue(castValueFromUintptr(*this, FD->getType(), Args[Cnt]->getName(), ArgLVal), FD->getType(), AlignmentSource::Decl); auto *ExprArg = EmitLoadOfLValue(CastedArgLVal, SourceLocation()).getScalarVal(); auto VAT = FD->getCapturedVLAType(); VLASizeMap[VAT->getSizeExpr()] = ExprArg; } else if (I->capturesVariable()) { auto *Var = I->getCapturedVar(); QualType VarTy = Var->getType(); Address ArgAddr = ArgLVal.getAddress(); if (!VarTy->isReferenceType()) { ArgAddr = EmitLoadOfReference( ArgAddr, ArgLVal.getType()->castAs()); } setAddrOfLocalVar( Var, Address(ArgAddr.getPointer(), getContext().getDeclAlign(Var))); } else if (I->capturesVariableByCopy()) { assert(!FD->getType()->isAnyPointerType() && "Not expecting a captured pointer."); auto *Var = I->getCapturedVar(); QualType VarTy = Var->getType(); setAddrOfLocalVar(I->getCapturedVar(), castValueFromUintptr(*this, FD->getType(), Args[Cnt]->getName(), ArgLVal, VarTy->isReferenceType())); } else { // If 'this' is captured, load it into CXXThisValue. assert(I->capturesThis()); CXXThisValue = EmitLoadOfLValue(ArgLVal, Args[Cnt]->getLocation()).getScalarVal(); } ++Cnt, ++I; } PGO.assignRegionCounters(GlobalDecl(CD), F); CapturedStmtInfo->EmitBody(*this, CD->getBody()); FinishFunction(CD->getBodyRBrace()); return F; } //===----------------------------------------------------------------------===// // OpenMP Directive Emission //===----------------------------------------------------------------------===// void CodeGenFunction::EmitOMPAggregateAssign( Address DestAddr, Address SrcAddr, QualType OriginalType, const llvm::function_ref &CopyGen) { // Perform element-by-element initialization. QualType ElementTy; // Drill down to the base element type on both arrays. auto ArrayTy = OriginalType->getAsArrayTypeUnsafe(); auto NumElements = emitArrayLength(ArrayTy, ElementTy, DestAddr); SrcAddr = Builder.CreateElementBitCast(SrcAddr, DestAddr.getElementType()); auto SrcBegin = SrcAddr.getPointer(); auto DestBegin = DestAddr.getPointer(); // Cast from pointer to array type to pointer to single element. auto DestEnd = Builder.CreateGEP(DestBegin, NumElements); // The basic structure here is a while-do loop. auto BodyBB = createBasicBlock("omp.arraycpy.body"); auto DoneBB = createBasicBlock("omp.arraycpy.done"); auto IsEmpty = Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arraycpy.isempty"); Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB); // Enter the loop body, making that address the current address. auto EntryBB = Builder.GetInsertBlock(); EmitBlock(BodyBB); CharUnits ElementSize = getContext().getTypeSizeInChars(ElementTy); llvm::PHINode *SrcElementPHI = Builder.CreatePHI(SrcBegin->getType(), 2, "omp.arraycpy.srcElementPast"); SrcElementPHI->addIncoming(SrcBegin, EntryBB); Address SrcElementCurrent = Address(SrcElementPHI, SrcAddr.getAlignment().alignmentOfArrayElement(ElementSize)); llvm::PHINode *DestElementPHI = Builder.CreatePHI(DestBegin->getType(), 2, "omp.arraycpy.destElementPast"); DestElementPHI->addIncoming(DestBegin, EntryBB); Address DestElementCurrent = Address(DestElementPHI, DestAddr.getAlignment().alignmentOfArrayElement(ElementSize)); // Emit copy. CopyGen(DestElementCurrent, SrcElementCurrent); // Shift the address forward by one element. auto DestElementNext = Builder.CreateConstGEP1_32( DestElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element"); auto SrcElementNext = Builder.CreateConstGEP1_32( SrcElementPHI, /*Idx0=*/1, "omp.arraycpy.src.element"); // Check whether we've reached the end. auto Done = Builder.CreateICmpEQ(DestElementNext, DestEnd, "omp.arraycpy.done"); Builder.CreateCondBr(Done, DoneBB, BodyBB); DestElementPHI->addIncoming(DestElementNext, Builder.GetInsertBlock()); SrcElementPHI->addIncoming(SrcElementNext, Builder.GetInsertBlock()); // Done. EmitBlock(DoneBB, /*IsFinished=*/true); } /// \brief Emit initialization of arrays of complex types. /// \param DestAddr Address of the array. /// \param Type Type of array. /// \param Init Initial expression of array. static void EmitOMPAggregateInit(CodeGenFunction &CGF, Address DestAddr, QualType Type, const Expr *Init) { // Perform element-by-element initialization. QualType ElementTy; // Drill down to the base element type on both arrays. auto ArrayTy = Type->getAsArrayTypeUnsafe(); auto NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, DestAddr); DestAddr = CGF.Builder.CreateElementBitCast(DestAddr, DestAddr.getElementType()); auto DestBegin = DestAddr.getPointer(); // Cast from pointer to array type to pointer to single element. auto DestEnd = CGF.Builder.CreateGEP(DestBegin, NumElements); // The basic structure here is a while-do loop. auto BodyBB = CGF.createBasicBlock("omp.arrayinit.body"); auto DoneBB = CGF.createBasicBlock("omp.arrayinit.done"); auto IsEmpty = CGF.Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arrayinit.isempty"); CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB); // Enter the loop body, making that address the current address. auto EntryBB = CGF.Builder.GetInsertBlock(); CGF.EmitBlock(BodyBB); CharUnits ElementSize = CGF.getContext().getTypeSizeInChars(ElementTy); llvm::PHINode *DestElementPHI = CGF.Builder.CreatePHI( DestBegin->getType(), 2, "omp.arraycpy.destElementPast"); DestElementPHI->addIncoming(DestBegin, EntryBB); Address DestElementCurrent = Address(DestElementPHI, DestAddr.getAlignment().alignmentOfArrayElement(ElementSize)); // Emit copy. { CodeGenFunction::RunCleanupsScope InitScope(CGF); CGF.EmitAnyExprToMem(Init, DestElementCurrent, ElementTy.getQualifiers(), /*IsInitializer=*/false); } // Shift the address forward by one element. auto DestElementNext = CGF.Builder.CreateConstGEP1_32( DestElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element"); // Check whether we've reached the end. auto Done = CGF.Builder.CreateICmpEQ(DestElementNext, DestEnd, "omp.arraycpy.done"); CGF.Builder.CreateCondBr(Done, DoneBB, BodyBB); DestElementPHI->addIncoming(DestElementNext, CGF.Builder.GetInsertBlock()); // Done. CGF.EmitBlock(DoneBB, /*IsFinished=*/true); } void CodeGenFunction::EmitOMPCopy(QualType OriginalType, Address DestAddr, Address SrcAddr, const VarDecl *DestVD, const VarDecl *SrcVD, const Expr *Copy) { if (OriginalType->isArrayType()) { auto *BO = dyn_cast(Copy); if (BO && BO->getOpcode() == BO_Assign) { // Perform simple memcpy for simple copying. EmitAggregateAssign(DestAddr, SrcAddr, OriginalType); } else { // For arrays with complex element types perform element by element // copying. EmitOMPAggregateAssign( DestAddr, SrcAddr, OriginalType, [this, Copy, SrcVD, DestVD](Address DestElement, Address SrcElement) { // Working with the single array element, so have to remap // destination and source variables to corresponding array // elements. CodeGenFunction::OMPPrivateScope Remap(*this); Remap.addPrivate(DestVD, [DestElement]() -> Address { return DestElement; }); Remap.addPrivate( SrcVD, [SrcElement]() -> Address { return SrcElement; }); (void)Remap.Privatize(); EmitIgnoredExpr(Copy); }); } } else { // Remap pseudo source variable to private copy. CodeGenFunction::OMPPrivateScope Remap(*this); Remap.addPrivate(SrcVD, [SrcAddr]() -> Address { return SrcAddr; }); Remap.addPrivate(DestVD, [DestAddr]() -> Address { return DestAddr; }); (void)Remap.Privatize(); // Emit copying of the whole variable. EmitIgnoredExpr(Copy); } } bool CodeGenFunction::EmitOMPFirstprivateClause(const OMPExecutableDirective &D, OMPPrivateScope &PrivateScope) { if (!HaveInsertPoint()) return false; llvm::DenseSet EmittedAsFirstprivate; for (const auto *C : D.getClausesOfKind()) { auto IRef = C->varlist_begin(); auto InitsRef = C->inits().begin(); for (auto IInit : C->private_copies()) { auto *OrigVD = cast(cast(*IRef)->getDecl()); if (EmittedAsFirstprivate.count(OrigVD) == 0) { EmittedAsFirstprivate.insert(OrigVD); auto *VD = cast(cast(IInit)->getDecl()); auto *VDInit = cast(cast(*InitsRef)->getDecl()); bool IsRegistered; DeclRefExpr DRE( const_cast(OrigVD), /*RefersToEnclosingVariableOrCapture=*/CapturedStmtInfo->lookup( OrigVD) != nullptr, (*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc()); Address OriginalAddr = EmitLValue(&DRE).getAddress(); QualType Type = OrigVD->getType(); if (Type->isArrayType()) { // Emit VarDecl with copy init for arrays. // Get the address of the original variable captured in current // captured region. IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> Address { auto Emission = EmitAutoVarAlloca(*VD); auto *Init = VD->getInit(); if (!isa(Init) || isTrivialInitializer(Init)) { // Perform simple memcpy. EmitAggregateAssign(Emission.getAllocatedAddress(), OriginalAddr, Type); } else { EmitOMPAggregateAssign( Emission.getAllocatedAddress(), OriginalAddr, Type, [this, VDInit, Init](Address DestElement, Address SrcElement) { // Clean up any temporaries needed by the initialization. RunCleanupsScope InitScope(*this); // Emit initialization for single element. setAddrOfLocalVar(VDInit, SrcElement); EmitAnyExprToMem(Init, DestElement, Init->getType().getQualifiers(), /*IsInitializer*/ false); LocalDeclMap.erase(VDInit); }); } EmitAutoVarCleanups(Emission); return Emission.getAllocatedAddress(); }); } else { IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> Address { // Emit private VarDecl with copy init. // Remap temp VDInit variable to the address of the original // variable // (for proper handling of captured global variables). setAddrOfLocalVar(VDInit, OriginalAddr); EmitDecl(*VD); LocalDeclMap.erase(VDInit); return GetAddrOfLocalVar(VD); }); } assert(IsRegistered && "firstprivate var already registered as private"); // Silence the warning about unused variable. (void)IsRegistered; } ++IRef, ++InitsRef; } } return !EmittedAsFirstprivate.empty(); } void CodeGenFunction::EmitOMPPrivateClause( const OMPExecutableDirective &D, CodeGenFunction::OMPPrivateScope &PrivateScope) { if (!HaveInsertPoint()) return; llvm::DenseSet EmittedAsPrivate; for (const auto *C : D.getClausesOfKind()) { auto IRef = C->varlist_begin(); for (auto IInit : C->private_copies()) { auto *OrigVD = cast(cast(*IRef)->getDecl()); if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) { auto VD = cast(cast(IInit)->getDecl()); bool IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> Address { // Emit private VarDecl with copy init. EmitDecl(*VD); return GetAddrOfLocalVar(VD); }); assert(IsRegistered && "private var already registered as private"); // Silence the warning about unused variable. (void)IsRegistered; } ++IRef; } } } bool CodeGenFunction::EmitOMPCopyinClause(const OMPExecutableDirective &D) { if (!HaveInsertPoint()) return false; // threadprivate_var1 = master_threadprivate_var1; // operator=(threadprivate_var2, master_threadprivate_var2); // ... // __kmpc_barrier(&loc, global_tid); llvm::DenseSet CopiedVars; llvm::BasicBlock *CopyBegin = nullptr, *CopyEnd = nullptr; for (const auto *C : D.getClausesOfKind()) { auto IRef = C->varlist_begin(); auto ISrcRef = C->source_exprs().begin(); auto IDestRef = C->destination_exprs().begin(); for (auto *AssignOp : C->assignment_ops()) { auto *VD = cast(cast(*IRef)->getDecl()); QualType Type = VD->getType(); if (CopiedVars.insert(VD->getCanonicalDecl()).second) { // Get the address of the master variable. If we are emitting code with // TLS support, the address is passed from the master as field in the // captured declaration. Address MasterAddr = Address::invalid(); if (getLangOpts().OpenMPUseTLS && getContext().getTargetInfo().isTLSSupported()) { assert(CapturedStmtInfo->lookup(VD) && "Copyin threadprivates should have been captured!"); DeclRefExpr DRE(const_cast(VD), true, (*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc()); MasterAddr = EmitLValue(&DRE).getAddress(); LocalDeclMap.erase(VD); } else { MasterAddr = Address(VD->isStaticLocal() ? CGM.getStaticLocalDeclAddress(VD) : CGM.GetAddrOfGlobal(VD), getContext().getDeclAlign(VD)); } // Get the address of the threadprivate variable. Address PrivateAddr = EmitLValue(*IRef).getAddress(); if (CopiedVars.size() == 1) { // At first check if current thread is a master thread. If it is, no // need to copy data. CopyBegin = createBasicBlock("copyin.not.master"); CopyEnd = createBasicBlock("copyin.not.master.end"); Builder.CreateCondBr( Builder.CreateICmpNE( Builder.CreatePtrToInt(MasterAddr.getPointer(), CGM.IntPtrTy), Builder.CreatePtrToInt(PrivateAddr.getPointer(), CGM.IntPtrTy)), CopyBegin, CopyEnd); EmitBlock(CopyBegin); } auto *SrcVD = cast(cast(*ISrcRef)->getDecl()); auto *DestVD = cast(cast(*IDestRef)->getDecl()); EmitOMPCopy(Type, PrivateAddr, MasterAddr, DestVD, SrcVD, AssignOp); } ++IRef; ++ISrcRef; ++IDestRef; } } if (CopyEnd) { // Exit out of copying procedure for non-master thread. EmitBlock(CopyEnd, /*IsFinished=*/true); return true; } return false; } bool CodeGenFunction::EmitOMPLastprivateClauseInit( const OMPExecutableDirective &D, OMPPrivateScope &PrivateScope) { if (!HaveInsertPoint()) return false; bool HasAtLeastOneLastprivate = false; llvm::DenseSet AlreadyEmittedVars; for (const auto *C : D.getClausesOfKind()) { HasAtLeastOneLastprivate = true; auto IRef = C->varlist_begin(); auto IDestRef = C->destination_exprs().begin(); for (auto *IInit : C->private_copies()) { // Keep the address of the original variable for future update at the end // of the loop. auto *OrigVD = cast(cast(*IRef)->getDecl()); if (AlreadyEmittedVars.insert(OrigVD->getCanonicalDecl()).second) { auto *DestVD = cast(cast(*IDestRef)->getDecl()); PrivateScope.addPrivate(DestVD, [this, OrigVD, IRef]() -> Address { DeclRefExpr DRE( const_cast(OrigVD), /*RefersToEnclosingVariableOrCapture=*/CapturedStmtInfo->lookup( OrigVD) != nullptr, (*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc()); return EmitLValue(&DRE).getAddress(); }); // Check if the variable is also a firstprivate: in this case IInit is // not generated. Initialization of this variable will happen in codegen // for 'firstprivate' clause. if (IInit) { auto *VD = cast(cast(IInit)->getDecl()); bool IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> Address { // Emit private VarDecl with copy init. EmitDecl(*VD); return GetAddrOfLocalVar(VD); }); assert(IsRegistered && "lastprivate var already registered as private"); (void)IsRegistered; } } ++IRef, ++IDestRef; } } return HasAtLeastOneLastprivate; } void CodeGenFunction::EmitOMPLastprivateClauseFinal( const OMPExecutableDirective &D, llvm::Value *IsLastIterCond) { if (!HaveInsertPoint()) return; // Emit following code: // if () { // orig_var1 = private_orig_var1; // ... // orig_varn = private_orig_varn; // } llvm::BasicBlock *ThenBB = nullptr; llvm::BasicBlock *DoneBB = nullptr; if (IsLastIterCond) { ThenBB = createBasicBlock(".omp.lastprivate.then"); DoneBB = createBasicBlock(".omp.lastprivate.done"); Builder.CreateCondBr(IsLastIterCond, ThenBB, DoneBB); EmitBlock(ThenBB); } llvm::DenseMap LoopCountersAndUpdates; - const Expr *LastIterVal = nullptr; - const Expr *IVExpr = nullptr; - const Expr *IncExpr = nullptr; if (auto *LoopDirective = dyn_cast(&D)) { - if (isOpenMPWorksharingDirective(D.getDirectiveKind())) { - LastIterVal = cast(cast( - LoopDirective->getUpperBoundVariable()) - ->getDecl()) - ->getAnyInitializer(); - IVExpr = LoopDirective->getIterationVariable(); - IncExpr = LoopDirective->getInc(); - auto IUpdate = LoopDirective->updates().begin(); - for (auto *E : LoopDirective->counters()) { - auto *D = cast(E)->getDecl()->getCanonicalDecl(); - LoopCountersAndUpdates[D] = *IUpdate; - ++IUpdate; - } + auto IC = LoopDirective->counters().begin(); + for (auto F : LoopDirective->finals()) { + auto *D = cast(*IC)->getDecl()->getCanonicalDecl(); + LoopCountersAndUpdates[D] = F; + ++IC; } } - { - llvm::DenseSet AlreadyEmittedVars; - bool FirstLCV = true; - for (const auto *C : D.getClausesOfKind()) { - auto IRef = C->varlist_begin(); - auto ISrcRef = C->source_exprs().begin(); - auto IDestRef = C->destination_exprs().begin(); - for (auto *AssignOp : C->assignment_ops()) { - auto *PrivateVD = cast(cast(*IRef)->getDecl()); - QualType Type = PrivateVD->getType(); - auto *CanonicalVD = PrivateVD->getCanonicalDecl(); - if (AlreadyEmittedVars.insert(CanonicalVD).second) { - // If lastprivate variable is a loop control variable for loop-based - // directive, update its value before copyin back to original - // variable. - if (auto *UpExpr = LoopCountersAndUpdates.lookup(CanonicalVD)) { - if (FirstLCV && LastIterVal) { - EmitAnyExprToMem(LastIterVal, EmitLValue(IVExpr).getAddress(), - IVExpr->getType().getQualifiers(), - /*IsInitializer=*/false); - EmitIgnoredExpr(IncExpr); - FirstLCV = false; - } - EmitIgnoredExpr(UpExpr); - } - auto *SrcVD = cast(cast(*ISrcRef)->getDecl()); - auto *DestVD = cast(cast(*IDestRef)->getDecl()); - // Get the address of the original variable. - Address OriginalAddr = GetAddrOfLocalVar(DestVD); - // Get the address of the private variable. - Address PrivateAddr = GetAddrOfLocalVar(PrivateVD); - if (auto RefTy = PrivateVD->getType()->getAs()) - PrivateAddr = + llvm::DenseSet AlreadyEmittedVars; + for (const auto *C : D.getClausesOfKind()) { + auto IRef = C->varlist_begin(); + auto ISrcRef = C->source_exprs().begin(); + auto IDestRef = C->destination_exprs().begin(); + for (auto *AssignOp : C->assignment_ops()) { + auto *PrivateVD = cast(cast(*IRef)->getDecl()); + QualType Type = PrivateVD->getType(); + auto *CanonicalVD = PrivateVD->getCanonicalDecl(); + if (AlreadyEmittedVars.insert(CanonicalVD).second) { + // If lastprivate variable is a loop control variable for loop-based + // directive, update its value before copyin back to original + // variable. + if (auto *UpExpr = LoopCountersAndUpdates.lookup(CanonicalVD)) + EmitIgnoredExpr(UpExpr); + auto *SrcVD = cast(cast(*ISrcRef)->getDecl()); + auto *DestVD = cast(cast(*IDestRef)->getDecl()); + // Get the address of the original variable. + Address OriginalAddr = GetAddrOfLocalVar(DestVD); + // Get the address of the private variable. + Address PrivateAddr = GetAddrOfLocalVar(PrivateVD); + if (auto RefTy = PrivateVD->getType()->getAs()) + PrivateAddr = Address(Builder.CreateLoad(PrivateAddr), getNaturalTypeAlignment(RefTy->getPointeeType())); - EmitOMPCopy(Type, OriginalAddr, PrivateAddr, DestVD, SrcVD, AssignOp); - } - ++IRef; - ++ISrcRef; - ++IDestRef; + EmitOMPCopy(Type, OriginalAddr, PrivateAddr, DestVD, SrcVD, AssignOp); } + ++IRef; + ++ISrcRef; + ++IDestRef; } } - if (IsLastIterCond) { + if (IsLastIterCond) EmitBlock(DoneBB, /*IsFinished=*/true); - } } void CodeGenFunction::EmitOMPReductionClauseInit( const OMPExecutableDirective &D, CodeGenFunction::OMPPrivateScope &PrivateScope) { if (!HaveInsertPoint()) return; for (const auto *C : D.getClausesOfKind()) { auto ILHS = C->lhs_exprs().begin(); auto IRHS = C->rhs_exprs().begin(); auto IPriv = C->privates().begin(); for (auto IRef : C->varlists()) { auto *LHSVD = cast(cast(*ILHS)->getDecl()); auto *RHSVD = cast(cast(*IRHS)->getDecl()); auto *PrivateVD = cast(cast(*IPriv)->getDecl()); if (auto *OASE = dyn_cast(IRef)) { auto *Base = OASE->getBase()->IgnoreParenImpCasts(); while (auto *TempOASE = dyn_cast(Base)) Base = TempOASE->getBase()->IgnoreParenImpCasts(); while (auto *TempASE = dyn_cast(Base)) Base = TempASE->getBase()->IgnoreParenImpCasts(); auto *DE = cast(Base); auto *OrigVD = cast(DE->getDecl()); auto OASELValueLB = EmitOMPArraySectionExpr(OASE); auto OASELValueUB = EmitOMPArraySectionExpr(OASE, /*IsLowerBound=*/false); auto OriginalBaseLValue = EmitLValue(DE); auto BaseLValue = OriginalBaseLValue; auto *Zero = Builder.getInt64(/*C=*/0); llvm::SmallVector Indexes; Indexes.push_back(Zero); auto *ItemTy = OASELValueLB.getPointer()->getType()->getPointerElementType(); auto *Ty = BaseLValue.getPointer()->getType()->getPointerElementType(); while (Ty != ItemTy) { Indexes.push_back(Zero); Ty = Ty->getPointerElementType(); } BaseLValue = MakeAddrLValue( Address(Builder.CreateInBoundsGEP(BaseLValue.getPointer(), Indexes), OASELValueLB.getAlignment()), OASELValueLB.getType(), OASELValueLB.getAlignmentSource()); // Store the address of the original variable associated with the LHS // implicit variable. PrivateScope.addPrivate(LHSVD, [this, OASELValueLB]() -> Address { return OASELValueLB.getAddress(); }); // Emit reduction copy. bool IsRegistered = PrivateScope.addPrivate( OrigVD, [this, PrivateVD, BaseLValue, OASELValueLB, OASELValueUB, OriginalBaseLValue]() -> Address { // Emit VarDecl with copy init for arrays. // Get the address of the original variable captured in current // captured region. auto *Size = Builder.CreatePtrDiff(OASELValueUB.getPointer(), OASELValueLB.getPointer()); Size = Builder.CreateNUWAdd( Size, llvm::ConstantInt::get(Size->getType(), /*V=*/1)); CodeGenFunction::OpaqueValueMapping OpaqueMap( *this, cast( getContext() .getAsVariableArrayType(PrivateVD->getType()) ->getSizeExpr()), RValue::get(Size)); EmitVariablyModifiedType(PrivateVD->getType()); auto Emission = EmitAutoVarAlloca(*PrivateVD); auto Addr = Emission.getAllocatedAddress(); auto *Init = PrivateVD->getInit(); EmitOMPAggregateInit(*this, Addr, PrivateVD->getType(), Init); EmitAutoVarCleanups(Emission); // Emit private VarDecl with reduction init. auto *Offset = Builder.CreatePtrDiff(BaseLValue.getPointer(), OASELValueLB.getPointer()); auto *Ptr = Builder.CreateGEP(Addr.getPointer(), Offset); Ptr = Builder.CreatePointerBitCastOrAddrSpaceCast( Ptr, OriginalBaseLValue.getPointer()->getType()); return Address(Ptr, OriginalBaseLValue.getAlignment()); }); assert(IsRegistered && "private var already registered as private"); // Silence the warning about unused variable. (void)IsRegistered; PrivateScope.addPrivate(RHSVD, [this, PrivateVD]() -> Address { return GetAddrOfLocalVar(PrivateVD); }); } else if (auto *ASE = dyn_cast(IRef)) { auto *Base = ASE->getBase()->IgnoreParenImpCasts(); while (auto *TempASE = dyn_cast(Base)) Base = TempASE->getBase()->IgnoreParenImpCasts(); auto *DE = cast(Base); auto *OrigVD = cast(DE->getDecl()); auto ASELValue = EmitLValue(ASE); auto OriginalBaseLValue = EmitLValue(DE); auto BaseLValue = OriginalBaseLValue; auto *Zero = Builder.getInt64(/*C=*/0); llvm::SmallVector Indexes; Indexes.push_back(Zero); auto *ItemTy = ASELValue.getPointer()->getType()->getPointerElementType(); auto *Ty = BaseLValue.getPointer()->getType()->getPointerElementType(); while (Ty != ItemTy) { Indexes.push_back(Zero); Ty = Ty->getPointerElementType(); } BaseLValue = MakeAddrLValue( Address(Builder.CreateInBoundsGEP(BaseLValue.getPointer(), Indexes), ASELValue.getAlignment()), ASELValue.getType(), ASELValue.getAlignmentSource()); // Store the address of the original variable associated with the LHS // implicit variable. PrivateScope.addPrivate(LHSVD, [this, ASELValue]() -> Address { return ASELValue.getAddress(); }); // Emit reduction copy. bool IsRegistered = PrivateScope.addPrivate( OrigVD, [this, PrivateVD, BaseLValue, ASELValue, OriginalBaseLValue]() -> Address { // Emit private VarDecl with reduction init. EmitDecl(*PrivateVD); auto Addr = GetAddrOfLocalVar(PrivateVD); auto *Offset = Builder.CreatePtrDiff(BaseLValue.getPointer(), ASELValue.getPointer()); auto *Ptr = Builder.CreateGEP(Addr.getPointer(), Offset); Ptr = Builder.CreatePointerBitCastOrAddrSpaceCast( Ptr, OriginalBaseLValue.getPointer()->getType()); return Address(Ptr, OriginalBaseLValue.getAlignment()); }); assert(IsRegistered && "private var already registered as private"); // Silence the warning about unused variable. (void)IsRegistered; PrivateScope.addPrivate(RHSVD, [this, PrivateVD]() -> Address { return GetAddrOfLocalVar(PrivateVD); }); } else { auto *OrigVD = cast(cast(IRef)->getDecl()); // Store the address of the original variable associated with the LHS // implicit variable. PrivateScope.addPrivate(LHSVD, [this, OrigVD, IRef]() -> Address { DeclRefExpr DRE(const_cast(OrigVD), CapturedStmtInfo->lookup(OrigVD) != nullptr, IRef->getType(), VK_LValue, IRef->getExprLoc()); return EmitLValue(&DRE).getAddress(); }); // Emit reduction copy. bool IsRegistered = PrivateScope.addPrivate(OrigVD, [this, PrivateVD]() -> Address { // Emit private VarDecl with reduction init. EmitDecl(*PrivateVD); return GetAddrOfLocalVar(PrivateVD); }); assert(IsRegistered && "private var already registered as private"); // Silence the warning about unused variable. (void)IsRegistered; PrivateScope.addPrivate(RHSVD, [this, PrivateVD]() -> Address { return GetAddrOfLocalVar(PrivateVD); }); } ++ILHS, ++IRHS, ++IPriv; } } } void CodeGenFunction::EmitOMPReductionClauseFinal( const OMPExecutableDirective &D) { if (!HaveInsertPoint()) return; llvm::SmallVector Privates; llvm::SmallVector LHSExprs; llvm::SmallVector RHSExprs; llvm::SmallVector ReductionOps; bool HasAtLeastOneReduction = false; for (const auto *C : D.getClausesOfKind()) { HasAtLeastOneReduction = true; Privates.append(C->privates().begin(), C->privates().end()); LHSExprs.append(C->lhs_exprs().begin(), C->lhs_exprs().end()); RHSExprs.append(C->rhs_exprs().begin(), C->rhs_exprs().end()); ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end()); } if (HasAtLeastOneReduction) { // Emit nowait reduction if nowait clause is present or directive is a // parallel directive (it always has implicit barrier). CGM.getOpenMPRuntime().emitReduction( *this, D.getLocEnd(), Privates, LHSExprs, RHSExprs, ReductionOps, D.getSingleClause() || isOpenMPParallelDirective(D.getDirectiveKind()) || D.getDirectiveKind() == OMPD_simd, D.getDirectiveKind() == OMPD_simd); } } static void emitCommonOMPParallelDirective(CodeGenFunction &CGF, const OMPExecutableDirective &S, OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) { auto CS = cast(S.getAssociatedStmt()); llvm::SmallVector CapturedVars; CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars); auto OutlinedFn = CGF.CGM.getOpenMPRuntime().emitParallelOutlinedFunction( S, *CS->getCapturedDecl()->param_begin(), InnermostKind, CodeGen); if (const auto *NumThreadsClause = S.getSingleClause()) { CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF); auto NumThreads = CGF.EmitScalarExpr(NumThreadsClause->getNumThreads(), /*IgnoreResultAssign*/ true); CGF.CGM.getOpenMPRuntime().emitNumThreadsClause( CGF, NumThreads, NumThreadsClause->getLocStart()); } if (const auto *ProcBindClause = S.getSingleClause()) { CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF); CGF.CGM.getOpenMPRuntime().emitProcBindClause( CGF, ProcBindClause->getProcBindKind(), ProcBindClause->getLocStart()); } const Expr *IfCond = nullptr; for (const auto *C : S.getClausesOfKind()) { if (C->getNameModifier() == OMPD_unknown || C->getNameModifier() == OMPD_parallel) { IfCond = C->getCondition(); break; } } CGF.CGM.getOpenMPRuntime().emitParallelCall(CGF, S.getLocStart(), OutlinedFn, CapturedVars, IfCond); } void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { LexicalScope Scope(*this, S.getSourceRange()); // Emit parallel region as a standalone region. auto &&CodeGen = [&S](CodeGenFunction &CGF) { OMPPrivateScope PrivateScope(CGF); bool Copyins = CGF.EmitOMPCopyinClause(S); bool Firstprivates = CGF.EmitOMPFirstprivateClause(S, PrivateScope); if (Copyins || Firstprivates) { // Emit implicit barrier to synchronize threads and avoid data races on // initialization of firstprivate variables or propagation master's thread // values of threadprivate variables to local instances of that variables // of all other implicit threads. CGF.CGM.getOpenMPRuntime().emitBarrierCall( CGF, S.getLocStart(), OMPD_unknown, /*EmitChecks=*/false, /*ForceSimpleCall=*/true); } CGF.EmitOMPPrivateClause(S, PrivateScope); CGF.EmitOMPReductionClauseInit(S, PrivateScope); (void)PrivateScope.Privatize(); CGF.EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); CGF.EmitOMPReductionClauseFinal(S); }; emitCommonOMPParallelDirective(*this, S, OMPD_parallel, CodeGen); } void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D, JumpDest LoopExit) { RunCleanupsScope BodyScope(*this); // Update counters values on current iteration. for (auto I : D.updates()) { EmitIgnoredExpr(I); } // Update the linear variables. for (const auto *C : D.getClausesOfKind()) { for (auto U : C->updates()) { EmitIgnoredExpr(U); } } // On a continue in the body, jump to the end. auto Continue = getJumpDestInCurrentScope("omp.body.continue"); BreakContinueStack.push_back(BreakContinue(LoopExit, Continue)); // Emit loop body. EmitStmt(D.getBody()); // The end (updates/cleanups). EmitBlock(Continue.getBlock()); BreakContinueStack.pop_back(); - // TODO: Update lastprivates if the SeparateIter flag is true. - // This will be implemented in a follow-up OMPLastprivateClause patch, but - // result should be still correct without it, as we do not make these - // variables private yet. } void CodeGenFunction::EmitOMPInnerLoop( const Stmt &S, bool RequiresCleanup, const Expr *LoopCond, const Expr *IncExpr, const llvm::function_ref &BodyGen, const llvm::function_ref &PostIncGen) { auto LoopExit = getJumpDestInCurrentScope("omp.inner.for.end"); // Start the loop with a block that tests the condition. auto CondBlock = createBasicBlock("omp.inner.for.cond"); EmitBlock(CondBlock); LoopStack.push(CondBlock); // If there are any cleanups between here and the loop-exit scope, // create a block to stage a loop exit along. auto ExitBlock = LoopExit.getBlock(); if (RequiresCleanup) ExitBlock = createBasicBlock("omp.inner.for.cond.cleanup"); auto LoopBody = createBasicBlock("omp.inner.for.body"); // Emit condition. EmitBranchOnBoolExpr(LoopCond, LoopBody, ExitBlock, getProfileCount(&S)); if (ExitBlock != LoopExit.getBlock()) { EmitBlock(ExitBlock); EmitBranchThroughCleanup(LoopExit); } EmitBlock(LoopBody); incrementProfileCounter(&S); // Create a block for the increment. auto Continue = getJumpDestInCurrentScope("omp.inner.for.inc"); BreakContinueStack.push_back(BreakContinue(LoopExit, Continue)); BodyGen(*this); // Emit "IV = IV + 1" and a back-edge to the condition block. EmitBlock(Continue.getBlock()); EmitIgnoredExpr(IncExpr); PostIncGen(*this); BreakContinueStack.pop_back(); EmitBranch(CondBlock); LoopStack.pop(); // Emit the fall-through block. EmitBlock(LoopExit.getBlock()); } void CodeGenFunction::EmitOMPLinearClauseInit(const OMPLoopDirective &D) { if (!HaveInsertPoint()) return; // Emit inits for the linear variables. for (const auto *C : D.getClausesOfKind()) { for (auto Init : C->inits()) { auto *VD = cast(cast(Init)->getDecl()); auto *OrigVD = cast( cast(VD->getInit()->IgnoreImpCasts())->getDecl()); DeclRefExpr DRE(const_cast(OrigVD), CapturedStmtInfo->lookup(OrigVD) != nullptr, VD->getInit()->getType(), VK_LValue, VD->getInit()->getExprLoc()); AutoVarEmission Emission = EmitAutoVarAlloca(*VD); EmitExprAsInit(&DRE, VD, MakeAddrLValue(Emission.getAllocatedAddress(), VD->getType()), /*capturedByInit=*/false); EmitAutoVarCleanups(Emission); } // Emit the linear steps for the linear clauses. // If a step is not constant, it is pre-calculated before the loop. if (auto CS = cast_or_null(C->getCalcStep())) if (auto SaveRef = cast(CS->getLHS())) { EmitVarDecl(*cast(SaveRef->getDecl())); // Emit calculation of the linear step. EmitIgnoredExpr(CS); } } } static void emitLinearClauseFinal(CodeGenFunction &CGF, const OMPLoopDirective &D) { if (!CGF.HaveInsertPoint()) return; // Emit the final values of the linear variables. for (const auto *C : D.getClausesOfKind()) { auto IC = C->varlist_begin(); for (auto F : C->finals()) { auto *OrigVD = cast(cast(*IC)->getDecl()); DeclRefExpr DRE(const_cast(OrigVD), CGF.CapturedStmtInfo->lookup(OrigVD) != nullptr, (*IC)->getType(), VK_LValue, (*IC)->getExprLoc()); Address OrigAddr = CGF.EmitLValue(&DRE).getAddress(); CodeGenFunction::OMPPrivateScope VarScope(CGF); VarScope.addPrivate(OrigVD, [OrigAddr]() -> Address { return OrigAddr; }); (void)VarScope.Privatize(); CGF.EmitIgnoredExpr(F); ++IC; } } } static void emitAlignedClause(CodeGenFunction &CGF, const OMPExecutableDirective &D) { if (!CGF.HaveInsertPoint()) return; for (const auto *Clause : D.getClausesOfKind()) { unsigned ClauseAlignment = 0; if (auto AlignmentExpr = Clause->getAlignment()) { auto AlignmentCI = cast(CGF.EmitScalarExpr(AlignmentExpr)); ClauseAlignment = static_cast(AlignmentCI->getZExtValue()); } for (auto E : Clause->varlists()) { unsigned Alignment = ClauseAlignment; if (Alignment == 0) { // OpenMP [2.8.1, Description] // If no optional parameter is specified, implementation-defined default // alignments for SIMD instructions on the target platforms are assumed. Alignment = CGF.getContext() .toCharUnitsFromBits(CGF.getContext().getOpenMPDefaultSimdAlign( E->getType()->getPointeeType())) .getQuantity(); } assert((Alignment == 0 || llvm::isPowerOf2_32(Alignment)) && "alignment is not power of 2"); if (Alignment != 0) { llvm::Value *PtrValue = CGF.EmitScalarExpr(E); CGF.EmitAlignmentAssumption(PtrValue, Alignment); } } } } static void emitPrivateLoopCounters(CodeGenFunction &CGF, CodeGenFunction::OMPPrivateScope &LoopScope, ArrayRef Counters, ArrayRef PrivateCounters) { if (!CGF.HaveInsertPoint()) return; auto I = PrivateCounters.begin(); for (auto *E : Counters) { auto *VD = cast(cast(E)->getDecl()); auto *PrivateVD = cast(cast(*I)->getDecl()); Address Addr = Address::invalid(); (void)LoopScope.addPrivate(PrivateVD, [&]() -> Address { // Emit var without initialization. auto VarEmission = CGF.EmitAutoVarAlloca(*PrivateVD); CGF.EmitAutoVarCleanups(VarEmission); Addr = VarEmission.getAllocatedAddress(); return Addr; }); (void)LoopScope.addPrivate(VD, [&]() -> Address { return Addr; }); ++I; } } static void emitPreCond(CodeGenFunction &CGF, const OMPLoopDirective &S, const Expr *Cond, llvm::BasicBlock *TrueBlock, llvm::BasicBlock *FalseBlock, uint64_t TrueCount) { if (!CGF.HaveInsertPoint()) return; { CodeGenFunction::OMPPrivateScope PreCondScope(CGF); emitPrivateLoopCounters(CGF, PreCondScope, S.counters(), S.private_counters()); (void)PreCondScope.Privatize(); // Get initial values of real counters. for (auto I : S.inits()) { CGF.EmitIgnoredExpr(I); } } // Check that loop is executed at least one time. CGF.EmitBranchOnBoolExpr(Cond, TrueBlock, FalseBlock, TrueCount); } static void emitPrivateLinearVars(CodeGenFunction &CGF, const OMPExecutableDirective &D, CodeGenFunction::OMPPrivateScope &PrivateScope) { if (!CGF.HaveInsertPoint()) return; for (const auto *C : D.getClausesOfKind()) { auto CurPrivate = C->privates().begin(); for (auto *E : C->varlists()) { auto *VD = cast(cast(E)->getDecl()); auto *PrivateVD = cast(cast(*CurPrivate)->getDecl()); bool IsRegistered = PrivateScope.addPrivate(VD, [&]() -> Address { // Emit private VarDecl with copy init. CGF.EmitVarDecl(*PrivateVD); return CGF.GetAddrOfLocalVar(PrivateVD); }); assert(IsRegistered && "linear var already registered as private"); // Silence the warning about unused variable. (void)IsRegistered; ++CurPrivate; } } } static void emitSimdlenSafelenClause(CodeGenFunction &CGF, const OMPExecutableDirective &D, bool IsMonotonic) { if (!CGF.HaveInsertPoint()) return; if (const auto *C = D.getSingleClause()) { RValue Len = CGF.EmitAnyExpr(C->getSimdlen(), AggValueSlot::ignored(), /*ignoreResult=*/true); llvm::ConstantInt *Val = cast(Len.getScalarVal()); CGF.LoopStack.setVectorizeWidth(Val->getZExtValue()); // In presence of finite 'safelen', it may be unsafe to mark all // the memory instructions parallel, because loop-carried // dependences of 'safelen' iterations are possible. if (!IsMonotonic) CGF.LoopStack.setParallel(!D.getSingleClause()); } else if (const auto *C = D.getSingleClause()) { RValue Len = CGF.EmitAnyExpr(C->getSafelen(), AggValueSlot::ignored(), /*ignoreResult=*/true); llvm::ConstantInt *Val = cast(Len.getScalarVal()); CGF.LoopStack.setVectorizeWidth(Val->getZExtValue()); // In presence of finite 'safelen', it may be unsafe to mark all // the memory instructions parallel, because loop-carried // dependences of 'safelen' iterations are possible. CGF.LoopStack.setParallel(false); } } void CodeGenFunction::EmitOMPSimdInit(const OMPLoopDirective &D, bool IsMonotonic) { // Walk clauses and process safelen/lastprivate. LoopStack.setParallel(!IsMonotonic); LoopStack.setVectorizeEnable(true); emitSimdlenSafelenClause(*this, D, IsMonotonic); } void CodeGenFunction::EmitOMPSimdFinal(const OMPLoopDirective &D) { if (!HaveInsertPoint()) return; auto IC = D.counters().begin(); for (auto F : D.finals()) { auto *OrigVD = cast(cast((*IC))->getDecl()); if (LocalDeclMap.count(OrigVD) || CapturedStmtInfo->lookup(OrigVD)) { DeclRefExpr DRE(const_cast(OrigVD), CapturedStmtInfo->lookup(OrigVD) != nullptr, (*IC)->getType(), VK_LValue, (*IC)->getExprLoc()); Address OrigAddr = EmitLValue(&DRE).getAddress(); OMPPrivateScope VarScope(*this); VarScope.addPrivate(OrigVD, [OrigAddr]() -> Address { return OrigAddr; }); (void)VarScope.Privatize(); EmitIgnoredExpr(F); } ++IC; } emitLinearClauseFinal(*this, D); } void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) { auto &&CodeGen = [&S](CodeGenFunction &CGF) { // if (PreCond) { // for (IV in 0..LastIteration) BODY; // ; // } // // Emit: if (PreCond) - begin. // If the condition constant folds and can be elided, avoid emitting the // whole loop. bool CondConstant; llvm::BasicBlock *ContBlock = nullptr; if (CGF.ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) { if (!CondConstant) return; } else { auto *ThenBlock = CGF.createBasicBlock("simd.if.then"); ContBlock = CGF.createBasicBlock("simd.if.end"); emitPreCond(CGF, S, S.getPreCond(), ThenBlock, ContBlock, CGF.getProfileCount(&S)); CGF.EmitBlock(ThenBlock); CGF.incrementProfileCounter(&S); } // Emit the loop iteration variable. const Expr *IVExpr = S.getIterationVariable(); const VarDecl *IVDecl = cast(cast(IVExpr)->getDecl()); CGF.EmitVarDecl(*IVDecl); CGF.EmitIgnoredExpr(S.getInit()); // Emit the iterations count variable. // If it is not a variable, Sema decided to calculate iterations count on // each iteration (e.g., it is foldable into a constant). if (auto LIExpr = dyn_cast(S.getLastIteration())) { CGF.EmitVarDecl(*cast(LIExpr->getDecl())); // Emit calculation of the iterations count. CGF.EmitIgnoredExpr(S.getCalcLastIteration()); } CGF.EmitOMPSimdInit(S); emitAlignedClause(CGF, S); CGF.EmitOMPLinearClauseInit(S); bool HasLastprivateClause; { OMPPrivateScope LoopScope(CGF); emitPrivateLoopCounters(CGF, LoopScope, S.counters(), S.private_counters()); emitPrivateLinearVars(CGF, S, LoopScope); CGF.EmitOMPPrivateClause(S, LoopScope); CGF.EmitOMPReductionClauseInit(S, LoopScope); HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope); (void)LoopScope.Privatize(); CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(), [&S](CodeGenFunction &CGF) { CGF.EmitOMPLoopBody(S, JumpDest()); CGF.EmitStopPoint(&S); }, [](CodeGenFunction &) {}); // Emit final copy of the lastprivate variables at the end of loops. if (HasLastprivateClause) { CGF.EmitOMPLastprivateClauseFinal(S); } CGF.EmitOMPReductionClauseFinal(S); } CGF.EmitOMPSimdFinal(S); // Emit: if (PreCond) - end. if (ContBlock) { CGF.EmitBranch(ContBlock); CGF.EmitBlock(ContBlock, true); } }; CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen); } void CodeGenFunction::EmitOMPForOuterLoop( OpenMPScheduleClauseKind ScheduleKind, bool IsMonotonic, const OMPLoopDirective &S, OMPPrivateScope &LoopScope, bool Ordered, Address LB, Address UB, Address ST, Address IL, llvm::Value *Chunk) { auto &RT = CGM.getOpenMPRuntime(); // Dynamic scheduling of the outer loop (dynamic, guided, auto, runtime). const bool DynamicOrOrdered = Ordered || RT.isDynamic(ScheduleKind); assert((Ordered || !RT.isStaticNonchunked(ScheduleKind, /*Chunked=*/Chunk != nullptr)) && "static non-chunked schedule does not need outer loop"); // Emit outer loop. // // OpenMP [2.7.1, Loop Construct, Description, table 2-1] // When schedule(dynamic,chunk_size) is specified, the iterations are // distributed to threads in the team in chunks as the threads request them. // Each thread executes a chunk of iterations, then requests another chunk, // until no chunks remain to be distributed. Each chunk contains chunk_size // iterations, except for the last chunk to be distributed, which may have // fewer iterations. When no chunk_size is specified, it defaults to 1. // // When schedule(guided,chunk_size) is specified, the iterations are assigned // to threads in the team in chunks as the executing threads request them. // Each thread executes a chunk of iterations, then requests another chunk, // until no chunks remain to be assigned. For a chunk_size of 1, the size of // each chunk is proportional to the number of unassigned iterations divided // by the number of threads in the team, decreasing to 1. For a chunk_size // with value k (greater than 1), the size of each chunk is determined in the // same way, with the restriction that the chunks do not contain fewer than k // iterations (except for the last chunk to be assigned, which may have fewer // than k iterations). // // When schedule(auto) is specified, the decision regarding scheduling is // delegated to the compiler and/or runtime system. The programmer gives the // implementation the freedom to choose any possible mapping of iterations to // threads in the team. // // When schedule(runtime) is specified, the decision regarding scheduling is // deferred until run time, and the schedule and chunk size are taken from the // run-sched-var ICV. If the ICV is set to auto, the schedule is // implementation defined // // while(__kmpc_dispatch_next(&LB, &UB)) { // idx = LB; // while (idx <= UB) { BODY; ++idx; // __kmpc_dispatch_fini_(4|8)[u](); // For ordered loops only. // } // inner loop // } // // OpenMP [2.7.1, Loop Construct, Description, table 2-1] // When schedule(static, chunk_size) is specified, iterations are divided into // chunks of size chunk_size, and the chunks are assigned to the threads in // the team in a round-robin fashion in the order of the thread number. // // while(UB = min(UB, GlobalUB), idx = LB, idx < UB) { // while (idx <= UB) { BODY; ++idx; } // inner loop // LB = LB + ST; // UB = UB + ST; // } // const Expr *IVExpr = S.getIterationVariable(); const unsigned IVSize = getContext().getTypeSize(IVExpr->getType()); const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation(); if (DynamicOrOrdered) { llvm::Value *UBVal = EmitScalarExpr(S.getLastIteration()); RT.emitForDispatchInit(*this, S.getLocStart(), ScheduleKind, IVSize, IVSigned, Ordered, UBVal, Chunk); } else { RT.emitForStaticInit(*this, S.getLocStart(), ScheduleKind, IVSize, IVSigned, Ordered, IL, LB, UB, ST, Chunk); } auto LoopExit = getJumpDestInCurrentScope("omp.dispatch.end"); // Start the loop with a block that tests the condition. auto CondBlock = createBasicBlock("omp.dispatch.cond"); EmitBlock(CondBlock); LoopStack.push(CondBlock); llvm::Value *BoolCondVal = nullptr; if (!DynamicOrOrdered) { // UB = min(UB, GlobalUB) EmitIgnoredExpr(S.getEnsureUpperBound()); // IV = LB EmitIgnoredExpr(S.getInit()); // IV < UB BoolCondVal = EvaluateExprAsBool(S.getCond()); } else { BoolCondVal = RT.emitForNext(*this, S.getLocStart(), IVSize, IVSigned, IL, LB, UB, ST); } // If there are any cleanups between here and the loop-exit scope, // create a block to stage a loop exit along. auto ExitBlock = LoopExit.getBlock(); if (LoopScope.requiresCleanups()) ExitBlock = createBasicBlock("omp.dispatch.cleanup"); auto LoopBody = createBasicBlock("omp.dispatch.body"); Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock); if (ExitBlock != LoopExit.getBlock()) { EmitBlock(ExitBlock); EmitBranchThroughCleanup(LoopExit); } EmitBlock(LoopBody); // Emit "IV = LB" (in case of static schedule, we have already calculated new // LB for loop condition and emitted it above). if (DynamicOrOrdered) EmitIgnoredExpr(S.getInit()); // Create a block for the increment. auto Continue = getJumpDestInCurrentScope("omp.dispatch.inc"); BreakContinueStack.push_back(BreakContinue(LoopExit, Continue)); // Generate !llvm.loop.parallel metadata for loads and stores for loops // with dynamic/guided scheduling and without ordered clause. if (!isOpenMPSimdDirective(S.getDirectiveKind())) LoopStack.setParallel(!IsMonotonic); else EmitOMPSimdInit(S, IsMonotonic); SourceLocation Loc = S.getLocStart(); EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(), [&S, LoopExit](CodeGenFunction &CGF) { CGF.EmitOMPLoopBody(S, LoopExit); CGF.EmitStopPoint(&S); }, [Ordered, IVSize, IVSigned, Loc](CodeGenFunction &CGF) { if (Ordered) { CGF.CGM.getOpenMPRuntime().emitForOrderedIterationEnd( CGF, Loc, IVSize, IVSigned); } }); EmitBlock(Continue.getBlock()); BreakContinueStack.pop_back(); if (!DynamicOrOrdered) { // Emit "LB = LB + Stride", "UB = UB + Stride". EmitIgnoredExpr(S.getNextLowerBound()); EmitIgnoredExpr(S.getNextUpperBound()); } EmitBranch(CondBlock); LoopStack.pop(); // Emit the fall-through block. EmitBlock(LoopExit.getBlock()); // Tell the runtime we are done. if (!DynamicOrOrdered) RT.emitForStaticFinish(*this, S.getLocEnd()); } /// \brief Emit a helper variable and return corresponding lvalue. static LValue EmitOMPHelperVar(CodeGenFunction &CGF, const DeclRefExpr *Helper) { auto VDecl = cast(Helper->getDecl()); CGF.EmitVarDecl(*VDecl); return CGF.EmitLValue(Helper); } namespace { struct ScheduleKindModifiersTy { OpenMPScheduleClauseKind Kind; OpenMPScheduleClauseModifier M1; OpenMPScheduleClauseModifier M2; ScheduleKindModifiersTy(OpenMPScheduleClauseKind Kind, OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2) : Kind(Kind), M1(M1), M2(M2) {} }; } // namespace static std::pair emitScheduleClause(CodeGenFunction &CGF, const OMPLoopDirective &S, bool OuterRegion) { // Detect the loop schedule kind and chunk. auto ScheduleKind = OMPC_SCHEDULE_unknown; OpenMPScheduleClauseModifier M1 = OMPC_SCHEDULE_MODIFIER_unknown; OpenMPScheduleClauseModifier M2 = OMPC_SCHEDULE_MODIFIER_unknown; llvm::Value *Chunk = nullptr; if (const auto *C = S.getSingleClause()) { ScheduleKind = C->getScheduleKind(); M1 = C->getFirstScheduleModifier(); M2 = C->getSecondScheduleModifier(); if (const auto *Ch = C->getChunkSize()) { if (auto *ImpRef = cast_or_null(C->getHelperChunkSize())) { if (OuterRegion) { const VarDecl *ImpVar = cast(ImpRef->getDecl()); CGF.EmitVarDecl(*ImpVar); CGF.EmitStoreThroughLValue( CGF.EmitAnyExpr(Ch), CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(ImpVar), ImpVar->getType())); } else { Ch = ImpRef; } } if (!C->getHelperChunkSize() || !OuterRegion) { Chunk = CGF.EmitScalarExpr(Ch); Chunk = CGF.EmitScalarConversion(Chunk, Ch->getType(), S.getIterationVariable()->getType(), S.getLocStart()); } } } return std::make_pair(Chunk, ScheduleKindModifiersTy(ScheduleKind, M1, M2)); } bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) { // Emit the loop iteration variable. auto IVExpr = cast(S.getIterationVariable()); auto IVDecl = cast(IVExpr->getDecl()); EmitVarDecl(*IVDecl); // Emit the iterations count variable. // If it is not a variable, Sema decided to calculate iterations count on each // iteration (e.g., it is foldable into a constant). if (auto LIExpr = dyn_cast(S.getLastIteration())) { EmitVarDecl(*cast(LIExpr->getDecl())); // Emit calculation of the iterations count. EmitIgnoredExpr(S.getCalcLastIteration()); } auto &RT = CGM.getOpenMPRuntime(); bool HasLastprivateClause; // Check pre-condition. { // Skip the entire loop if we don't meet the precondition. // If the condition constant folds and can be elided, avoid emitting the // whole loop. bool CondConstant; llvm::BasicBlock *ContBlock = nullptr; if (ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) { if (!CondConstant) return false; } else { auto *ThenBlock = createBasicBlock("omp.precond.then"); ContBlock = createBasicBlock("omp.precond.end"); emitPreCond(*this, S, S.getPreCond(), ThenBlock, ContBlock, getProfileCount(&S)); EmitBlock(ThenBlock); incrementProfileCounter(&S); } emitAlignedClause(*this, S); EmitOMPLinearClauseInit(S); // Emit 'then' code. { // Emit helper vars inits. LValue LB = EmitOMPHelperVar(*this, cast(S.getLowerBoundVariable())); LValue UB = EmitOMPHelperVar(*this, cast(S.getUpperBoundVariable())); LValue ST = EmitOMPHelperVar(*this, cast(S.getStrideVariable())); LValue IL = EmitOMPHelperVar(*this, cast(S.getIsLastIterVariable())); OMPPrivateScope LoopScope(*this); if (EmitOMPFirstprivateClause(S, LoopScope)) { // Emit implicit barrier to synchronize threads and avoid data races on // initialization of firstprivate variables. CGM.getOpenMPRuntime().emitBarrierCall( *this, S.getLocStart(), OMPD_unknown, /*EmitChecks=*/false, /*ForceSimpleCall=*/true); } EmitOMPPrivateClause(S, LoopScope); HasLastprivateClause = EmitOMPLastprivateClauseInit(S, LoopScope); EmitOMPReductionClauseInit(S, LoopScope); emitPrivateLoopCounters(*this, LoopScope, S.counters(), S.private_counters()); emitPrivateLinearVars(*this, S, LoopScope); (void)LoopScope.Privatize(); // Detect the loop schedule kind and chunk. llvm::Value *Chunk; OpenMPScheduleClauseKind ScheduleKind; auto ScheduleInfo = emitScheduleClause(*this, S, /*OuterRegion=*/false); Chunk = ScheduleInfo.first; ScheduleKind = ScheduleInfo.second.Kind; const OpenMPScheduleClauseModifier M1 = ScheduleInfo.second.M1; const OpenMPScheduleClauseModifier M2 = ScheduleInfo.second.M2; const unsigned IVSize = getContext().getTypeSize(IVExpr->getType()); const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation(); const bool Ordered = S.getSingleClause() != nullptr; // OpenMP 4.5, 2.7.1 Loop Construct, Description. // If the static schedule kind is specified or if the ordered clause is // specified, and if no monotonic modifier is specified, the effect will // be as if the monotonic modifier was specified. if (RT.isStaticNonchunked(ScheduleKind, /* Chunked */ Chunk != nullptr) && !Ordered) { if (isOpenMPSimdDirective(S.getDirectiveKind())) EmitOMPSimdInit(S, /*IsMonotonic=*/true); // OpenMP [2.7.1, Loop Construct, Description, table 2-1] // When no chunk_size is specified, the iteration space is divided into // chunks that are approximately equal in size, and at most one chunk is // distributed to each thread. Note that the size of the chunks is // unspecified in this case. RT.emitForStaticInit(*this, S.getLocStart(), ScheduleKind, IVSize, IVSigned, Ordered, IL.getAddress(), LB.getAddress(), UB.getAddress(), ST.getAddress()); auto LoopExit = getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit")); // UB = min(UB, GlobalUB); EmitIgnoredExpr(S.getEnsureUpperBound()); // IV = LB; EmitIgnoredExpr(S.getInit()); // while (idx <= UB) { BODY; ++idx; } EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(), [&S, LoopExit](CodeGenFunction &CGF) { CGF.EmitOMPLoopBody(S, LoopExit); CGF.EmitStopPoint(&S); }, [](CodeGenFunction &) {}); EmitBlock(LoopExit.getBlock()); // Tell the runtime we are done. RT.emitForStaticFinish(*this, S.getLocStart()); } else { const bool IsMonotonic = Ordered || ScheduleKind == OMPC_SCHEDULE_static || ScheduleKind == OMPC_SCHEDULE_unknown || M1 == OMPC_SCHEDULE_MODIFIER_monotonic || M2 == OMPC_SCHEDULE_MODIFIER_monotonic; // Emit the outer loop, which requests its work chunk [LB..UB] from // runtime and runs the inner loop to process it. EmitOMPForOuterLoop(ScheduleKind, IsMonotonic, S, LoopScope, Ordered, LB.getAddress(), UB.getAddress(), ST.getAddress(), IL.getAddress(), Chunk); } EmitOMPReductionClauseFinal(S); // Emit final copy of the lastprivate variables if IsLastIter != 0. if (HasLastprivateClause) EmitOMPLastprivateClauseFinal( S, Builder.CreateIsNotNull(EmitLoadOfScalar(IL, S.getLocStart()))); } if (isOpenMPSimdDirective(S.getDirectiveKind())) { EmitOMPSimdFinal(S); } // We're now done with the loop, so jump to the continuation block. if (ContBlock) { EmitBranch(ContBlock); EmitBlock(ContBlock, true); } } return HasLastprivateClause; } void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &S) { LexicalScope Scope(*this, S.getSourceRange()); bool HasLastprivates = false; auto &&CodeGen = [&S, &HasLastprivates](CodeGenFunction &CGF) { HasLastprivates = CGF.EmitOMPWorksharingLoop(S); }; CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_for, CodeGen, S.hasCancel()); // Emit an implicit barrier at the end. if (!S.getSingleClause() || HasLastprivates) { CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(), OMPD_for); } } void CodeGenFunction::EmitOMPForSimdDirective(const OMPForSimdDirective &S) { LexicalScope Scope(*this, S.getSourceRange()); bool HasLastprivates = false; auto &&CodeGen = [&S, &HasLastprivates](CodeGenFunction &CGF) { HasLastprivates = CGF.EmitOMPWorksharingLoop(S); }; CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen); // Emit an implicit barrier at the end. if (!S.getSingleClause() || HasLastprivates) { CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(), OMPD_for); } } static LValue createSectionLVal(CodeGenFunction &CGF, QualType Ty, const Twine &Name, llvm::Value *Init = nullptr) { auto LVal = CGF.MakeAddrLValue(CGF.CreateMemTemp(Ty, Name), Ty); if (Init) CGF.EmitScalarInit(Init, LVal); return LVal; } OpenMPDirectiveKind CodeGenFunction::EmitSections(const OMPExecutableDirective &S) { auto *Stmt = cast(S.getAssociatedStmt())->getCapturedStmt(); auto *CS = dyn_cast(Stmt); bool HasLastprivates = false; auto &&CodeGen = [&S, Stmt, CS, &HasLastprivates](CodeGenFunction &CGF) { auto &C = CGF.CGM.getContext(); auto KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1); // Emit helper vars inits. LValue LB = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.lb.", CGF.Builder.getInt32(0)); auto *GlobalUBVal = CS != nullptr ? CGF.Builder.getInt32(CS->size() - 1) : CGF.Builder.getInt32(0); LValue UB = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.ub.", GlobalUBVal); LValue ST = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.st.", CGF.Builder.getInt32(1)); LValue IL = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.il.", CGF.Builder.getInt32(0)); // Loop counter. LValue IV = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.iv."); OpaqueValueExpr IVRefExpr(S.getLocStart(), KmpInt32Ty, VK_LValue); CodeGenFunction::OpaqueValueMapping OpaqueIV(CGF, &IVRefExpr, IV); OpaqueValueExpr UBRefExpr(S.getLocStart(), KmpInt32Ty, VK_LValue); CodeGenFunction::OpaqueValueMapping OpaqueUB(CGF, &UBRefExpr, UB); // Generate condition for loop. BinaryOperator Cond(&IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue, OK_Ordinary, S.getLocStart(), /*fpContractable=*/false); // Increment for loop counter. UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary, S.getLocStart()); auto BodyGen = [Stmt, CS, &S, &IV](CodeGenFunction &CGF) { // Iterate through all sections and emit a switch construct: // switch (IV) { // case 0: // ; // break; // ... // case - 1: // - 1]>; // break; // } // .omp.sections.exit: auto *ExitBB = CGF.createBasicBlock(".omp.sections.exit"); auto *SwitchStmt = CGF.Builder.CreateSwitch( CGF.EmitLoadOfLValue(IV, S.getLocStart()).getScalarVal(), ExitBB, CS == nullptr ? 1 : CS->size()); if (CS) { unsigned CaseNumber = 0; for (auto *SubStmt : CS->children()) { auto CaseBB = CGF.createBasicBlock(".omp.sections.case"); CGF.EmitBlock(CaseBB); SwitchStmt->addCase(CGF.Builder.getInt32(CaseNumber), CaseBB); CGF.EmitStmt(SubStmt); CGF.EmitBranch(ExitBB); ++CaseNumber; } } else { auto CaseBB = CGF.createBasicBlock(".omp.sections.case"); CGF.EmitBlock(CaseBB); SwitchStmt->addCase(CGF.Builder.getInt32(0), CaseBB); CGF.EmitStmt(Stmt); CGF.EmitBranch(ExitBB); } CGF.EmitBlock(ExitBB, /*IsFinished=*/true); }; CodeGenFunction::OMPPrivateScope LoopScope(CGF); if (CGF.EmitOMPFirstprivateClause(S, LoopScope)) { // Emit implicit barrier to synchronize threads and avoid data races on // initialization of firstprivate variables. CGF.CGM.getOpenMPRuntime().emitBarrierCall( CGF, S.getLocStart(), OMPD_unknown, /*EmitChecks=*/false, /*ForceSimpleCall=*/true); } CGF.EmitOMPPrivateClause(S, LoopScope); HasLastprivates = CGF.EmitOMPLastprivateClauseInit(S, LoopScope); CGF.EmitOMPReductionClauseInit(S, LoopScope); (void)LoopScope.Privatize(); // Emit static non-chunked loop. CGF.CGM.getOpenMPRuntime().emitForStaticInit( CGF, S.getLocStart(), OMPC_SCHEDULE_static, /*IVSize=*/32, /*IVSigned=*/true, /*Ordered=*/false, IL.getAddress(), LB.getAddress(), UB.getAddress(), ST.getAddress()); // UB = min(UB, GlobalUB); auto *UBVal = CGF.EmitLoadOfScalar(UB, S.getLocStart()); auto *MinUBGlobalUB = CGF.Builder.CreateSelect( CGF.Builder.CreateICmpSLT(UBVal, GlobalUBVal), UBVal, GlobalUBVal); CGF.EmitStoreOfScalar(MinUBGlobalUB, UB); // IV = LB; CGF.EmitStoreOfScalar(CGF.EmitLoadOfScalar(LB, S.getLocStart()), IV); // while (idx <= UB) { BODY; ++idx; } CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, &Cond, &Inc, BodyGen, [](CodeGenFunction &) {}); // Tell the runtime we are done. CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocStart()); CGF.EmitOMPReductionClauseFinal(S); // Emit final copy of the lastprivate variables if IsLastIter != 0. if (HasLastprivates) CGF.EmitOMPLastprivateClauseFinal( S, CGF.Builder.CreateIsNotNull( CGF.EmitLoadOfScalar(IL, S.getLocStart()))); }; bool HasCancel = false; if (auto *OSD = dyn_cast(&S)) HasCancel = OSD->hasCancel(); else if (auto *OPSD = dyn_cast(&S)) HasCancel = OPSD->hasCancel(); CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_sections, CodeGen, HasCancel); // Emit barrier for lastprivates only if 'sections' directive has 'nowait' // clause. Otherwise the barrier will be generated by the codegen for the // directive. if (HasLastprivates && S.getSingleClause()) { // Emit implicit barrier to synchronize threads and avoid data races on // initialization of firstprivate variables. CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(), OMPD_unknown); } return OMPD_sections; } void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &S) { LexicalScope Scope(*this, S.getSourceRange()); OpenMPDirectiveKind EmittedAs = EmitSections(S); // Emit an implicit barrier at the end. if (!S.getSingleClause()) { CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(), EmittedAs); } } void CodeGenFunction::EmitOMPSectionDirective(const OMPSectionDirective &S) { LexicalScope Scope(*this, S.getSourceRange()); auto &&CodeGen = [&S](CodeGenFunction &CGF) { CGF.EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); }; CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_section, CodeGen, S.hasCancel()); } void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &S) { llvm::SmallVector CopyprivateVars; llvm::SmallVector DestExprs; llvm::SmallVector SrcExprs; llvm::SmallVector AssignmentOps; // Check if there are any 'copyprivate' clauses associated with this // 'single' // construct. // Build a list of copyprivate variables along with helper expressions // (, , = expressions) for (const auto *C : S.getClausesOfKind()) { CopyprivateVars.append(C->varlists().begin(), C->varlists().end()); DestExprs.append(C->destination_exprs().begin(), C->destination_exprs().end()); SrcExprs.append(C->source_exprs().begin(), C->source_exprs().end()); AssignmentOps.append(C->assignment_ops().begin(), C->assignment_ops().end()); } LexicalScope Scope(*this, S.getSourceRange()); // Emit code for 'single' region along with 'copyprivate' clauses bool HasFirstprivates; auto &&CodeGen = [&S, &HasFirstprivates](CodeGenFunction &CGF) { CodeGenFunction::OMPPrivateScope SingleScope(CGF); HasFirstprivates = CGF.EmitOMPFirstprivateClause(S, SingleScope); CGF.EmitOMPPrivateClause(S, SingleScope); (void)SingleScope.Privatize(); CGF.EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); }; CGM.getOpenMPRuntime().emitSingleRegion(*this, CodeGen, S.getLocStart(), CopyprivateVars, DestExprs, SrcExprs, AssignmentOps); // Emit an implicit barrier at the end (to avoid data race on firstprivate // init or if no 'nowait' clause was specified and no 'copyprivate' clause). if ((!S.getSingleClause() || HasFirstprivates) && CopyprivateVars.empty()) { CGM.getOpenMPRuntime().emitBarrierCall( *this, S.getLocStart(), S.getSingleClause() ? OMPD_unknown : OMPD_single); } } void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) { LexicalScope Scope(*this, S.getSourceRange()); auto &&CodeGen = [&S](CodeGenFunction &CGF) { CGF.EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); }; CGM.getOpenMPRuntime().emitMasterRegion(*this, CodeGen, S.getLocStart()); } void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) { LexicalScope Scope(*this, S.getSourceRange()); auto &&CodeGen = [&S](CodeGenFunction &CGF) { CGF.EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); }; Expr *Hint = nullptr; if (auto *HintClause = S.getSingleClause()) Hint = HintClause->getHint(); CGM.getOpenMPRuntime().emitCriticalRegion(*this, S.getDirectiveName().getAsString(), CodeGen, S.getLocStart(), Hint); } void CodeGenFunction::EmitOMPParallelForDirective( const OMPParallelForDirective &S) { // Emit directive as a combined directive that consists of two implicit // directives: 'parallel' with 'for' directive. LexicalScope Scope(*this, S.getSourceRange()); (void)emitScheduleClause(*this, S, /*OuterRegion=*/true); auto &&CodeGen = [&S](CodeGenFunction &CGF) { CGF.EmitOMPWorksharingLoop(S); }; emitCommonOMPParallelDirective(*this, S, OMPD_for, CodeGen); } void CodeGenFunction::EmitOMPParallelForSimdDirective( const OMPParallelForSimdDirective &S) { // Emit directive as a combined directive that consists of two implicit // directives: 'parallel' with 'for' directive. LexicalScope Scope(*this, S.getSourceRange()); (void)emitScheduleClause(*this, S, /*OuterRegion=*/true); auto &&CodeGen = [&S](CodeGenFunction &CGF) { CGF.EmitOMPWorksharingLoop(S); }; emitCommonOMPParallelDirective(*this, S, OMPD_simd, CodeGen); } void CodeGenFunction::EmitOMPParallelSectionsDirective( const OMPParallelSectionsDirective &S) { // Emit directive as a combined directive that consists of two implicit // directives: 'parallel' with 'sections' directive. LexicalScope Scope(*this, S.getSourceRange()); auto &&CodeGen = [&S](CodeGenFunction &CGF) { (void)CGF.EmitSections(S); }; emitCommonOMPParallelDirective(*this, S, OMPD_sections, CodeGen); } void CodeGenFunction::EmitOMPTaskDirective(const OMPTaskDirective &S) { // Emit outlined function for task construct. LexicalScope Scope(*this, S.getSourceRange()); auto CS = cast(S.getAssociatedStmt()); auto CapturedStruct = GenerateCapturedStmtArgument(*CS); auto *I = CS->getCapturedDecl()->param_begin(); auto *PartId = std::next(I); // The first function argument for tasks is a thread id, the second one is a // part id (0 for tied tasks, >=0 for untied task). llvm::DenseSet EmittedAsPrivate; // Get list of private variables. llvm::SmallVector PrivateVars; llvm::SmallVector PrivateCopies; for (const auto *C : S.getClausesOfKind()) { auto IRef = C->varlist_begin(); for (auto *IInit : C->private_copies()) { auto *OrigVD = cast(cast(*IRef)->getDecl()); if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) { PrivateVars.push_back(*IRef); PrivateCopies.push_back(IInit); } ++IRef; } } EmittedAsPrivate.clear(); // Get list of firstprivate variables. llvm::SmallVector FirstprivateVars; llvm::SmallVector FirstprivateCopies; llvm::SmallVector FirstprivateInits; for (const auto *C : S.getClausesOfKind()) { auto IRef = C->varlist_begin(); auto IElemInitRef = C->inits().begin(); for (auto *IInit : C->private_copies()) { auto *OrigVD = cast(cast(*IRef)->getDecl()); if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) { FirstprivateVars.push_back(*IRef); FirstprivateCopies.push_back(IInit); FirstprivateInits.push_back(*IElemInitRef); } ++IRef, ++IElemInitRef; } } // Build list of dependences. llvm::SmallVector, 8> Dependences; for (const auto *C : S.getClausesOfKind()) { for (auto *IRef : C->varlists()) { Dependences.push_back(std::make_pair(C->getDependencyKind(), IRef)); } } auto &&CodeGen = [PartId, &S, &PrivateVars, &FirstprivateVars]( CodeGenFunction &CGF) { // Set proper addresses for generated private copies. auto *CS = cast(S.getAssociatedStmt()); OMPPrivateScope Scope(CGF); if (!PrivateVars.empty() || !FirstprivateVars.empty()) { auto *CopyFn = CGF.Builder.CreateLoad( CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(3))); auto *PrivatesPtr = CGF.Builder.CreateLoad( CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(2))); // Map privates. llvm::SmallVector, 16> PrivatePtrs; llvm::SmallVector CallArgs; CallArgs.push_back(PrivatesPtr); for (auto *E : PrivateVars) { auto *VD = cast(cast(E)->getDecl()); Address PrivatePtr = CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType())); PrivatePtrs.push_back(std::make_pair(VD, PrivatePtr)); CallArgs.push_back(PrivatePtr.getPointer()); } for (auto *E : FirstprivateVars) { auto *VD = cast(cast(E)->getDecl()); Address PrivatePtr = CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType())); PrivatePtrs.push_back(std::make_pair(VD, PrivatePtr)); CallArgs.push_back(PrivatePtr.getPointer()); } CGF.EmitRuntimeCall(CopyFn, CallArgs); for (auto &&Pair : PrivatePtrs) { Address Replacement(CGF.Builder.CreateLoad(Pair.second), CGF.getContext().getDeclAlign(Pair.first)); Scope.addPrivate(Pair.first, [Replacement]() { return Replacement; }); } } (void)Scope.Privatize(); if (*PartId) { // TODO: emit code for untied tasks. } CGF.EmitStmt(CS->getCapturedStmt()); }; auto OutlinedFn = CGM.getOpenMPRuntime().emitTaskOutlinedFunction( S, *I, OMPD_task, CodeGen); // Check if we should emit tied or untied task. bool Tied = !S.getSingleClause(); // Check if the task is final llvm::PointerIntPair Final; if (const auto *Clause = S.getSingleClause()) { // If the condition constant folds and can be elided, try to avoid emitting // the condition and the dead arm of the if/else. auto *Cond = Clause->getCondition(); bool CondConstant; if (ConstantFoldsToSimpleInteger(Cond, CondConstant)) Final.setInt(CondConstant); else Final.setPointer(EvaluateExprAsBool(Cond)); } else { // By default the task is not final. Final.setInt(/*IntVal=*/false); } auto SharedsTy = getContext().getRecordType(CS->getCapturedRecordDecl()); const Expr *IfCond = nullptr; for (const auto *C : S.getClausesOfKind()) { if (C->getNameModifier() == OMPD_unknown || C->getNameModifier() == OMPD_task) { IfCond = C->getCondition(); break; } } CGM.getOpenMPRuntime().emitTaskCall( *this, S.getLocStart(), S, Tied, Final, OutlinedFn, SharedsTy, CapturedStruct, IfCond, PrivateVars, PrivateCopies, FirstprivateVars, FirstprivateCopies, FirstprivateInits, Dependences); } void CodeGenFunction::EmitOMPTaskyieldDirective( const OMPTaskyieldDirective &S) { CGM.getOpenMPRuntime().emitTaskyieldCall(*this, S.getLocStart()); } void CodeGenFunction::EmitOMPBarrierDirective(const OMPBarrierDirective &S) { CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(), OMPD_barrier); } void CodeGenFunction::EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S) { CGM.getOpenMPRuntime().emitTaskwaitCall(*this, S.getLocStart()); } void CodeGenFunction::EmitOMPTaskgroupDirective( const OMPTaskgroupDirective &S) { LexicalScope Scope(*this, S.getSourceRange()); auto &&CodeGen = [&S](CodeGenFunction &CGF) { CGF.EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); }; CGM.getOpenMPRuntime().emitTaskgroupRegion(*this, CodeGen, S.getLocStart()); } void CodeGenFunction::EmitOMPFlushDirective(const OMPFlushDirective &S) { CGM.getOpenMPRuntime().emitFlush(*this, [&]() -> ArrayRef { if (const auto *FlushClause = S.getSingleClause()) { return llvm::makeArrayRef(FlushClause->varlist_begin(), FlushClause->varlist_end()); } return llvm::None; }(), S.getLocStart()); } void CodeGenFunction::EmitOMPDistributeDirective( const OMPDistributeDirective &S) { llvm_unreachable("CodeGen for 'omp distribute' is not supported yet."); } static llvm::Function *emitOutlinedOrderedFunction(CodeGenModule &CGM, const CapturedStmt *S) { CodeGenFunction CGF(CGM, /*suppressNewContext=*/true); CodeGenFunction::CGCapturedStmtInfo CapStmtInfo; CGF.CapturedStmtInfo = &CapStmtInfo; auto *Fn = CGF.GenerateOpenMPCapturedStmtFunction(*S); Fn->addFnAttr(llvm::Attribute::NoInline); return Fn; } void CodeGenFunction::EmitOMPOrderedDirective(const OMPOrderedDirective &S) { if (!S.getAssociatedStmt()) return; LexicalScope Scope(*this, S.getSourceRange()); auto *C = S.getSingleClause(); auto &&CodeGen = [&S, C, this](CodeGenFunction &CGF) { if (C) { auto CS = cast(S.getAssociatedStmt()); llvm::SmallVector CapturedVars; CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars); auto *OutlinedFn = emitOutlinedOrderedFunction(CGM, CS); CGF.EmitNounwindRuntimeCall(OutlinedFn, CapturedVars); } else { CGF.EmitStmt( cast(S.getAssociatedStmt())->getCapturedStmt()); } }; CGM.getOpenMPRuntime().emitOrderedRegion(*this, CodeGen, S.getLocStart(), !C); } static llvm::Value *convertToScalarValue(CodeGenFunction &CGF, RValue Val, QualType SrcType, QualType DestType, SourceLocation Loc) { assert(CGF.hasScalarEvaluationKind(DestType) && "DestType must have scalar evaluation kind."); assert(!Val.isAggregate() && "Must be a scalar or complex."); return Val.isScalar() ? CGF.EmitScalarConversion(Val.getScalarVal(), SrcType, DestType, Loc) : CGF.EmitComplexToScalarConversion(Val.getComplexVal(), SrcType, DestType, Loc); } static CodeGenFunction::ComplexPairTy convertToComplexValue(CodeGenFunction &CGF, RValue Val, QualType SrcType, QualType DestType, SourceLocation Loc) { assert(CGF.getEvaluationKind(DestType) == TEK_Complex && "DestType must have complex evaluation kind."); CodeGenFunction::ComplexPairTy ComplexVal; if (Val.isScalar()) { // Convert the input element to the element type of the complex. auto DestElementType = DestType->castAs()->getElementType(); auto ScalarVal = CGF.EmitScalarConversion(Val.getScalarVal(), SrcType, DestElementType, Loc); ComplexVal = CodeGenFunction::ComplexPairTy( ScalarVal, llvm::Constant::getNullValue(ScalarVal->getType())); } else { assert(Val.isComplex() && "Must be a scalar or complex."); auto SrcElementType = SrcType->castAs()->getElementType(); auto DestElementType = DestType->castAs()->getElementType(); ComplexVal.first = CGF.EmitScalarConversion( Val.getComplexVal().first, SrcElementType, DestElementType, Loc); ComplexVal.second = CGF.EmitScalarConversion( Val.getComplexVal().second, SrcElementType, DestElementType, Loc); } return ComplexVal; } static void emitSimpleAtomicStore(CodeGenFunction &CGF, bool IsSeqCst, LValue LVal, RValue RVal) { if (LVal.isGlobalReg()) { CGF.EmitStoreThroughGlobalRegLValue(RVal, LVal); } else { CGF.EmitAtomicStore(RVal, LVal, IsSeqCst ? llvm::SequentiallyConsistent : llvm::Monotonic, LVal.isVolatile(), /*IsInit=*/false); } } void CodeGenFunction::emitOMPSimpleStore(LValue LVal, RValue RVal, QualType RValTy, SourceLocation Loc) { switch (getEvaluationKind(LVal.getType())) { case TEK_Scalar: EmitStoreThroughLValue(RValue::get(convertToScalarValue( *this, RVal, RValTy, LVal.getType(), Loc)), LVal); break; case TEK_Complex: EmitStoreOfComplex( convertToComplexValue(*this, RVal, RValTy, LVal.getType(), Loc), LVal, /*isInit=*/false); break; case TEK_Aggregate: llvm_unreachable("Must be a scalar or complex."); } } static void EmitOMPAtomicReadExpr(CodeGenFunction &CGF, bool IsSeqCst, const Expr *X, const Expr *V, SourceLocation Loc) { // v = x; assert(V->isLValue() && "V of 'omp atomic read' is not lvalue"); assert(X->isLValue() && "X of 'omp atomic read' is not lvalue"); LValue XLValue = CGF.EmitLValue(X); LValue VLValue = CGF.EmitLValue(V); RValue Res = XLValue.isGlobalReg() ? CGF.EmitLoadOfLValue(XLValue, Loc) : CGF.EmitAtomicLoad(XLValue, Loc, IsSeqCst ? llvm::SequentiallyConsistent : llvm::Monotonic, XLValue.isVolatile()); // OpenMP, 2.12.6, atomic Construct // Any atomic construct with a seq_cst clause forces the atomically // performed operation to include an implicit flush operation without a // list. if (IsSeqCst) CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc); CGF.emitOMPSimpleStore(VLValue, Res, X->getType().getNonReferenceType(), Loc); } static void EmitOMPAtomicWriteExpr(CodeGenFunction &CGF, bool IsSeqCst, const Expr *X, const Expr *E, SourceLocation Loc) { // x = expr; assert(X->isLValue() && "X of 'omp atomic write' is not lvalue"); emitSimpleAtomicStore(CGF, IsSeqCst, CGF.EmitLValue(X), CGF.EmitAnyExpr(E)); // OpenMP, 2.12.6, atomic Construct // Any atomic construct with a seq_cst clause forces the atomically // performed operation to include an implicit flush operation without a // list. if (IsSeqCst) CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc); } static std::pair emitOMPAtomicRMW(CodeGenFunction &CGF, LValue X, RValue Update, BinaryOperatorKind BO, llvm::AtomicOrdering AO, bool IsXLHSInRHSPart) { auto &Context = CGF.CGM.getContext(); // Allow atomicrmw only if 'x' and 'update' are integer values, lvalue for 'x' // expression is simple and atomic is allowed for the given type for the // target platform. if (BO == BO_Comma || !Update.isScalar() || !Update.getScalarVal()->getType()->isIntegerTy() || !X.isSimple() || (!isa(Update.getScalarVal()) && (Update.getScalarVal()->getType() != X.getAddress().getElementType())) || !X.getAddress().getElementType()->isIntegerTy() || !Context.getTargetInfo().hasBuiltinAtomic( Context.getTypeSize(X.getType()), Context.toBits(X.getAlignment()))) return std::make_pair(false, RValue::get(nullptr)); llvm::AtomicRMWInst::BinOp RMWOp; switch (BO) { case BO_Add: RMWOp = llvm::AtomicRMWInst::Add; break; case BO_Sub: if (!IsXLHSInRHSPart) return std::make_pair(false, RValue::get(nullptr)); RMWOp = llvm::AtomicRMWInst::Sub; break; case BO_And: RMWOp = llvm::AtomicRMWInst::And; break; case BO_Or: RMWOp = llvm::AtomicRMWInst::Or; break; case BO_Xor: RMWOp = llvm::AtomicRMWInst::Xor; break; case BO_LT: RMWOp = X.getType()->hasSignedIntegerRepresentation() ? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Min : llvm::AtomicRMWInst::Max) : (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMin : llvm::AtomicRMWInst::UMax); break; case BO_GT: RMWOp = X.getType()->hasSignedIntegerRepresentation() ? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Max : llvm::AtomicRMWInst::Min) : (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMax : llvm::AtomicRMWInst::UMin); break; case BO_Assign: RMWOp = llvm::AtomicRMWInst::Xchg; break; case BO_Mul: case BO_Div: case BO_Rem: case BO_Shl: case BO_Shr: case BO_LAnd: case BO_LOr: return std::make_pair(false, RValue::get(nullptr)); case BO_PtrMemD: case BO_PtrMemI: case BO_LE: case BO_GE: case BO_EQ: case BO_NE: case BO_AddAssign: case BO_SubAssign: case BO_AndAssign: case BO_OrAssign: case BO_XorAssign: case BO_MulAssign: case BO_DivAssign: case BO_RemAssign: case BO_ShlAssign: case BO_ShrAssign: case BO_Comma: llvm_unreachable("Unsupported atomic update operation"); } auto *UpdateVal = Update.getScalarVal(); if (auto *IC = dyn_cast(UpdateVal)) { UpdateVal = CGF.Builder.CreateIntCast( IC, X.getAddress().getElementType(), X.getType()->hasSignedIntegerRepresentation()); } auto *Res = CGF.Builder.CreateAtomicRMW(RMWOp, X.getPointer(), UpdateVal, AO); return std::make_pair(true, RValue::get(Res)); } std::pair CodeGenFunction::EmitOMPAtomicSimpleUpdateExpr( LValue X, RValue E, BinaryOperatorKind BO, bool IsXLHSInRHSPart, llvm::AtomicOrdering AO, SourceLocation Loc, const llvm::function_ref &CommonGen) { // Update expressions are allowed to have the following forms: // x binop= expr; -> xrval + expr; // x++, ++x -> xrval + 1; // x--, --x -> xrval - 1; // x = x binop expr; -> xrval binop expr // x = expr Op x; - > expr binop xrval; auto Res = emitOMPAtomicRMW(*this, X, E, BO, AO, IsXLHSInRHSPart); if (!Res.first) { if (X.isGlobalReg()) { // Emit an update expression: 'xrval' binop 'expr' or 'expr' binop // 'xrval'. EmitStoreThroughLValue(CommonGen(EmitLoadOfLValue(X, Loc)), X); } else { // Perform compare-and-swap procedure. EmitAtomicUpdate(X, AO, CommonGen, X.getType().isVolatileQualified()); } } return Res; } static void EmitOMPAtomicUpdateExpr(CodeGenFunction &CGF, bool IsSeqCst, const Expr *X, const Expr *E, const Expr *UE, bool IsXLHSInRHSPart, SourceLocation Loc) { assert(isa(UE->IgnoreImpCasts()) && "Update expr in 'atomic update' must be a binary operator."); auto *BOUE = cast(UE->IgnoreImpCasts()); // Update expressions are allowed to have the following forms: // x binop= expr; -> xrval + expr; // x++, ++x -> xrval + 1; // x--, --x -> xrval - 1; // x = x binop expr; -> xrval binop expr // x = expr Op x; - > expr binop xrval; assert(X->isLValue() && "X of 'omp atomic update' is not lvalue"); LValue XLValue = CGF.EmitLValue(X); RValue ExprRValue = CGF.EmitAnyExpr(E); auto AO = IsSeqCst ? llvm::SequentiallyConsistent : llvm::Monotonic; auto *LHS = cast(BOUE->getLHS()->IgnoreImpCasts()); auto *RHS = cast(BOUE->getRHS()->IgnoreImpCasts()); auto *XRValExpr = IsXLHSInRHSPart ? LHS : RHS; auto *ERValExpr = IsXLHSInRHSPart ? RHS : LHS; auto Gen = [&CGF, UE, ExprRValue, XRValExpr, ERValExpr](RValue XRValue) -> RValue { CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue); CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, XRValue); return CGF.EmitAnyExpr(UE); }; (void)CGF.EmitOMPAtomicSimpleUpdateExpr( XLValue, ExprRValue, BOUE->getOpcode(), IsXLHSInRHSPart, AO, Loc, Gen); // OpenMP, 2.12.6, atomic Construct // Any atomic construct with a seq_cst clause forces the atomically // performed operation to include an implicit flush operation without a // list. if (IsSeqCst) CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc); } static RValue convertToType(CodeGenFunction &CGF, RValue Value, QualType SourceType, QualType ResType, SourceLocation Loc) { switch (CGF.getEvaluationKind(ResType)) { case TEK_Scalar: return RValue::get( convertToScalarValue(CGF, Value, SourceType, ResType, Loc)); case TEK_Complex: { auto Res = convertToComplexValue(CGF, Value, SourceType, ResType, Loc); return RValue::getComplex(Res.first, Res.second); } case TEK_Aggregate: break; } llvm_unreachable("Must be a scalar or complex."); } static void EmitOMPAtomicCaptureExpr(CodeGenFunction &CGF, bool IsSeqCst, bool IsPostfixUpdate, const Expr *V, const Expr *X, const Expr *E, const Expr *UE, bool IsXLHSInRHSPart, SourceLocation Loc) { assert(X->isLValue() && "X of 'omp atomic capture' is not lvalue"); assert(V->isLValue() && "V of 'omp atomic capture' is not lvalue"); RValue NewVVal; LValue VLValue = CGF.EmitLValue(V); LValue XLValue = CGF.EmitLValue(X); RValue ExprRValue = CGF.EmitAnyExpr(E); auto AO = IsSeqCst ? llvm::SequentiallyConsistent : llvm::Monotonic; QualType NewVValType; if (UE) { // 'x' is updated with some additional value. assert(isa(UE->IgnoreImpCasts()) && "Update expr in 'atomic capture' must be a binary operator."); auto *BOUE = cast(UE->IgnoreImpCasts()); // Update expressions are allowed to have the following forms: // x binop= expr; -> xrval + expr; // x++, ++x -> xrval + 1; // x--, --x -> xrval - 1; // x = x binop expr; -> xrval binop expr // x = expr Op x; - > expr binop xrval; auto *LHS = cast(BOUE->getLHS()->IgnoreImpCasts()); auto *RHS = cast(BOUE->getRHS()->IgnoreImpCasts()); auto *XRValExpr = IsXLHSInRHSPart ? LHS : RHS; NewVValType = XRValExpr->getType(); auto *ERValExpr = IsXLHSInRHSPart ? RHS : LHS; auto &&Gen = [&CGF, &NewVVal, UE, ExprRValue, XRValExpr, ERValExpr, IsSeqCst, IsPostfixUpdate](RValue XRValue) -> RValue { CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue); CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, XRValue); RValue Res = CGF.EmitAnyExpr(UE); NewVVal = IsPostfixUpdate ? XRValue : Res; return Res; }; auto Res = CGF.EmitOMPAtomicSimpleUpdateExpr( XLValue, ExprRValue, BOUE->getOpcode(), IsXLHSInRHSPart, AO, Loc, Gen); if (Res.first) { // 'atomicrmw' instruction was generated. if (IsPostfixUpdate) { // Use old value from 'atomicrmw'. NewVVal = Res.second; } else { // 'atomicrmw' does not provide new value, so evaluate it using old // value of 'x'. CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue); CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, Res.second); NewVVal = CGF.EmitAnyExpr(UE); } } } else { // 'x' is simply rewritten with some 'expr'. NewVValType = X->getType().getNonReferenceType(); ExprRValue = convertToType(CGF, ExprRValue, E->getType(), X->getType().getNonReferenceType(), Loc); auto &&Gen = [&CGF, &NewVVal, ExprRValue](RValue XRValue) -> RValue { NewVVal = XRValue; return ExprRValue; }; // Try to perform atomicrmw xchg, otherwise simple exchange. auto Res = CGF.EmitOMPAtomicSimpleUpdateExpr( XLValue, ExprRValue, /*BO=*/BO_Assign, /*IsXLHSInRHSPart=*/false, AO, Loc, Gen); if (Res.first) { // 'atomicrmw' instruction was generated. NewVVal = IsPostfixUpdate ? Res.second : ExprRValue; } } // Emit post-update store to 'v' of old/new 'x' value. CGF.emitOMPSimpleStore(VLValue, NewVVal, NewVValType, Loc); // OpenMP, 2.12.6, atomic Construct // Any atomic construct with a seq_cst clause forces the atomically // performed operation to include an implicit flush operation without a // list. if (IsSeqCst) CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc); } static void EmitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind, bool IsSeqCst, bool IsPostfixUpdate, const Expr *X, const Expr *V, const Expr *E, const Expr *UE, bool IsXLHSInRHSPart, SourceLocation Loc) { switch (Kind) { case OMPC_read: EmitOMPAtomicReadExpr(CGF, IsSeqCst, X, V, Loc); break; case OMPC_write: EmitOMPAtomicWriteExpr(CGF, IsSeqCst, X, E, Loc); break; case OMPC_unknown: case OMPC_update: EmitOMPAtomicUpdateExpr(CGF, IsSeqCst, X, E, UE, IsXLHSInRHSPart, Loc); break; case OMPC_capture: EmitOMPAtomicCaptureExpr(CGF, IsSeqCst, IsPostfixUpdate, V, X, E, UE, IsXLHSInRHSPart, Loc); break; case OMPC_if: case OMPC_final: case OMPC_num_threads: case OMPC_private: case OMPC_firstprivate: case OMPC_lastprivate: case OMPC_reduction: case OMPC_safelen: case OMPC_simdlen: case OMPC_collapse: case OMPC_default: case OMPC_seq_cst: case OMPC_shared: case OMPC_linear: case OMPC_aligned: case OMPC_copyin: case OMPC_copyprivate: case OMPC_flush: case OMPC_proc_bind: case OMPC_schedule: case OMPC_ordered: case OMPC_nowait: case OMPC_untied: case OMPC_threadprivate: case OMPC_depend: case OMPC_mergeable: case OMPC_device: case OMPC_threads: case OMPC_simd: case OMPC_map: case OMPC_num_teams: case OMPC_thread_limit: case OMPC_priority: case OMPC_grainsize: case OMPC_nogroup: case OMPC_num_tasks: case OMPC_hint: llvm_unreachable("Clause is not allowed in 'omp atomic'."); } } void CodeGenFunction::EmitOMPAtomicDirective(const OMPAtomicDirective &S) { bool IsSeqCst = S.getSingleClause(); OpenMPClauseKind Kind = OMPC_unknown; for (auto *C : S.clauses()) { // Find first clause (skip seq_cst clause, if it is first). if (C->getClauseKind() != OMPC_seq_cst) { Kind = C->getClauseKind(); break; } } const auto *CS = S.getAssociatedStmt()->IgnoreContainers(/*IgnoreCaptured=*/true); if (const auto *EWC = dyn_cast(CS)) { enterFullExpression(EWC); } // Processing for statements under 'atomic capture'. if (const auto *Compound = dyn_cast(CS)) { for (const auto *C : Compound->body()) { if (const auto *EWC = dyn_cast(C)) { enterFullExpression(EWC); } } } LexicalScope Scope(*this, S.getSourceRange()); auto &&CodeGen = [&S, Kind, IsSeqCst, CS](CodeGenFunction &CGF) { CGF.EmitStopPoint(CS); EmitOMPAtomicExpr(CGF, Kind, IsSeqCst, S.isPostfixUpdate(), S.getX(), S.getV(), S.getExpr(), S.getUpdateExpr(), S.isXLHSInRHSPart(), S.getLocStart()); }; CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_atomic, CodeGen); } void CodeGenFunction::EmitOMPTargetDirective(const OMPTargetDirective &S) { LexicalScope Scope(*this, S.getSourceRange()); const CapturedStmt &CS = *cast(S.getAssociatedStmt()); llvm::SmallVector CapturedVars; GenerateOpenMPCapturedVars(CS, CapturedVars); llvm::Function *Fn = nullptr; llvm::Constant *FnID = nullptr; // Check if we have any if clause associated with the directive. const Expr *IfCond = nullptr; if (auto *C = S.getSingleClause()) { IfCond = C->getCondition(); } // Check if we have any device clause associated with the directive. const Expr *Device = nullptr; if (auto *C = S.getSingleClause()) { Device = C->getDevice(); } // Check if we have an if clause whose conditional always evaluates to false // or if we do not have any targets specified. If so the target region is not // an offload entry point. bool IsOffloadEntry = true; if (IfCond) { bool Val; if (ConstantFoldsToSimpleInteger(IfCond, Val) && !Val) IsOffloadEntry = false; } if (CGM.getLangOpts().OMPTargetTriples.empty()) IsOffloadEntry = false; assert(CurFuncDecl && "No parent declaration for target region!"); StringRef ParentName; // In case we have Ctors/Dtors we use the complete type variant to produce // the mangling of the device outlined kernel. if (auto *D = dyn_cast(CurFuncDecl)) ParentName = CGM.getMangledName(GlobalDecl(D, Ctor_Complete)); else if (auto *D = dyn_cast(CurFuncDecl)) ParentName = CGM.getMangledName(GlobalDecl(D, Dtor_Complete)); else ParentName = CGM.getMangledName(GlobalDecl(cast(CurFuncDecl))); CGM.getOpenMPRuntime().emitTargetOutlinedFunction(S, ParentName, Fn, FnID, IsOffloadEntry); CGM.getOpenMPRuntime().emitTargetCall(*this, S, Fn, FnID, IfCond, Device, CapturedVars); } void CodeGenFunction::EmitOMPTeamsDirective(const OMPTeamsDirective &) { llvm_unreachable("CodeGen for 'omp teams' is not supported yet."); } void CodeGenFunction::EmitOMPCancellationPointDirective( const OMPCancellationPointDirective &S) { CGM.getOpenMPRuntime().emitCancellationPointCall(*this, S.getLocStart(), S.getCancelRegion()); } void CodeGenFunction::EmitOMPCancelDirective(const OMPCancelDirective &S) { const Expr *IfCond = nullptr; for (const auto *C : S.getClausesOfKind()) { if (C->getNameModifier() == OMPD_unknown || C->getNameModifier() == OMPD_cancel) { IfCond = C->getCondition(); break; } } CGM.getOpenMPRuntime().emitCancelCall(*this, S.getLocStart(), IfCond, S.getCancelRegion()); } CodeGenFunction::JumpDest CodeGenFunction::getOMPCancelDestination(OpenMPDirectiveKind Kind) { if (Kind == OMPD_parallel || Kind == OMPD_task) return ReturnBlock; assert(Kind == OMPD_for || Kind == OMPD_section || Kind == OMPD_sections || Kind == OMPD_parallel_sections || Kind == OMPD_parallel_for); return BreakContinueStack.back().BreakBlock; } // Generate the instructions for '#pragma omp target data' directive. void CodeGenFunction::EmitOMPTargetDataDirective( const OMPTargetDataDirective &S) { // emit the code inside the construct for now auto CS = cast(S.getAssociatedStmt()); CGM.getOpenMPRuntime().emitInlinedDirective( *this, OMPD_target_data, [&CS](CodeGenFunction &CGF) { CGF.EmitStmt(CS->getCapturedStmt()); }); } void CodeGenFunction::EmitOMPTaskLoopDirective(const OMPTaskLoopDirective &S) { // emit the code inside the construct for now auto CS = cast(S.getAssociatedStmt()); CGM.getOpenMPRuntime().emitInlinedDirective( *this, OMPD_taskloop, [&CS](CodeGenFunction &CGF) { CGF.EmitStmt(CS->getCapturedStmt()); }); } void CodeGenFunction::EmitOMPTaskLoopSimdDirective( const OMPTaskLoopSimdDirective &S) { // emit the code inside the construct for now auto CS = cast(S.getAssociatedStmt()); CGM.getOpenMPRuntime().emitInlinedDirective( *this, OMPD_taskloop_simd, [&CS](CodeGenFunction &CGF) { CGF.EmitStmt(CS->getCapturedStmt()); }); } Index: projects/clang380-import/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- projects/clang380-import/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp (revision 295858) +++ projects/clang380-import/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp (revision 295859) @@ -1,7601 +1,7586 @@ //===---- TargetInfo.cpp - Encapsulate target details -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // These classes wrap the information about a call or function // definition used to handle ABI compliancy. // //===----------------------------------------------------------------------===// #include "TargetInfo.h" #include "ABIInfo.h" #include "CGCXXABI.h" #include "CGValue.h" #include "CodeGenFunction.h" #include "clang/AST/RecordLayout.h" #include "clang/CodeGen/CGFunctionInfo.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Type.h" #include "llvm/Support/raw_ostream.h" #include // std::sort using namespace clang; using namespace CodeGen; static void AssignToArrayRange(CodeGen::CGBuilderTy &Builder, llvm::Value *Array, llvm::Value *Value, unsigned FirstIndex, unsigned LastIndex) { // Alternatively, we could emit this as a loop in the source. for (unsigned I = FirstIndex; I <= LastIndex; ++I) { llvm::Value *Cell = Builder.CreateConstInBoundsGEP1_32(Builder.getInt8Ty(), Array, I); Builder.CreateAlignedStore(Value, Cell, CharUnits::One()); } } static bool isAggregateTypeForABI(QualType T) { return !CodeGenFunction::hasScalarEvaluationKind(T) || T->isMemberFunctionPointerType(); } ABIArgInfo ABIInfo::getNaturalAlignIndirect(QualType Ty, bool ByRef, bool Realign, llvm::Type *Padding) const { return ABIArgInfo::getIndirect(getContext().getTypeAlignInChars(Ty), ByRef, Realign, Padding); } ABIArgInfo ABIInfo::getNaturalAlignIndirectInReg(QualType Ty, bool Realign) const { return ABIArgInfo::getIndirectInReg(getContext().getTypeAlignInChars(Ty), /*ByRef*/ false, Realign); } Address ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { return Address::invalid(); } ABIInfo::~ABIInfo() {} static CGCXXABI::RecordArgABI getRecordArgABI(const RecordType *RT, CGCXXABI &CXXABI) { const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); if (!RD) return CGCXXABI::RAA_Default; return CXXABI.getRecordArgABI(RD); } static CGCXXABI::RecordArgABI getRecordArgABI(QualType T, CGCXXABI &CXXABI) { const RecordType *RT = T->getAs(); if (!RT) return CGCXXABI::RAA_Default; return getRecordArgABI(RT, CXXABI); } /// Pass transparent unions as if they were the type of the first element. Sema /// should ensure that all elements of the union have the same "machine type". static QualType useFirstFieldIfTransparentUnion(QualType Ty) { if (const RecordType *UT = Ty->getAsUnionType()) { const RecordDecl *UD = UT->getDecl(); if (UD->hasAttr()) { assert(!UD->field_empty() && "sema created an empty transparent union"); return UD->field_begin()->getType(); } } return Ty; } CGCXXABI &ABIInfo::getCXXABI() const { return CGT.getCXXABI(); } ASTContext &ABIInfo::getContext() const { return CGT.getContext(); } llvm::LLVMContext &ABIInfo::getVMContext() const { return CGT.getLLVMContext(); } const llvm::DataLayout &ABIInfo::getDataLayout() const { return CGT.getDataLayout(); } const TargetInfo &ABIInfo::getTarget() const { return CGT.getTarget(); } bool ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const { return false; } bool ABIInfo::isHomogeneousAggregateSmallEnough(const Type *Base, uint64_t Members) const { return false; } bool ABIInfo::shouldSignExtUnsignedType(QualType Ty) const { return false; } void ABIArgInfo::dump() const { raw_ostream &OS = llvm::errs(); OS << "(ABIArgInfo Kind="; switch (TheKind) { case Direct: OS << "Direct Type="; if (llvm::Type *Ty = getCoerceToType()) Ty->print(OS); else OS << "null"; break; case Extend: OS << "Extend"; break; case Ignore: OS << "Ignore"; break; case InAlloca: OS << "InAlloca Offset=" << getInAllocaFieldIndex(); break; case Indirect: OS << "Indirect Align=" << getIndirectAlign().getQuantity() << " ByVal=" << getIndirectByVal() << " Realign=" << getIndirectRealign(); break; case Expand: OS << "Expand"; break; } OS << ")\n"; } // Dynamically round a pointer up to a multiple of the given alignment. static llvm::Value *emitRoundPointerUpToAlignment(CodeGenFunction &CGF, llvm::Value *Ptr, CharUnits Align) { llvm::Value *PtrAsInt = Ptr; // OverflowArgArea = (OverflowArgArea + Align - 1) & -Align; PtrAsInt = CGF.Builder.CreatePtrToInt(PtrAsInt, CGF.IntPtrTy); PtrAsInt = CGF.Builder.CreateAdd(PtrAsInt, llvm::ConstantInt::get(CGF.IntPtrTy, Align.getQuantity() - 1)); PtrAsInt = CGF.Builder.CreateAnd(PtrAsInt, llvm::ConstantInt::get(CGF.IntPtrTy, -Align.getQuantity())); PtrAsInt = CGF.Builder.CreateIntToPtr(PtrAsInt, Ptr->getType(), Ptr->getName() + ".aligned"); return PtrAsInt; } /// Emit va_arg for a platform using the common void* representation, /// where arguments are simply emitted in an array of slots on the stack. /// /// This version implements the core direct-value passing rules. /// /// \param SlotSize - The size and alignment of a stack slot. /// Each argument will be allocated to a multiple of this number of /// slots, and all the slots will be aligned to this value. /// \param AllowHigherAlign - The slot alignment is not a cap; /// an argument type with an alignment greater than the slot size /// will be emitted on a higher-alignment address, potentially /// leaving one or more empty slots behind as padding. If this /// is false, the returned address might be less-aligned than /// DirectAlign. static Address emitVoidPtrDirectVAArg(CodeGenFunction &CGF, Address VAListAddr, llvm::Type *DirectTy, CharUnits DirectSize, CharUnits DirectAlign, CharUnits SlotSize, bool AllowHigherAlign) { // Cast the element type to i8* if necessary. Some platforms define // va_list as a struct containing an i8* instead of just an i8*. if (VAListAddr.getElementType() != CGF.Int8PtrTy) VAListAddr = CGF.Builder.CreateElementBitCast(VAListAddr, CGF.Int8PtrTy); llvm::Value *Ptr = CGF.Builder.CreateLoad(VAListAddr, "argp.cur"); // If the CC aligns values higher than the slot size, do so if needed. Address Addr = Address::invalid(); if (AllowHigherAlign && DirectAlign > SlotSize) { Addr = Address(emitRoundPointerUpToAlignment(CGF, Ptr, DirectAlign), DirectAlign); } else { Addr = Address(Ptr, SlotSize); } // Advance the pointer past the argument, then store that back. CharUnits FullDirectSize = DirectSize.RoundUpToAlignment(SlotSize); llvm::Value *NextPtr = CGF.Builder.CreateConstInBoundsByteGEP(Addr.getPointer(), FullDirectSize, "argp.next"); CGF.Builder.CreateStore(NextPtr, VAListAddr); // If the argument is smaller than a slot, and this is a big-endian // target, the argument will be right-adjusted in its slot. if (DirectSize < SlotSize && CGF.CGM.getDataLayout().isBigEndian()) { Addr = CGF.Builder.CreateConstInBoundsByteGEP(Addr, SlotSize - DirectSize); } Addr = CGF.Builder.CreateElementBitCast(Addr, DirectTy); return Addr; } /// Emit va_arg for a platform using the common void* representation, /// where arguments are simply emitted in an array of slots on the stack. /// /// \param IsIndirect - Values of this type are passed indirectly. /// \param ValueInfo - The size and alignment of this type, generally /// computed with getContext().getTypeInfoInChars(ValueTy). /// \param SlotSizeAndAlign - The size and alignment of a stack slot. /// Each argument will be allocated to a multiple of this number of /// slots, and all the slots will be aligned to this value. /// \param AllowHigherAlign - The slot alignment is not a cap; /// an argument type with an alignment greater than the slot size /// will be emitted on a higher-alignment address, potentially /// leaving one or more empty slots behind as padding. static Address emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType ValueTy, bool IsIndirect, std::pair ValueInfo, CharUnits SlotSizeAndAlign, bool AllowHigherAlign) { // The size and alignment of the value that was passed directly. CharUnits DirectSize, DirectAlign; if (IsIndirect) { DirectSize = CGF.getPointerSize(); DirectAlign = CGF.getPointerAlign(); } else { DirectSize = ValueInfo.first; DirectAlign = ValueInfo.second; } // Cast the address we've calculated to the right type. llvm::Type *DirectTy = CGF.ConvertTypeForMem(ValueTy); if (IsIndirect) DirectTy = DirectTy->getPointerTo(0); Address Addr = emitVoidPtrDirectVAArg(CGF, VAListAddr, DirectTy, DirectSize, DirectAlign, SlotSizeAndAlign, AllowHigherAlign); if (IsIndirect) { Addr = Address(CGF.Builder.CreateLoad(Addr), ValueInfo.second); } return Addr; } static Address emitMergePHI(CodeGenFunction &CGF, Address Addr1, llvm::BasicBlock *Block1, Address Addr2, llvm::BasicBlock *Block2, const llvm::Twine &Name = "") { assert(Addr1.getType() == Addr2.getType()); llvm::PHINode *PHI = CGF.Builder.CreatePHI(Addr1.getType(), 2, Name); PHI->addIncoming(Addr1.getPointer(), Block1); PHI->addIncoming(Addr2.getPointer(), Block2); CharUnits Align = std::min(Addr1.getAlignment(), Addr2.getAlignment()); return Address(PHI, Align); } TargetCodeGenInfo::~TargetCodeGenInfo() { delete Info; } // If someone can figure out a general rule for this, that would be great. // It's probably just doomed to be platform-dependent, though. unsigned TargetCodeGenInfo::getSizeOfUnwindException() const { // Verified for: // x86-64 FreeBSD, Linux, Darwin // x86-32 FreeBSD, Linux, Darwin // PowerPC Linux, Darwin // ARM Darwin (*not* EABI) // AArch64 Linux return 32; } bool TargetCodeGenInfo::isNoProtoCallVariadic(const CallArgList &args, const FunctionNoProtoType *fnType) const { // The following conventions are known to require this to be false: // x86_stdcall // MIPS // For everything else, we just prefer false unless we opt out. return false; } void TargetCodeGenInfo::getDependentLibraryOption(llvm::StringRef Lib, llvm::SmallString<24> &Opt) const { // This assumes the user is passing a library name like "rt" instead of a // filename like "librt.a/so", and that they don't care whether it's static or // dynamic. Opt = "-l"; Opt += Lib; } static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays); /// isEmptyField - Return true iff a the field is "empty", that is it /// is an unnamed bit-field or an (array of) empty record(s). static bool isEmptyField(ASTContext &Context, const FieldDecl *FD, bool AllowArrays) { if (FD->isUnnamedBitfield()) return true; QualType FT = FD->getType(); // Constant arrays of empty records count as empty, strip them off. // Constant arrays of zero length always count as empty. if (AllowArrays) while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) { if (AT->getSize() == 0) return true; FT = AT->getElementType(); } const RecordType *RT = FT->getAs(); if (!RT) return false; // C++ record fields are never empty, at least in the Itanium ABI. // // FIXME: We should use a predicate for whether this behavior is true in the // current ABI. if (isa(RT->getDecl())) return false; return isEmptyRecord(Context, FT, AllowArrays); } /// isEmptyRecord - Return true iff a structure contains only empty /// fields. Note that a structure with a flexible array member is not /// considered empty. static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) { const RecordType *RT = T->getAs(); if (!RT) return 0; const RecordDecl *RD = RT->getDecl(); if (RD->hasFlexibleArrayMember()) return false; // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) for (const auto &I : CXXRD->bases()) if (!isEmptyRecord(Context, I.getType(), true)) return false; for (const auto *I : RD->fields()) if (!isEmptyField(Context, I, AllowArrays)) return false; return true; } /// isSingleElementStruct - Determine if a structure is a "single /// element struct", i.e. it has exactly one non-empty field or /// exactly one field which is itself a single element /// struct. Structures with flexible array members are never /// considered single element structs. /// /// \return The field declaration for the single non-empty field, if /// it exists. static const Type *isSingleElementStruct(QualType T, ASTContext &Context) { const RecordType *RT = T->getAs(); if (!RT) return nullptr; const RecordDecl *RD = RT->getDecl(); if (RD->hasFlexibleArrayMember()) return nullptr; const Type *Found = nullptr; // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { for (const auto &I : CXXRD->bases()) { // Ignore empty records. if (isEmptyRecord(Context, I.getType(), true)) continue; // If we already found an element then this isn't a single-element struct. if (Found) return nullptr; // If this is non-empty and not a single element struct, the composite // cannot be a single element struct. Found = isSingleElementStruct(I.getType(), Context); if (!Found) return nullptr; } } // Check for single element. for (const auto *FD : RD->fields()) { QualType FT = FD->getType(); // Ignore empty fields. if (isEmptyField(Context, FD, true)) continue; // If we already found an element then this isn't a single-element // struct. if (Found) return nullptr; // Treat single element arrays as the element. while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) { if (AT->getSize().getZExtValue() != 1) break; FT = AT->getElementType(); } if (!isAggregateTypeForABI(FT)) { Found = FT.getTypePtr(); } else { Found = isSingleElementStruct(FT, Context); if (!Found) return nullptr; } } // We don't consider a struct a single-element struct if it has // padding beyond the element type. if (Found && Context.getTypeSize(Found) != Context.getTypeSize(T)) return nullptr; return Found; } static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) { // Treat complex types as the element type. if (const ComplexType *CTy = Ty->getAs()) Ty = CTy->getElementType(); // Check for a type which we know has a simple scalar argument-passing // convention without any padding. (We're specifically looking for 32 // and 64-bit integer and integer-equivalents, float, and double.) if (!Ty->getAs() && !Ty->hasPointerRepresentation() && !Ty->isEnumeralType() && !Ty->isBlockPointerType()) return false; uint64_t Size = Context.getTypeSize(Ty); return Size == 32 || Size == 64; } /// canExpandIndirectArgument - Test whether an argument type which is to be /// passed indirectly (on the stack) would have the equivalent layout if it was /// expanded into separate arguments. If so, we prefer to do the latter to avoid /// inhibiting optimizations. /// // FIXME: This predicate is missing many cases, currently it just follows // llvm-gcc (checks that all fields are 32-bit or 64-bit primitive types). We // should probably make this smarter, or better yet make the LLVM backend // capable of handling it. static bool canExpandIndirectArgument(QualType Ty, ASTContext &Context) { // We can only expand structure types. const RecordType *RT = Ty->getAs(); if (!RT) return false; // We can only expand (C) structures. // // FIXME: This needs to be generalized to handle classes as well. const RecordDecl *RD = RT->getDecl(); if (!RD->isStruct()) return false; // We try to expand CLike CXXRecordDecl. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { if (!CXXRD->isCLike()) return false; } uint64_t Size = 0; for (const auto *FD : RD->fields()) { if (!is32Or64BitBasicType(FD->getType(), Context)) return false; // FIXME: Reject bit-fields wholesale; there are two problems, we don't know // how to expand them yet, and the predicate for telling if a bitfield still // counts as "basic" is more complicated than what we were doing previously. if (FD->isBitField()) return false; Size += Context.getTypeSize(FD->getType()); } // Make sure there are not any holes in the struct. if (Size != Context.getTypeSize(Ty)) return false; return true; } namespace { /// DefaultABIInfo - The default implementation for ABI specific /// details. This implementation provides information which results in /// self-consistent and sensible LLVM IR generation, but does not /// conform to any particular ABI. class DefaultABIInfo : public ABIInfo { public: DefaultABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {} ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType RetTy) const; void computeInfo(CGFunctionInfo &FI) const override { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type); } Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; }; class DefaultTargetCodeGenInfo : public TargetCodeGenInfo { public: DefaultTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) : TargetCodeGenInfo(new DefaultABIInfo(CGT)) {} }; Address DefaultABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { return Address::invalid(); } ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const { Ty = useFirstFieldIfTransparentUnion(Ty); if (isAggregateTypeForABI(Ty)) { // Records with non-trivial destructors/copy-constructors should not be // passed by value. if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); return getNaturalAlignIndirect(Ty); } // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); if (isAggregateTypeForABI(RetTy)) return getNaturalAlignIndirect(RetTy); // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } //===----------------------------------------------------------------------===// // WebAssembly ABI Implementation // // This is a very simple ABI that relies a lot on DefaultABIInfo. //===----------------------------------------------------------------------===// class WebAssemblyABIInfo final : public DefaultABIInfo { public: explicit WebAssemblyABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} private: ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType Ty) const; // DefaultABIInfo's classifyReturnType and classifyArgumentType are // non-virtual, but computeInfo is virtual, so we overload that. void computeInfo(CGFunctionInfo &FI) const override { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &Arg : FI.arguments()) Arg.info = classifyArgumentType(Arg.type); } }; class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo { public: explicit WebAssemblyTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) : TargetCodeGenInfo(new WebAssemblyABIInfo(CGT)) {} }; /// \brief Classify argument of given type \p Ty. ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const { Ty = useFirstFieldIfTransparentUnion(Ty); if (isAggregateTypeForABI(Ty)) { // Records with non-trivial destructors/copy-constructors should not be // passed by value. if (auto RAA = getRecordArgABI(Ty, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); // Ignore empty structs/unions. if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); // Lower single-element structs to just pass a regular value. TODO: We // could do reasonable-size multiple-element structs too, using getExpand(), // though watch out for things like bitfields. if (const Type *SeltTy = isSingleElementStruct(Ty, getContext())) return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); } // Otherwise just do the default thing. return DefaultABIInfo::classifyArgumentType(Ty); } ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy) const { if (isAggregateTypeForABI(RetTy)) { // Records with non-trivial destructors/copy-constructors should not be // returned by value. if (!getRecordArgABI(RetTy, getCXXABI())) { // Ignore empty structs/unions. if (isEmptyRecord(getContext(), RetTy, true)) return ABIArgInfo::getIgnore(); // Lower single-element structs to just return a regular value. TODO: We // could do reasonable-size multiple-element structs too, using // ABIArgInfo::getDirect(). if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext())) return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); } } // Otherwise just do the default thing. return DefaultABIInfo::classifyReturnType(RetTy); } //===----------------------------------------------------------------------===// // le32/PNaCl bitcode ABI Implementation // // This is a simplified version of the x86_32 ABI. Arguments and return values // are always passed on the stack. //===----------------------------------------------------------------------===// class PNaClABIInfo : public ABIInfo { public: PNaClABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {} ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType RetTy) const; void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; }; class PNaClTargetCodeGenInfo : public TargetCodeGenInfo { public: PNaClTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) : TargetCodeGenInfo(new PNaClABIInfo(CGT)) {} }; void PNaClABIInfo::computeInfo(CGFunctionInfo &FI) const { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type); } Address PNaClABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { return Address::invalid(); } /// \brief Classify argument of given type \p Ty. ABIArgInfo PNaClABIInfo::classifyArgumentType(QualType Ty) const { if (isAggregateTypeForABI(Ty)) { if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); return getNaturalAlignIndirect(Ty); } else if (const EnumType *EnumTy = Ty->getAs()) { // Treat an enum type as its underlying type. Ty = EnumTy->getDecl()->getIntegerType(); } else if (Ty->isFloatingType()) { // Floating-point types don't go inreg. return ABIArgInfo::getDirect(); } return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } ABIArgInfo PNaClABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); // In the PNaCl ABI we always return records/structures on the stack. if (isAggregateTypeForABI(RetTy)) return getNaturalAlignIndirect(RetTy); // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } /// IsX86_MMXType - Return true if this is an MMX type. bool IsX86_MMXType(llvm::Type *IRType) { // Return true if the type is an MMX type <2 x i32>, <4 x i16>, or <8 x i8>. return IRType->isVectorTy() && IRType->getPrimitiveSizeInBits() == 64 && cast(IRType)->getElementType()->isIntegerTy() && IRType->getScalarSizeInBits() != 64; } static llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF, StringRef Constraint, llvm::Type* Ty) { if ((Constraint == "y" || Constraint == "&y") && Ty->isVectorTy()) { if (cast(Ty)->getBitWidth() != 64) { // Invalid MMX constraint return nullptr; } return llvm::Type::getX86_MMXTy(CGF.getLLVMContext()); } // No operation needed return Ty; } /// Returns true if this type can be passed in SSE registers with the /// X86_VectorCall calling convention. Shared between x86_32 and x86_64. static bool isX86VectorTypeForVectorCall(ASTContext &Context, QualType Ty) { if (const BuiltinType *BT = Ty->getAs()) { if (BT->isFloatingPoint() && BT->getKind() != BuiltinType::Half) return true; } else if (const VectorType *VT = Ty->getAs()) { // vectorcall can pass XMM, YMM, and ZMM vectors. We don't pass SSE1 MMX // registers specially. unsigned VecSize = Context.getTypeSize(VT); if (VecSize == 128 || VecSize == 256 || VecSize == 512) return true; } return false; } /// Returns true if this aggregate is small enough to be passed in SSE registers /// in the X86_VectorCall calling convention. Shared between x86_32 and x86_64. static bool isX86VectorCallAggregateSmallEnough(uint64_t NumMembers) { return NumMembers <= 4; } //===----------------------------------------------------------------------===// // X86-32 ABI Implementation //===----------------------------------------------------------------------===// /// \brief Similar to llvm::CCState, but for Clang. struct CCState { CCState(unsigned CC) : CC(CC), FreeRegs(0), FreeSSERegs(0) {} unsigned CC; unsigned FreeRegs; unsigned FreeSSERegs; }; /// X86_32ABIInfo - The X86-32 ABI information. class X86_32ABIInfo : public ABIInfo { enum Class { Integer, Float }; static const unsigned MinABIStackAlignInBytes = 4; bool IsDarwinVectorABI; bool IsRetSmallStructInRegABI; bool IsWin32StructABI; bool IsSoftFloatABI; bool IsMCUABI; unsigned DefaultNumRegisterParameters; static bool isRegisterSize(unsigned Size) { return (Size == 8 || Size == 16 || Size == 32 || Size == 64); } bool isHomogeneousAggregateBaseType(QualType Ty) const override { // FIXME: Assumes vectorcall is in use. return isX86VectorTypeForVectorCall(getContext(), Ty); } bool isHomogeneousAggregateSmallEnough(const Type *Ty, uint64_t NumMembers) const override { // FIXME: Assumes vectorcall is in use. return isX86VectorCallAggregateSmallEnough(NumMembers); } bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context) const; /// getIndirectResult - Give a source type \arg Ty, return a suitable result /// such that the argument will be passed in memory. ABIArgInfo getIndirectResult(QualType Ty, bool ByVal, CCState &State) const; ABIArgInfo getIndirectReturnResult(QualType Ty, CCState &State) const; /// \brief Return the alignment to use for the given type on the stack. unsigned getTypeStackAlignInBytes(QualType Ty, unsigned Align) const; Class classify(QualType Ty) const; ABIArgInfo classifyReturnType(QualType RetTy, CCState &State) const; ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const; /// \brief Updates the number of available free registers, returns /// true if any registers were allocated. bool updateFreeRegs(QualType Ty, CCState &State) const; bool shouldAggregateUseDirect(QualType Ty, CCState &State, bool &InReg, bool &NeedsPadding) const; bool shouldPrimitiveUseInReg(QualType Ty, CCState &State) const; /// \brief Rewrite the function info so that all memory arguments use /// inalloca. void rewriteWithInAlloca(CGFunctionInfo &FI) const; void addFieldToArgStruct(SmallVector &FrameFields, CharUnits &StackOffset, ABIArgInfo &Info, QualType Type) const; public: void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool DarwinVectorABI, bool RetSmallStructInRegABI, bool Win32StructABI, unsigned NumRegisterParameters, bool SoftFloatABI) : ABIInfo(CGT), IsDarwinVectorABI(DarwinVectorABI), IsRetSmallStructInRegABI(RetSmallStructInRegABI), IsWin32StructABI(Win32StructABI), IsSoftFloatABI(SoftFloatABI), IsMCUABI(CGT.getTarget().getTriple().isOSIAMCU()), DefaultNumRegisterParameters(NumRegisterParameters) {} }; class X86_32TargetCodeGenInfo : public TargetCodeGenInfo { public: X86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool DarwinVectorABI, bool RetSmallStructInRegABI, bool Win32StructABI, unsigned NumRegisterParameters, bool SoftFloatABI) : TargetCodeGenInfo(new X86_32ABIInfo( CGT, DarwinVectorABI, RetSmallStructInRegABI, Win32StructABI, NumRegisterParameters, SoftFloatABI)) {} static bool isStructReturnInRegABI( const llvm::Triple &Triple, const CodeGenOptions &Opts); void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override; int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override { // Darwin uses different dwarf register numbers for EH. if (CGM.getTarget().getTriple().isOSDarwin()) return 5; return 4; } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF, StringRef Constraint, llvm::Type* Ty) const override { return X86AdjustInlineAsmType(CGF, Constraint, Ty); } void addReturnRegisterOutputs(CodeGenFunction &CGF, LValue ReturnValue, std::string &Constraints, std::vector &ResultRegTypes, std::vector &ResultTruncRegTypes, std::vector &ResultRegDests, std::string &AsmString, unsigned NumOutputs) const override; llvm::Constant * getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const override { unsigned Sig = (0xeb << 0) | // jmp rel8 (0x06 << 8) | // .+0x08 ('F' << 16) | ('T' << 24); return llvm::ConstantInt::get(CGM.Int32Ty, Sig); } }; } /// Rewrite input constraint references after adding some output constraints. /// In the case where there is one output and one input and we add one output, /// we need to replace all operand references greater than or equal to 1: /// mov $0, $1 /// mov eax, $1 /// The result will be: /// mov $0, $2 /// mov eax, $2 static void rewriteInputConstraintReferences(unsigned FirstIn, unsigned NumNewOuts, std::string &AsmString) { std::string Buf; llvm::raw_string_ostream OS(Buf); size_t Pos = 0; while (Pos < AsmString.size()) { size_t DollarStart = AsmString.find('$', Pos); if (DollarStart == std::string::npos) DollarStart = AsmString.size(); size_t DollarEnd = AsmString.find_first_not_of('$', DollarStart); if (DollarEnd == std::string::npos) DollarEnd = AsmString.size(); OS << StringRef(&AsmString[Pos], DollarEnd - Pos); Pos = DollarEnd; size_t NumDollars = DollarEnd - DollarStart; if (NumDollars % 2 != 0 && Pos < AsmString.size()) { // We have an operand reference. size_t DigitStart = Pos; size_t DigitEnd = AsmString.find_first_not_of("0123456789", DigitStart); if (DigitEnd == std::string::npos) DigitEnd = AsmString.size(); StringRef OperandStr(&AsmString[DigitStart], DigitEnd - DigitStart); unsigned OperandIndex; if (!OperandStr.getAsInteger(10, OperandIndex)) { if (OperandIndex >= FirstIn) OperandIndex += NumNewOuts; OS << OperandIndex; } else { OS << OperandStr; } Pos = DigitEnd; } } AsmString = std::move(OS.str()); } /// Add output constraints for EAX:EDX because they are return registers. void X86_32TargetCodeGenInfo::addReturnRegisterOutputs( CodeGenFunction &CGF, LValue ReturnSlot, std::string &Constraints, std::vector &ResultRegTypes, std::vector &ResultTruncRegTypes, std::vector &ResultRegDests, std::string &AsmString, unsigned NumOutputs) const { uint64_t RetWidth = CGF.getContext().getTypeSize(ReturnSlot.getType()); // Use the EAX constraint if the width is 32 or smaller and EAX:EDX if it is // larger. if (!Constraints.empty()) Constraints += ','; if (RetWidth <= 32) { Constraints += "={eax}"; ResultRegTypes.push_back(CGF.Int32Ty); } else { // Use the 'A' constraint for EAX:EDX. Constraints += "=A"; ResultRegTypes.push_back(CGF.Int64Ty); } // Truncate EAX or EAX:EDX to an integer of the appropriate size. llvm::Type *CoerceTy = llvm::IntegerType::get(CGF.getLLVMContext(), RetWidth); ResultTruncRegTypes.push_back(CoerceTy); // Coerce the integer by bitcasting the return slot pointer. ReturnSlot.setAddress(CGF.Builder.CreateBitCast(ReturnSlot.getAddress(), CoerceTy->getPointerTo())); ResultRegDests.push_back(ReturnSlot); rewriteInputConstraintReferences(NumOutputs, 1, AsmString); } /// shouldReturnTypeInRegister - Determine if the given type should be /// returned in a register (for the Darwin and MCU ABI). bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, ASTContext &Context) const { uint64_t Size = Context.getTypeSize(Ty); // For i386, type must be register sized. // For the MCU ABI, it only needs to be <= 8-byte if ((IsMCUABI && Size > 64) || (!IsMCUABI && !isRegisterSize(Size))) return false; if (Ty->isVectorType()) { // 64- and 128- bit vectors inside structures are not returned in // registers. if (Size == 64 || Size == 128) return false; return true; } // If this is a builtin, pointer, enum, complex type, member pointer, or // member function pointer it is ok. if (Ty->getAs() || Ty->hasPointerRepresentation() || Ty->isAnyComplexType() || Ty->isEnumeralType() || Ty->isBlockPointerType() || Ty->isMemberPointerType()) return true; // Arrays are treated like records. if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) return shouldReturnTypeInRegister(AT->getElementType(), Context); // Otherwise, it must be a record type. const RecordType *RT = Ty->getAs(); if (!RT) return false; // FIXME: Traverse bases here too. // Structure types are passed in register if all fields would be // passed in a register. for (const auto *FD : RT->getDecl()->fields()) { // Empty fields are ignored. if (isEmptyField(Context, FD, true)) continue; // Check fields recursively. if (!shouldReturnTypeInRegister(FD->getType(), Context)) return false; } return true; } ABIArgInfo X86_32ABIInfo::getIndirectReturnResult(QualType RetTy, CCState &State) const { // If the return value is indirect, then the hidden argument is consuming one // integer register. if (State.FreeRegs) { --State.FreeRegs; if (!IsMCUABI) return getNaturalAlignIndirectInReg(RetTy); } return getNaturalAlignIndirect(RetTy, /*ByVal=*/false); } ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, CCState &State) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); const Type *Base = nullptr; uint64_t NumElts = 0; if (State.CC == llvm::CallingConv::X86_VectorCall && isHomogeneousAggregate(RetTy, Base, NumElts)) { // The LLVM struct type for such an aggregate should lower properly. return ABIArgInfo::getDirect(); } if (const VectorType *VT = RetTy->getAs()) { // On Darwin, some vectors are returned in registers. if (IsDarwinVectorABI) { uint64_t Size = getContext().getTypeSize(RetTy); // 128-bit vectors are a special case; they are returned in // registers and we need to make sure to pick a type the LLVM // backend will like. if (Size == 128) return ABIArgInfo::getDirect(llvm::VectorType::get( llvm::Type::getInt64Ty(getVMContext()), 2)); // Always return in register if it fits in a general purpose // register, or if it is 64 bits and has a single element. if ((Size == 8 || Size == 16 || Size == 32) || (Size == 64 && VT->getNumElements() == 1)) return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); return getIndirectReturnResult(RetTy, State); } return ABIArgInfo::getDirect(); } if (isAggregateTypeForABI(RetTy)) { if (const RecordType *RT = RetTy->getAs()) { // Structures with flexible arrays are always indirect. if (RT->getDecl()->hasFlexibleArrayMember()) return getIndirectReturnResult(RetTy, State); } // If specified, structs and unions are always indirect. if (!IsRetSmallStructInRegABI && !RetTy->isAnyComplexType()) return getIndirectReturnResult(RetTy, State); // Small structures which are register sized are generally returned // in a register. if (shouldReturnTypeInRegister(RetTy, getContext())) { uint64_t Size = getContext().getTypeSize(RetTy); // As a special-case, if the struct is a "single-element" struct, and // the field is of type "float" or "double", return it in a // floating-point register. (MSVC does not apply this special case.) // We apply a similar transformation for pointer types to improve the // quality of the generated IR. if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext())) if ((!IsWin32StructABI && SeltTy->isRealFloatingType()) || SeltTy->hasPointerRepresentation()) return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); // FIXME: We should be able to narrow this integer in cases with dead // padding. return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),Size)); } return getIndirectReturnResult(RetTy, State); } // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } static bool isSSEVectorType(ASTContext &Context, QualType Ty) { return Ty->getAs() && Context.getTypeSize(Ty) == 128; } static bool isRecordWithSSEVectorType(ASTContext &Context, QualType Ty) { const RecordType *RT = Ty->getAs(); if (!RT) return 0; const RecordDecl *RD = RT->getDecl(); // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) for (const auto &I : CXXRD->bases()) if (!isRecordWithSSEVectorType(Context, I.getType())) return false; for (const auto *i : RD->fields()) { QualType FT = i->getType(); if (isSSEVectorType(Context, FT)) return true; if (isRecordWithSSEVectorType(Context, FT)) return true; } return false; } unsigned X86_32ABIInfo::getTypeStackAlignInBytes(QualType Ty, unsigned Align) const { // Otherwise, if the alignment is less than or equal to the minimum ABI // alignment, just use the default; the backend will handle this. if (Align <= MinABIStackAlignInBytes) return 0; // Use default alignment. // On non-Darwin, the stack type alignment is always 4. if (!IsDarwinVectorABI) { // Set explicit alignment, since we may need to realign the top. return MinABIStackAlignInBytes; } // Otherwise, if the type contains an SSE vector type, the alignment is 16. if (Align >= 16 && (isSSEVectorType(getContext(), Ty) || isRecordWithSSEVectorType(getContext(), Ty))) return 16; return MinABIStackAlignInBytes; } ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal, CCState &State) const { if (!ByVal) { if (State.FreeRegs) { --State.FreeRegs; // Non-byval indirects just use one pointer. if (!IsMCUABI) return getNaturalAlignIndirectInReg(Ty); } return getNaturalAlignIndirect(Ty, false); } // Compute the byval alignment. unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8; unsigned StackAlign = getTypeStackAlignInBytes(Ty, TypeAlign); if (StackAlign == 0) return ABIArgInfo::getIndirect(CharUnits::fromQuantity(4), /*ByVal=*/true); // If the stack alignment is less than the type alignment, realign the // argument. bool Realign = TypeAlign > StackAlign; return ABIArgInfo::getIndirect(CharUnits::fromQuantity(StackAlign), /*ByVal=*/true, Realign); } X86_32ABIInfo::Class X86_32ABIInfo::classify(QualType Ty) const { const Type *T = isSingleElementStruct(Ty, getContext()); if (!T) T = Ty.getTypePtr(); if (const BuiltinType *BT = T->getAs()) { BuiltinType::Kind K = BT->getKind(); if (K == BuiltinType::Float || K == BuiltinType::Double) return Float; } return Integer; } bool X86_32ABIInfo::updateFreeRegs(QualType Ty, CCState &State) const { if (!IsSoftFloatABI) { Class C = classify(Ty); if (C == Float) return false; } unsigned Size = getContext().getTypeSize(Ty); unsigned SizeInRegs = (Size + 31) / 32; if (SizeInRegs == 0) return false; if (!IsMCUABI) { if (SizeInRegs > State.FreeRegs) { State.FreeRegs = 0; return false; } } else { // The MCU psABI allows passing parameters in-reg even if there are // earlier parameters that are passed on the stack. Also, // it does not allow passing >8-byte structs in-register, // even if there are 3 free registers available. if (SizeInRegs > State.FreeRegs || SizeInRegs > 2) return false; } State.FreeRegs -= SizeInRegs; return true; } bool X86_32ABIInfo::shouldAggregateUseDirect(QualType Ty, CCState &State, bool &InReg, bool &NeedsPadding) const { NeedsPadding = false; InReg = !IsMCUABI; if (!updateFreeRegs(Ty, State)) return false; if (IsMCUABI) return true; if (State.CC == llvm::CallingConv::X86_FastCall || State.CC == llvm::CallingConv::X86_VectorCall) { if (getContext().getTypeSize(Ty) <= 32 && State.FreeRegs) NeedsPadding = true; return false; } return true; } bool X86_32ABIInfo::shouldPrimitiveUseInReg(QualType Ty, CCState &State) const { if (!updateFreeRegs(Ty, State)) return false; if (IsMCUABI) return false; if (State.CC == llvm::CallingConv::X86_FastCall || State.CC == llvm::CallingConv::X86_VectorCall) { if (getContext().getTypeSize(Ty) > 32) return false; return (Ty->isIntegralOrEnumerationType() || Ty->isPointerType() || Ty->isReferenceType()); } return true; } ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, CCState &State) const { // FIXME: Set alignment on indirect arguments. Ty = useFirstFieldIfTransparentUnion(Ty); // Check with the C++ ABI first. const RecordType *RT = Ty->getAs(); if (RT) { CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()); if (RAA == CGCXXABI::RAA_Indirect) { return getIndirectResult(Ty, false, State); } else if (RAA == CGCXXABI::RAA_DirectInMemory) { // The field index doesn't matter, we'll fix it up later. return ABIArgInfo::getInAlloca(/*FieldIndex=*/0); } } // vectorcall adds the concept of a homogenous vector aggregate, similar // to other targets. const Type *Base = nullptr; uint64_t NumElts = 0; if (State.CC == llvm::CallingConv::X86_VectorCall && isHomogeneousAggregate(Ty, Base, NumElts)) { if (State.FreeSSERegs >= NumElts) { State.FreeSSERegs -= NumElts; if (Ty->isBuiltinType() || Ty->isVectorType()) return ABIArgInfo::getDirect(); return ABIArgInfo::getExpand(); } return getIndirectResult(Ty, /*ByVal=*/false, State); } if (isAggregateTypeForABI(Ty)) { if (RT) { // Structs are always byval on win32, regardless of what they contain. if (IsWin32StructABI) return getIndirectResult(Ty, true, State); // Structures with flexible arrays are always indirect. if (RT->getDecl()->hasFlexibleArrayMember()) return getIndirectResult(Ty, true, State); } // Ignore empty structs/unions. if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); llvm::LLVMContext &LLVMContext = getVMContext(); llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext); bool NeedsPadding, InReg; if (shouldAggregateUseDirect(Ty, State, InReg, NeedsPadding)) { unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32; SmallVector Elements(SizeInRegs, Int32); llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements); if (InReg) return ABIArgInfo::getDirectInReg(Result); else return ABIArgInfo::getDirect(Result); } llvm::IntegerType *PaddingType = NeedsPadding ? Int32 : nullptr; // Expand small (<= 128-bit) record types when we know that the stack layout // of those arguments will match the struct. This is important because the // LLVM backend isn't smart enough to remove byval, which inhibits many // optimizations. // Don't do this for the MCU if there are still free integer registers // (see X86_64 ABI for full explanation). if (getContext().getTypeSize(Ty) <= 4*32 && canExpandIndirectArgument(Ty, getContext()) && (!IsMCUABI || State.FreeRegs == 0)) return ABIArgInfo::getExpandWithPadding( State.CC == llvm::CallingConv::X86_FastCall || State.CC == llvm::CallingConv::X86_VectorCall, PaddingType); return getIndirectResult(Ty, true, State); } if (const VectorType *VT = Ty->getAs()) { // On Darwin, some vectors are passed in memory, we handle this by passing // it as an i8/i16/i32/i64. if (IsDarwinVectorABI) { uint64_t Size = getContext().getTypeSize(Ty); if ((Size == 8 || Size == 16 || Size == 32) || (Size == 64 && VT->getNumElements() == 1)) return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); } if (IsX86_MMXType(CGT.ConvertType(Ty))) return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), 64)); return ABIArgInfo::getDirect(); } if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); bool InReg = shouldPrimitiveUseInReg(Ty, State); if (Ty->isPromotableIntegerType()) { if (InReg) return ABIArgInfo::getExtendInReg(); return ABIArgInfo::getExtend(); } if (InReg) return ABIArgInfo::getDirectInReg(); return ABIArgInfo::getDirect(); } void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const { CCState State(FI.getCallingConvention()); if (IsMCUABI) State.FreeRegs = 3; else if (State.CC == llvm::CallingConv::X86_FastCall) State.FreeRegs = 2; else if (State.CC == llvm::CallingConv::X86_VectorCall) { State.FreeRegs = 2; State.FreeSSERegs = 6; } else if (FI.getHasRegParm()) State.FreeRegs = FI.getRegParm(); else State.FreeRegs = DefaultNumRegisterParameters; if (!getCXXABI().classifyReturnType(FI)) { FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), State); } else if (FI.getReturnInfo().isIndirect()) { // The C++ ABI is not aware of register usage, so we have to check if the // return value was sret and put it in a register ourselves if appropriate. if (State.FreeRegs) { --State.FreeRegs; // The sret parameter consumes a register. if (!IsMCUABI) FI.getReturnInfo().setInReg(true); } } // The chain argument effectively gives us another free register. if (FI.isChainCall()) ++State.FreeRegs; bool UsedInAlloca = false; for (auto &I : FI.arguments()) { I.info = classifyArgumentType(I.type, State); UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca); } // If we needed to use inalloca for any argument, do a second pass and rewrite // all the memory arguments to use inalloca. if (UsedInAlloca) rewriteWithInAlloca(FI); } void X86_32ABIInfo::addFieldToArgStruct(SmallVector &FrameFields, CharUnits &StackOffset, ABIArgInfo &Info, QualType Type) const { // Arguments are always 4-byte-aligned. CharUnits FieldAlign = CharUnits::fromQuantity(4); assert(StackOffset.isMultipleOf(FieldAlign) && "unaligned inalloca struct"); Info = ABIArgInfo::getInAlloca(FrameFields.size()); FrameFields.push_back(CGT.ConvertTypeForMem(Type)); StackOffset += getContext().getTypeSizeInChars(Type); // Insert padding bytes to respect alignment. CharUnits FieldEnd = StackOffset; StackOffset = FieldEnd.RoundUpToAlignment(FieldAlign); if (StackOffset != FieldEnd) { CharUnits NumBytes = StackOffset - FieldEnd; llvm::Type *Ty = llvm::Type::getInt8Ty(getVMContext()); Ty = llvm::ArrayType::get(Ty, NumBytes.getQuantity()); FrameFields.push_back(Ty); } } static bool isArgInAlloca(const ABIArgInfo &Info) { // Leave ignored and inreg arguments alone. switch (Info.getKind()) { case ABIArgInfo::InAlloca: return true; case ABIArgInfo::Indirect: assert(Info.getIndirectByVal()); return true; case ABIArgInfo::Ignore: return false; case ABIArgInfo::Direct: case ABIArgInfo::Extend: case ABIArgInfo::Expand: if (Info.getInReg()) return false; return true; } llvm_unreachable("invalid enum"); } void X86_32ABIInfo::rewriteWithInAlloca(CGFunctionInfo &FI) const { assert(IsWin32StructABI && "inalloca only supported on win32"); // Build a packed struct type for all of the arguments in memory. SmallVector FrameFields; // The stack alignment is always 4. CharUnits StackAlign = CharUnits::fromQuantity(4); CharUnits StackOffset; CGFunctionInfo::arg_iterator I = FI.arg_begin(), E = FI.arg_end(); // Put 'this' into the struct before 'sret', if necessary. bool IsThisCall = FI.getCallingConvention() == llvm::CallingConv::X86_ThisCall; ABIArgInfo &Ret = FI.getReturnInfo(); if (Ret.isIndirect() && Ret.isSRetAfterThis() && !IsThisCall && isArgInAlloca(I->info)) { addFieldToArgStruct(FrameFields, StackOffset, I->info, I->type); ++I; } // Put the sret parameter into the inalloca struct if it's in memory. if (Ret.isIndirect() && !Ret.getInReg()) { CanQualType PtrTy = getContext().getPointerType(FI.getReturnType()); addFieldToArgStruct(FrameFields, StackOffset, Ret, PtrTy); // On Windows, the hidden sret parameter is always returned in eax. Ret.setInAllocaSRet(IsWin32StructABI); } // Skip the 'this' parameter in ecx. if (IsThisCall) ++I; // Put arguments passed in memory into the struct. for (; I != E; ++I) { if (isArgInAlloca(I->info)) addFieldToArgStruct(FrameFields, StackOffset, I->info, I->type); } FI.setArgStruct(llvm::StructType::get(getVMContext(), FrameFields, /*isPacked=*/true), StackAlign); } Address X86_32ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { auto TypeInfo = getContext().getTypeInfoInChars(Ty); // x86-32 changes the alignment of certain arguments on the stack. // // Just messing with TypeInfo like this works because we never pass // anything indirectly. TypeInfo.second = CharUnits::fromQuantity( getTypeStackAlignInBytes(Ty, TypeInfo.second.getQuantity())); return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*Indirect*/ false, TypeInfo, CharUnits::fromQuantity(4), /*AllowHigherAlign*/ true); } bool X86_32TargetCodeGenInfo::isStructReturnInRegABI( const llvm::Triple &Triple, const CodeGenOptions &Opts) { assert(Triple.getArch() == llvm::Triple::x86); switch (Opts.getStructReturnConvention()) { case CodeGenOptions::SRCK_Default: break; case CodeGenOptions::SRCK_OnStack: // -fpcc-struct-return return false; case CodeGenOptions::SRCK_InRegs: // -freg-struct-return return true; } if (Triple.isOSDarwin() || Triple.isOSIAMCU()) return true; switch (Triple.getOS()) { case llvm::Triple::DragonFly: case llvm::Triple::FreeBSD: case llvm::Triple::OpenBSD: case llvm::Triple::Bitrig: case llvm::Triple::Win32: return true; default: return false; } } void X86_32TargetCodeGenInfo::setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { if (const FunctionDecl *FD = dyn_cast_or_null(D)) { if (FD->hasAttr()) { // Get the LLVM function. llvm::Function *Fn = cast(GV); // Now add the 'alignstack' attribute with a value of 16. llvm::AttrBuilder B; B.addStackAlignmentAttr(16); Fn->addAttributes(llvm::AttributeSet::FunctionIndex, llvm::AttributeSet::get(CGM.getLLVMContext(), llvm::AttributeSet::FunctionIndex, B)); } } } bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable( CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const { CodeGen::CGBuilderTy &Builder = CGF.Builder; llvm::Value *Four8 = llvm::ConstantInt::get(CGF.Int8Ty, 4); // 0-7 are the eight integer registers; the order is different // on Darwin (for EH), but the range is the same. // 8 is %eip. AssignToArrayRange(Builder, Address, Four8, 0, 8); if (CGF.CGM.getTarget().getTriple().isOSDarwin()) { // 12-16 are st(0..4). Not sure why we stop at 4. // These have size 16, which is sizeof(long double) on // platforms with 8-byte alignment for that type. llvm::Value *Sixteen8 = llvm::ConstantInt::get(CGF.Int8Ty, 16); AssignToArrayRange(Builder, Address, Sixteen8, 12, 16); } else { // 9 is %eflags, which doesn't get a size on Darwin for some // reason. Builder.CreateAlignedStore( Four8, Builder.CreateConstInBoundsGEP1_32(CGF.Int8Ty, Address, 9), CharUnits::One()); // 11-16 are st(0..5). Not sure why we stop at 5. // These have size 12, which is sizeof(long double) on // platforms with 4-byte alignment for that type. llvm::Value *Twelve8 = llvm::ConstantInt::get(CGF.Int8Ty, 12); AssignToArrayRange(Builder, Address, Twelve8, 11, 16); } return false; } //===----------------------------------------------------------------------===// // X86-64 ABI Implementation //===----------------------------------------------------------------------===// namespace { /// The AVX ABI level for X86 targets. enum class X86AVXABILevel { None, AVX, AVX512 }; /// \p returns the size in bits of the largest (native) vector for \p AVXLevel. static unsigned getNativeVectorSizeForAVXABI(X86AVXABILevel AVXLevel) { switch (AVXLevel) { case X86AVXABILevel::AVX512: return 512; case X86AVXABILevel::AVX: return 256; case X86AVXABILevel::None: return 128; } llvm_unreachable("Unknown AVXLevel"); } /// X86_64ABIInfo - The X86_64 ABI information. class X86_64ABIInfo : public ABIInfo { enum Class { Integer = 0, SSE, SSEUp, X87, X87Up, ComplexX87, NoClass, Memory }; /// merge - Implement the X86_64 ABI merging algorithm. /// /// Merge an accumulating classification \arg Accum with a field /// classification \arg Field. /// /// \param Accum - The accumulating classification. This should /// always be either NoClass or the result of a previous merge /// call. In addition, this should never be Memory (the caller /// should just return Memory for the aggregate). static Class merge(Class Accum, Class Field); /// postMerge - Implement the X86_64 ABI post merging algorithm. /// /// Post merger cleanup, reduces a malformed Hi and Lo pair to /// final MEMORY or SSE classes when necessary. /// /// \param AggregateSize - The size of the current aggregate in /// the classification process. /// /// \param Lo - The classification for the parts of the type /// residing in the low word of the containing object. /// /// \param Hi - The classification for the parts of the type /// residing in the higher words of the containing object. /// void postMerge(unsigned AggregateSize, Class &Lo, Class &Hi) const; /// classify - Determine the x86_64 register classes in which the /// given type T should be passed. /// /// \param Lo - The classification for the parts of the type /// residing in the low word of the containing object. /// /// \param Hi - The classification for the parts of the type /// residing in the high word of the containing object. /// /// \param OffsetBase - The bit offset of this type in the /// containing object. Some parameters are classified different /// depending on whether they straddle an eightbyte boundary. /// /// \param isNamedArg - Whether the argument in question is a "named" /// argument, as used in AMD64-ABI 3.5.7. /// /// If a word is unused its result will be NoClass; if a type should /// be passed in Memory then at least the classification of \arg Lo /// will be Memory. /// /// The \arg Lo class will be NoClass iff the argument is ignored. /// /// If the \arg Lo class is ComplexX87, then the \arg Hi class will /// also be ComplexX87. void classify(QualType T, uint64_t OffsetBase, Class &Lo, Class &Hi, bool isNamedArg) const; llvm::Type *GetByteVectorType(QualType Ty) const; llvm::Type *GetSSETypeAtOffset(llvm::Type *IRType, unsigned IROffset, QualType SourceTy, unsigned SourceOffset) const; llvm::Type *GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset, QualType SourceTy, unsigned SourceOffset) const; /// getIndirectResult - Give a source type \arg Ty, return a suitable result /// such that the argument will be returned in memory. ABIArgInfo getIndirectReturnResult(QualType Ty) const; /// getIndirectResult - Give a source type \arg Ty, return a suitable result /// such that the argument will be passed in memory. /// /// \param freeIntRegs - The number of free integer registers remaining /// available. ABIArgInfo getIndirectResult(QualType Ty, unsigned freeIntRegs) const; ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType Ty, unsigned freeIntRegs, unsigned &neededInt, unsigned &neededSSE, bool isNamedArg) const; bool IsIllegalVectorType(QualType Ty) const; /// The 0.98 ABI revision clarified a lot of ambiguities, /// unfortunately in ways that were not always consistent with /// certain previous compilers. In particular, platforms which /// required strict binary compatibility with older versions of GCC /// may need to exempt themselves. bool honorsRevision0_98() const { return !getTarget().getTriple().isOSDarwin(); } X86AVXABILevel AVXLevel; // Some ABIs (e.g. X32 ABI and Native Client OS) use 32 bit pointers on // 64-bit hardware. bool Has64BitPointers; public: X86_64ABIInfo(CodeGen::CodeGenTypes &CGT, X86AVXABILevel AVXLevel) : ABIInfo(CGT), AVXLevel(AVXLevel), Has64BitPointers(CGT.getDataLayout().getPointerSize(0) == 8) { } bool isPassedUsingAVXType(QualType type) const { unsigned neededInt, neededSSE; // The freeIntRegs argument doesn't matter here. ABIArgInfo info = classifyArgumentType(type, 0, neededInt, neededSSE, /*isNamedArg*/true); if (info.isDirect()) { llvm::Type *ty = info.getCoerceToType(); if (llvm::VectorType *vectorTy = dyn_cast_or_null(ty)) return (vectorTy->getBitWidth() > 128); } return false; } void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; Address EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; bool has64BitPointers() const { return Has64BitPointers; } }; /// WinX86_64ABIInfo - The Windows X86_64 ABI information. class WinX86_64ABIInfo : public ABIInfo { public: WinX86_64ABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT), IsMingw64(getTarget().getTriple().isWindowsGNUEnvironment()) {} void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; bool isHomogeneousAggregateBaseType(QualType Ty) const override { // FIXME: Assumes vectorcall is in use. return isX86VectorTypeForVectorCall(getContext(), Ty); } bool isHomogeneousAggregateSmallEnough(const Type *Ty, uint64_t NumMembers) const override { // FIXME: Assumes vectorcall is in use. return isX86VectorCallAggregateSmallEnough(NumMembers); } private: ABIArgInfo classify(QualType Ty, unsigned &FreeSSERegs, bool IsReturnType) const; bool IsMingw64; }; class X86_64TargetCodeGenInfo : public TargetCodeGenInfo { public: X86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, X86AVXABILevel AVXLevel) : TargetCodeGenInfo(new X86_64ABIInfo(CGT, AVXLevel)) {} const X86_64ABIInfo &getABIInfo() const { return static_cast(TargetCodeGenInfo::getABIInfo()); } int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override { return 7; } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override { llvm::Value *Eight8 = llvm::ConstantInt::get(CGF.Int8Ty, 8); // 0-15 are the 16 integer registers. // 16 is %rip. AssignToArrayRange(CGF.Builder, Address, Eight8, 0, 16); return false; } llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF, StringRef Constraint, llvm::Type* Ty) const override { return X86AdjustInlineAsmType(CGF, Constraint, Ty); } bool isNoProtoCallVariadic(const CallArgList &args, const FunctionNoProtoType *fnType) const override { // The default CC on x86-64 sets %al to the number of SSA // registers used, and GCC sets this when calling an unprototyped // function, so we override the default behavior. However, don't do // that when AVX types are involved: the ABI explicitly states it is // undefined, and it doesn't work in practice because of how the ABI // defines varargs anyway. if (fnType->getCallConv() == CC_C) { bool HasAVXType = false; for (CallArgList::const_iterator it = args.begin(), ie = args.end(); it != ie; ++it) { if (getABIInfo().isPassedUsingAVXType(it->Ty)) { HasAVXType = true; break; } } if (!HasAVXType) return true; } return TargetCodeGenInfo::isNoProtoCallVariadic(args, fnType); } llvm::Constant * getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const override { unsigned Sig; if (getABIInfo().has64BitPointers()) Sig = (0xeb << 0) | // jmp rel8 (0x0a << 8) | // .+0x0c ('F' << 16) | ('T' << 24); else Sig = (0xeb << 0) | // jmp rel8 (0x06 << 8) | // .+0x08 ('F' << 16) | ('T' << 24); return llvm::ConstantInt::get(CGM.Int32Ty, Sig); } }; class PS4TargetCodeGenInfo : public X86_64TargetCodeGenInfo { public: PS4TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, X86AVXABILevel AVXLevel) : X86_64TargetCodeGenInfo(CGT, AVXLevel) {} void getDependentLibraryOption(llvm::StringRef Lib, llvm::SmallString<24> &Opt) const override { Opt = "\01"; // If the argument contains a space, enclose it in quotes. if (Lib.find(" ") != StringRef::npos) Opt += "\"" + Lib.str() + "\""; else Opt += Lib; } }; static std::string qualifyWindowsLibrary(llvm::StringRef Lib) { // If the argument does not end in .lib, automatically add the suffix. // If the argument contains a space, enclose it in quotes. // This matches the behavior of MSVC. bool Quote = (Lib.find(" ") != StringRef::npos); std::string ArgStr = Quote ? "\"" : ""; ArgStr += Lib; if (!Lib.endswith_lower(".lib")) ArgStr += ".lib"; ArgStr += Quote ? "\"" : ""; return ArgStr; } class WinX86_32TargetCodeGenInfo : public X86_32TargetCodeGenInfo { public: WinX86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool DarwinVectorABI, bool RetSmallStructInRegABI, bool Win32StructABI, unsigned NumRegisterParameters) : X86_32TargetCodeGenInfo(CGT, DarwinVectorABI, RetSmallStructInRegABI, Win32StructABI, NumRegisterParameters, false) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override; void getDependentLibraryOption(llvm::StringRef Lib, llvm::SmallString<24> &Opt) const override { Opt = "/DEFAULTLIB:"; Opt += qualifyWindowsLibrary(Lib); } void getDetectMismatchOption(llvm::StringRef Name, llvm::StringRef Value, llvm::SmallString<32> &Opt) const override { Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\""; } }; static void addStackProbeSizeTargetAttribute(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) { if (D && isa(D)) { if (CGM.getCodeGenOpts().StackProbeSize != 4096) { llvm::Function *Fn = cast(GV); Fn->addFnAttr("stack-probe-size", llvm::utostr(CGM.getCodeGenOpts().StackProbeSize)); } } } void WinX86_32TargetCodeGenInfo::setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { X86_32TargetCodeGenInfo::setTargetAttributes(D, GV, CGM); addStackProbeSizeTargetAttribute(D, GV, CGM); } class WinX86_64TargetCodeGenInfo : public TargetCodeGenInfo { public: WinX86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, X86AVXABILevel AVXLevel) : TargetCodeGenInfo(new WinX86_64ABIInfo(CGT)) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override; int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override { return 7; } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override { llvm::Value *Eight8 = llvm::ConstantInt::get(CGF.Int8Ty, 8); // 0-15 are the 16 integer registers. // 16 is %rip. AssignToArrayRange(CGF.Builder, Address, Eight8, 0, 16); return false; } void getDependentLibraryOption(llvm::StringRef Lib, llvm::SmallString<24> &Opt) const override { Opt = "/DEFAULTLIB:"; Opt += qualifyWindowsLibrary(Lib); } void getDetectMismatchOption(llvm::StringRef Name, llvm::StringRef Value, llvm::SmallString<32> &Opt) const override { Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\""; } }; void WinX86_64TargetCodeGenInfo::setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { TargetCodeGenInfo::setTargetAttributes(D, GV, CGM); addStackProbeSizeTargetAttribute(D, GV, CGM); } } void X86_64ABIInfo::postMerge(unsigned AggregateSize, Class &Lo, Class &Hi) const { // AMD64-ABI 3.2.3p2: Rule 5. Then a post merger cleanup is done: // // (a) If one of the classes is Memory, the whole argument is passed in // memory. // // (b) If X87UP is not preceded by X87, the whole argument is passed in // memory. // // (c) If the size of the aggregate exceeds two eightbytes and the first // eightbyte isn't SSE or any other eightbyte isn't SSEUP, the whole // argument is passed in memory. NOTE: This is necessary to keep the // ABI working for processors that don't support the __m256 type. // // (d) If SSEUP is not preceded by SSE or SSEUP, it is converted to SSE. // // Some of these are enforced by the merging logic. Others can arise // only with unions; for example: // union { _Complex double; unsigned; } // // Note that clauses (b) and (c) were added in 0.98. // if (Hi == Memory) Lo = Memory; if (Hi == X87Up && Lo != X87 && honorsRevision0_98()) Lo = Memory; if (AggregateSize > 128 && (Lo != SSE || Hi != SSEUp)) Lo = Memory; if (Hi == SSEUp && Lo != SSE) Hi = SSE; } X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum, Class Field) { // AMD64-ABI 3.2.3p2: Rule 4. Each field of an object is // classified recursively so that always two fields are // considered. The resulting class is calculated according to // the classes of the fields in the eightbyte: // // (a) If both classes are equal, this is the resulting class. // // (b) If one of the classes is NO_CLASS, the resulting class is // the other class. // // (c) If one of the classes is MEMORY, the result is the MEMORY // class. // // (d) If one of the classes is INTEGER, the result is the // INTEGER. // // (e) If one of the classes is X87, X87UP, COMPLEX_X87 class, // MEMORY is used as class. // // (f) Otherwise class SSE is used. // Accum should never be memory (we should have returned) or // ComplexX87 (because this cannot be passed in a structure). assert((Accum != Memory && Accum != ComplexX87) && "Invalid accumulated classification during merge."); if (Accum == Field || Field == NoClass) return Accum; if (Field == Memory) return Memory; if (Accum == NoClass) return Field; if (Accum == Integer || Field == Integer) return Integer; if (Field == X87 || Field == X87Up || Field == ComplexX87 || Accum == X87 || Accum == X87Up) return Memory; return SSE; } void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo, Class &Hi, bool isNamedArg) const { // FIXME: This code can be simplified by introducing a simple value class for // Class pairs with appropriate constructor methods for the various // situations. // FIXME: Some of the split computations are wrong; unaligned vectors // shouldn't be passed in registers for example, so there is no chance they // can straddle an eightbyte. Verify & simplify. Lo = Hi = NoClass; Class &Current = OffsetBase < 64 ? Lo : Hi; Current = Memory; if (const BuiltinType *BT = Ty->getAs()) { BuiltinType::Kind k = BT->getKind(); if (k == BuiltinType::Void) { Current = NoClass; } else if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { Lo = Integer; Hi = Integer; } else if (k >= BuiltinType::Bool && k <= BuiltinType::LongLong) { Current = Integer; } else if (k == BuiltinType::Float || k == BuiltinType::Double) { Current = SSE; } else if (k == BuiltinType::LongDouble) { const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat(); if (LDF == &llvm::APFloat::IEEEquad) { Lo = SSE; Hi = SSEUp; } else if (LDF == &llvm::APFloat::x87DoubleExtended) { Lo = X87; Hi = X87Up; } else if (LDF == &llvm::APFloat::IEEEdouble) { Current = SSE; } else llvm_unreachable("unexpected long double representation!"); } // FIXME: _Decimal32 and _Decimal64 are SSE. // FIXME: _float128 and _Decimal128 are (SSE, SSEUp). return; } if (const EnumType *ET = Ty->getAs()) { // Classify the underlying integer type. classify(ET->getDecl()->getIntegerType(), OffsetBase, Lo, Hi, isNamedArg); return; } if (Ty->hasPointerRepresentation()) { Current = Integer; return; } if (Ty->isMemberPointerType()) { if (Ty->isMemberFunctionPointerType()) { if (Has64BitPointers) { // If Has64BitPointers, this is an {i64, i64}, so classify both // Lo and Hi now. Lo = Hi = Integer; } else { // Otherwise, with 32-bit pointers, this is an {i32, i32}. If that // straddles an eightbyte boundary, Hi should be classified as well. uint64_t EB_FuncPtr = (OffsetBase) / 64; uint64_t EB_ThisAdj = (OffsetBase + 64 - 1) / 64; if (EB_FuncPtr != EB_ThisAdj) { Lo = Hi = Integer; } else { Current = Integer; } } } else { Current = Integer; } return; } if (const VectorType *VT = Ty->getAs()) { uint64_t Size = getContext().getTypeSize(VT); if (Size == 1 || Size == 8 || Size == 16 || Size == 32) { // gcc passes the following as integer: // 4 bytes - <4 x char>, <2 x short>, <1 x int>, <1 x float> // 2 bytes - <2 x char>, <1 x short> // 1 byte - <1 x char> Current = Integer; // If this type crosses an eightbyte boundary, it should be // split. uint64_t EB_Lo = (OffsetBase) / 64; uint64_t EB_Hi = (OffsetBase + Size - 1) / 64; if (EB_Lo != EB_Hi) Hi = Lo; } else if (Size == 64) { // gcc passes <1 x double> in memory. :( if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::Double)) return; // gcc passes <1 x long long> as INTEGER. if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::LongLong) || VT->getElementType()->isSpecificBuiltinType(BuiltinType::ULongLong) || VT->getElementType()->isSpecificBuiltinType(BuiltinType::Long) || VT->getElementType()->isSpecificBuiltinType(BuiltinType::ULong)) Current = Integer; else Current = SSE; // If this type crosses an eightbyte boundary, it should be // split. if (OffsetBase && OffsetBase != 64) Hi = Lo; } else if (Size == 128 || (isNamedArg && Size <= getNativeVectorSizeForAVXABI(AVXLevel))) { // Arguments of 256-bits are split into four eightbyte chunks. The // least significant one belongs to class SSE and all the others to class // SSEUP. The original Lo and Hi design considers that types can't be // greater than 128-bits, so a 64-bit split in Hi and Lo makes sense. // This design isn't correct for 256-bits, but since there're no cases // where the upper parts would need to be inspected, avoid adding // complexity and just consider Hi to match the 64-256 part. // // Note that per 3.5.7 of AMD64-ABI, 256-bit args are only passed in // registers if they are "named", i.e. not part of the "..." of a // variadic function. // // Similarly, per 3.2.3. of the AVX512 draft, 512-bits ("named") args are // split into eight eightbyte chunks, one SSE and seven SSEUP. Lo = SSE; Hi = SSEUp; } return; } if (const ComplexType *CT = Ty->getAs()) { QualType ET = getContext().getCanonicalType(CT->getElementType()); uint64_t Size = getContext().getTypeSize(Ty); if (ET->isIntegralOrEnumerationType()) { if (Size <= 64) Current = Integer; else if (Size <= 128) Lo = Hi = Integer; } else if (ET == getContext().FloatTy) { Current = SSE; } else if (ET == getContext().DoubleTy) { Lo = Hi = SSE; } else if (ET == getContext().LongDoubleTy) { const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat(); if (LDF == &llvm::APFloat::IEEEquad) Current = Memory; else if (LDF == &llvm::APFloat::x87DoubleExtended) Current = ComplexX87; else if (LDF == &llvm::APFloat::IEEEdouble) Lo = Hi = SSE; else llvm_unreachable("unexpected long double representation!"); } // If this complex type crosses an eightbyte boundary then it // should be split. uint64_t EB_Real = (OffsetBase) / 64; uint64_t EB_Imag = (OffsetBase + getContext().getTypeSize(ET)) / 64; if (Hi == NoClass && EB_Real != EB_Imag) Hi = Lo; return; } if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) { // Arrays are treated like structures. uint64_t Size = getContext().getTypeSize(Ty); // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger // than four eightbytes, ..., it has class MEMORY. if (Size > 256) return; // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned // fields, it has class MEMORY. // // Only need to check alignment of array base. if (OffsetBase % getContext().getTypeAlign(AT->getElementType())) return; // Otherwise implement simplified merge. We could be smarter about // this, but it isn't worth it and would be harder to verify. Current = NoClass; uint64_t EltSize = getContext().getTypeSize(AT->getElementType()); uint64_t ArraySize = AT->getSize().getZExtValue(); // The only case a 256-bit wide vector could be used is when the array // contains a single 256-bit element. Since Lo and Hi logic isn't extended // to work for sizes wider than 128, early check and fallback to memory. if (Size > 128 && EltSize != 256) return; for (uint64_t i=0, Offset=OffsetBase; igetElementType(), Offset, FieldLo, FieldHi, isNamedArg); Lo = merge(Lo, FieldLo); Hi = merge(Hi, FieldHi); if (Lo == Memory || Hi == Memory) break; } postMerge(Size, Lo, Hi); assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp array classification."); return; } if (const RecordType *RT = Ty->getAs()) { uint64_t Size = getContext().getTypeSize(Ty); // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger // than four eightbytes, ..., it has class MEMORY. if (Size > 256) return; // AMD64-ABI 3.2.3p2: Rule 2. If a C++ object has either a non-trivial // copy constructor or a non-trivial destructor, it is passed by invisible // reference. if (getRecordArgABI(RT, getCXXABI())) return; const RecordDecl *RD = RT->getDecl(); // Assume variable sized types are passed in memory. if (RD->hasFlexibleArrayMember()) return; const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); // Reset Lo class, this will be recomputed. Current = NoClass; // If this is a C++ record, classify the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { for (const auto &I : CXXRD->bases()) { assert(!I.isVirtual() && !I.getType()->isDependentType() && "Unexpected base class!"); const CXXRecordDecl *Base = cast(I.getType()->getAs()->getDecl()); // Classify this field. // // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate exceeds a // single eightbyte, each is classified separately. Each eightbyte gets // initialized to class NO_CLASS. Class FieldLo, FieldHi; uint64_t Offset = OffsetBase + getContext().toBits(Layout.getBaseClassOffset(Base)); classify(I.getType(), Offset, FieldLo, FieldHi, isNamedArg); Lo = merge(Lo, FieldLo); Hi = merge(Hi, FieldHi); if (Lo == Memory || Hi == Memory) { postMerge(Size, Lo, Hi); return; } } } // Classify the fields one at a time, merging the results. unsigned idx = 0; for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i, ++idx) { uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx); bool BitField = i->isBitField(); // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger than // four eightbytes, or it contains unaligned fields, it has class MEMORY. // // The only case a 256-bit wide vector could be used is when the struct // contains a single 256-bit element. Since Lo and Hi logic isn't extended // to work for sizes wider than 128, early check and fallback to memory. // if (Size > 128 && getContext().getTypeSize(i->getType()) != 256) { Lo = Memory; postMerge(Size, Lo, Hi); return; } // Note, skip this test for bit-fields, see below. if (!BitField && Offset % getContext().getTypeAlign(i->getType())) { Lo = Memory; postMerge(Size, Lo, Hi); return; } // Classify this field. // // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate // exceeds a single eightbyte, each is classified // separately. Each eightbyte gets initialized to class // NO_CLASS. Class FieldLo, FieldHi; // Bit-fields require special handling, they do not force the // structure to be passed in memory even if unaligned, and // therefore they can straddle an eightbyte. if (BitField) { // Ignore padding bit-fields. if (i->isUnnamedBitfield()) continue; uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx); uint64_t Size = i->getBitWidthValue(getContext()); uint64_t EB_Lo = Offset / 64; uint64_t EB_Hi = (Offset + Size - 1) / 64; if (EB_Lo) { assert(EB_Hi == EB_Lo && "Invalid classification, type > 16 bytes."); FieldLo = NoClass; FieldHi = Integer; } else { FieldLo = Integer; FieldHi = EB_Hi ? Integer : NoClass; } } else classify(i->getType(), Offset, FieldLo, FieldHi, isNamedArg); Lo = merge(Lo, FieldLo); Hi = merge(Hi, FieldHi); if (Lo == Memory || Hi == Memory) break; } postMerge(Size, Lo, Hi); } } ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty) const { // If this is a scalar LLVM value then assume LLVM will pass it in the right // place naturally. if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } return getNaturalAlignIndirect(Ty); } bool X86_64ABIInfo::IsIllegalVectorType(QualType Ty) const { if (const VectorType *VecTy = Ty->getAs()) { uint64_t Size = getContext().getTypeSize(VecTy); unsigned LargestVector = getNativeVectorSizeForAVXABI(AVXLevel); if (Size <= 64 || Size > LargestVector) return true; } return false; } ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty, unsigned freeIntRegs) const { // If this is a scalar LLVM value then assume LLVM will pass it in the right // place naturally. // // This assumption is optimistic, as there could be free registers available // when we need to pass this argument in memory, and LLVM could try to pass // the argument in the free register. This does not seem to happen currently, // but this code would be much safer if we could mark the argument with // 'onstack'. See PR12193. if (!isAggregateTypeForABI(Ty) && !IsIllegalVectorType(Ty)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); // Compute the byval alignment. We specify the alignment of the byval in all // cases so that the mid-level optimizer knows the alignment of the byval. unsigned Align = std::max(getContext().getTypeAlign(Ty) / 8, 8U); // Attempt to avoid passing indirect results using byval when possible. This // is important for good codegen. // // We do this by coercing the value into a scalar type which the backend can // handle naturally (i.e., without using byval). // // For simplicity, we currently only do this when we have exhausted all of the // free integer registers. Doing this when there are free integer registers // would require more care, as we would have to ensure that the coerced value // did not claim the unused register. That would require either reording the // arguments to the function (so that any subsequent inreg values came first), // or only doing this optimization when there were no following arguments that // might be inreg. // // We currently expect it to be rare (particularly in well written code) for // arguments to be passed on the stack when there are still free integer // registers available (this would typically imply large structs being passed // by value), so this seems like a fair tradeoff for now. // // We can revisit this if the backend grows support for 'onstack' parameter // attributes. See PR12193. if (freeIntRegs == 0) { uint64_t Size = getContext().getTypeSize(Ty); // If this type fits in an eightbyte, coerce it into the matching integral // type, which will end up on the stack (with alignment 8). if (Align == 8 && Size <= 64) return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); } return ABIArgInfo::getIndirect(CharUnits::fromQuantity(Align)); } /// The ABI specifies that a value should be passed in a full vector XMM/YMM /// register. Pick an LLVM IR type that will be passed as a vector register. llvm::Type *X86_64ABIInfo::GetByteVectorType(QualType Ty) const { // Wrapper structs/arrays that only contain vectors are passed just like // vectors; strip them off if present. if (const Type *InnerTy = isSingleElementStruct(Ty, getContext())) Ty = QualType(InnerTy, 0); llvm::Type *IRType = CGT.ConvertType(Ty); if (isa(IRType) || IRType->getTypeID() == llvm::Type::FP128TyID) return IRType; // We couldn't find the preferred IR vector type for 'Ty'. uint64_t Size = getContext().getTypeSize(Ty); assert((Size == 128 || Size == 256) && "Invalid type found!"); // Return a LLVM IR vector type based on the size of 'Ty'. return llvm::VectorType::get(llvm::Type::getDoubleTy(getVMContext()), Size / 64); } /// BitsContainNoUserData - Return true if the specified [start,end) bit range /// is known to either be off the end of the specified type or being in /// alignment padding. The user type specified is known to be at most 128 bits /// in size, and have passed through X86_64ABIInfo::classify with a successful /// classification that put one of the two halves in the INTEGER class. /// /// It is conservatively correct to return false. static bool BitsContainNoUserData(QualType Ty, unsigned StartBit, unsigned EndBit, ASTContext &Context) { // If the bytes being queried are off the end of the type, there is no user // data hiding here. This handles analysis of builtins, vectors and other // types that don't contain interesting padding. unsigned TySize = (unsigned)Context.getTypeSize(Ty); if (TySize <= StartBit) return true; if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) { unsigned EltSize = (unsigned)Context.getTypeSize(AT->getElementType()); unsigned NumElts = (unsigned)AT->getSize().getZExtValue(); // Check each element to see if the element overlaps with the queried range. for (unsigned i = 0; i != NumElts; ++i) { // If the element is after the span we care about, then we're done.. unsigned EltOffset = i*EltSize; if (EltOffset >= EndBit) break; unsigned EltStart = EltOffset < StartBit ? StartBit-EltOffset :0; if (!BitsContainNoUserData(AT->getElementType(), EltStart, EndBit-EltOffset, Context)) return false; } // If it overlaps no elements, then it is safe to process as padding. return true; } if (const RecordType *RT = Ty->getAs()) { const RecordDecl *RD = RT->getDecl(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { for (const auto &I : CXXRD->bases()) { assert(!I.isVirtual() && !I.getType()->isDependentType() && "Unexpected base class!"); const CXXRecordDecl *Base = cast(I.getType()->getAs()->getDecl()); // If the base is after the span we care about, ignore it. unsigned BaseOffset = Context.toBits(Layout.getBaseClassOffset(Base)); if (BaseOffset >= EndBit) continue; unsigned BaseStart = BaseOffset < StartBit ? StartBit-BaseOffset :0; if (!BitsContainNoUserData(I.getType(), BaseStart, EndBit-BaseOffset, Context)) return false; } } // Verify that no field has data that overlaps the region of interest. Yes // this could be sped up a lot by being smarter about queried fields, // however we're only looking at structs up to 16 bytes, so we don't care // much. unsigned idx = 0; for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i, ++idx) { unsigned FieldOffset = (unsigned)Layout.getFieldOffset(idx); // If we found a field after the region we care about, then we're done. if (FieldOffset >= EndBit) break; unsigned FieldStart = FieldOffset < StartBit ? StartBit-FieldOffset :0; if (!BitsContainNoUserData(i->getType(), FieldStart, EndBit-FieldOffset, Context)) return false; } // If nothing in this record overlapped the area of interest, then we're // clean. return true; } return false; } /// ContainsFloatAtOffset - Return true if the specified LLVM IR type has a /// float member at the specified offset. For example, {int,{float}} has a /// float at offset 4. It is conservatively correct for this routine to return /// false. static bool ContainsFloatAtOffset(llvm::Type *IRType, unsigned IROffset, const llvm::DataLayout &TD) { // Base case if we find a float. if (IROffset == 0 && IRType->isFloatTy()) return true; // If this is a struct, recurse into the field at the specified offset. if (llvm::StructType *STy = dyn_cast(IRType)) { const llvm::StructLayout *SL = TD.getStructLayout(STy); unsigned Elt = SL->getElementContainingOffset(IROffset); IROffset -= SL->getElementOffset(Elt); return ContainsFloatAtOffset(STy->getElementType(Elt), IROffset, TD); } // If this is an array, recurse into the field at the specified offset. if (llvm::ArrayType *ATy = dyn_cast(IRType)) { llvm::Type *EltTy = ATy->getElementType(); unsigned EltSize = TD.getTypeAllocSize(EltTy); IROffset -= IROffset/EltSize*EltSize; return ContainsFloatAtOffset(EltTy, IROffset, TD); } return false; } /// GetSSETypeAtOffset - Return a type that will be passed by the backend in the /// low 8 bytes of an XMM register, corresponding to the SSE class. llvm::Type *X86_64ABIInfo:: GetSSETypeAtOffset(llvm::Type *IRType, unsigned IROffset, QualType SourceTy, unsigned SourceOffset) const { // The only three choices we have are either double, <2 x float>, or float. We // pass as float if the last 4 bytes is just padding. This happens for // structs that contain 3 floats. if (BitsContainNoUserData(SourceTy, SourceOffset*8+32, SourceOffset*8+64, getContext())) return llvm::Type::getFloatTy(getVMContext()); // We want to pass as <2 x float> if the LLVM IR type contains a float at // offset+0 and offset+4. Walk the LLVM IR type to find out if this is the // case. if (ContainsFloatAtOffset(IRType, IROffset, getDataLayout()) && ContainsFloatAtOffset(IRType, IROffset+4, getDataLayout())) return llvm::VectorType::get(llvm::Type::getFloatTy(getVMContext()), 2); return llvm::Type::getDoubleTy(getVMContext()); } /// GetINTEGERTypeAtOffset - The ABI specifies that a value should be passed in /// an 8-byte GPR. This means that we either have a scalar or we are talking /// about the high or low part of an up-to-16-byte struct. This routine picks /// the best LLVM IR type to represent this, which may be i64 or may be anything /// else that the backend will pass in a GPR that works better (e.g. i8, %foo*, /// etc). /// /// PrefType is an LLVM IR type that corresponds to (part of) the IR type for /// the source type. IROffset is an offset in bytes into the LLVM IR type that /// the 8-byte value references. PrefType may be null. /// /// SourceTy is the source-level type for the entire argument. SourceOffset is /// an offset into this that we're processing (which is always either 0 or 8). /// llvm::Type *X86_64ABIInfo:: GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset, QualType SourceTy, unsigned SourceOffset) const { // If we're dealing with an un-offset LLVM IR type, then it means that we're // returning an 8-byte unit starting with it. See if we can safely use it. if (IROffset == 0) { // Pointers and int64's always fill the 8-byte unit. if ((isa(IRType) && Has64BitPointers) || IRType->isIntegerTy(64)) return IRType; // If we have a 1/2/4-byte integer, we can use it only if the rest of the // goodness in the source type is just tail padding. This is allowed to // kick in for struct {double,int} on the int, but not on // struct{double,int,int} because we wouldn't return the second int. We // have to do this analysis on the source type because we can't depend on // unions being lowered a specific way etc. if (IRType->isIntegerTy(8) || IRType->isIntegerTy(16) || IRType->isIntegerTy(32) || (isa(IRType) && !Has64BitPointers)) { unsigned BitWidth = isa(IRType) ? 32 : cast(IRType)->getBitWidth(); if (BitsContainNoUserData(SourceTy, SourceOffset*8+BitWidth, SourceOffset*8+64, getContext())) return IRType; } } if (llvm::StructType *STy = dyn_cast(IRType)) { // If this is a struct, recurse into the field at the specified offset. const llvm::StructLayout *SL = getDataLayout().getStructLayout(STy); if (IROffset < SL->getSizeInBytes()) { unsigned FieldIdx = SL->getElementContainingOffset(IROffset); IROffset -= SL->getElementOffset(FieldIdx); return GetINTEGERTypeAtOffset(STy->getElementType(FieldIdx), IROffset, SourceTy, SourceOffset); } } if (llvm::ArrayType *ATy = dyn_cast(IRType)) { llvm::Type *EltTy = ATy->getElementType(); unsigned EltSize = getDataLayout().getTypeAllocSize(EltTy); unsigned EltOffset = IROffset/EltSize*EltSize; return GetINTEGERTypeAtOffset(EltTy, IROffset-EltOffset, SourceTy, SourceOffset); } // Okay, we don't have any better idea of what to pass, so we pass this in an // integer register that isn't too big to fit the rest of the struct. unsigned TySizeInBytes = (unsigned)getContext().getTypeSizeInChars(SourceTy).getQuantity(); assert(TySizeInBytes != SourceOffset && "Empty field?"); // It is always safe to classify this as an integer type up to i64 that // isn't larger than the structure. return llvm::IntegerType::get(getVMContext(), std::min(TySizeInBytes-SourceOffset, 8U)*8); } /// GetX86_64ByValArgumentPair - Given a high and low type that can ideally /// be used as elements of a two register pair to pass or return, return a /// first class aggregate to represent them. For example, if the low part of /// a by-value argument should be passed as i32* and the high part as float, /// return {i32*, float}. static llvm::Type * GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, const llvm::DataLayout &TD) { // In order to correctly satisfy the ABI, we need to the high part to start // at offset 8. If the high and low parts we inferred are both 4-byte types // (e.g. i32 and i32) then the resultant struct type ({i32,i32}) won't have // the second element at offset 8. Check for this: unsigned LoSize = (unsigned)TD.getTypeAllocSize(Lo); unsigned HiAlign = TD.getABITypeAlignment(Hi); unsigned HiStart = llvm::RoundUpToAlignment(LoSize, HiAlign); assert(HiStart != 0 && HiStart <= 8 && "Invalid x86-64 argument pair!"); // To handle this, we have to increase the size of the low part so that the // second element will start at an 8 byte offset. We can't increase the size // of the second element because it might make us access off the end of the // struct. if (HiStart != 8) { // There are usually two sorts of types the ABI generation code can produce // for the low part of a pair that aren't 8 bytes in size: float or // i8/i16/i32. This can also include pointers when they are 32-bit (X32 and // NaCl). // Promote these to a larger type. if (Lo->isFloatTy()) Lo = llvm::Type::getDoubleTy(Lo->getContext()); else { assert((Lo->isIntegerTy() || Lo->isPointerTy()) && "Invalid/unknown lo type"); Lo = llvm::Type::getInt64Ty(Lo->getContext()); } } llvm::StructType *Result = llvm::StructType::get(Lo, Hi, nullptr); // Verify that the second element is at an 8-byte offset. assert(TD.getStructLayout(Result)->getElementOffset(1) == 8 && "Invalid x86-64 argument pair!"); return Result; } ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy) const { // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the // classification algorithm. X86_64ABIInfo::Class Lo, Hi; classify(RetTy, 0, Lo, Hi, /*isNamedArg*/ true); // Check some invariants. assert((Hi != Memory || Lo == Memory) && "Invalid memory classification."); assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification."); llvm::Type *ResType = nullptr; switch (Lo) { case NoClass: if (Hi == NoClass) return ABIArgInfo::getIgnore(); // If the low part is just padding, it takes no register, leave ResType // null. assert((Hi == SSE || Hi == Integer || Hi == X87Up) && "Unknown missing lo part"); break; case SSEUp: case X87Up: llvm_unreachable("Invalid classification for lo word."); // AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via // hidden argument. case Memory: return getIndirectReturnResult(RetTy); // AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next // available register of the sequence %rax, %rdx is used. case Integer: ResType = GetINTEGERTypeAtOffset(CGT.ConvertType(RetTy), 0, RetTy, 0); // If we have a sign or zero extended integer, make sure to return Extend // so that the parameter gets the right LLVM IR attributes. if (Hi == NoClass && isa(ResType)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); if (RetTy->isIntegralOrEnumerationType() && RetTy->isPromotableIntegerType()) return ABIArgInfo::getExtend(); } break; // AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next // available SSE register of the sequence %xmm0, %xmm1 is used. case SSE: ResType = GetSSETypeAtOffset(CGT.ConvertType(RetTy), 0, RetTy, 0); break; // AMD64-ABI 3.2.3p4: Rule 6. If the class is X87, the value is // returned on the X87 stack in %st0 as 80-bit x87 number. case X87: ResType = llvm::Type::getX86_FP80Ty(getVMContext()); break; // AMD64-ABI 3.2.3p4: Rule 8. If the class is COMPLEX_X87, the real // part of the value is returned in %st0 and the imaginary part in // %st1. case ComplexX87: assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification."); ResType = llvm::StructType::get(llvm::Type::getX86_FP80Ty(getVMContext()), llvm::Type::getX86_FP80Ty(getVMContext()), nullptr); break; } llvm::Type *HighPart = nullptr; switch (Hi) { // Memory was handled previously and X87 should // never occur as a hi class. case Memory: case X87: llvm_unreachable("Invalid classification for hi word."); case ComplexX87: // Previously handled. case NoClass: break; case Integer: HighPart = GetINTEGERTypeAtOffset(CGT.ConvertType(RetTy), 8, RetTy, 8); if (Lo == NoClass) // Return HighPart at offset 8 in memory. return ABIArgInfo::getDirect(HighPart, 8); break; case SSE: HighPart = GetSSETypeAtOffset(CGT.ConvertType(RetTy), 8, RetTy, 8); if (Lo == NoClass) // Return HighPart at offset 8 in memory. return ABIArgInfo::getDirect(HighPart, 8); break; // AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte // is passed in the next available eightbyte chunk if the last used // vector register. // // SSEUP should always be preceded by SSE, just widen. case SSEUp: assert(Lo == SSE && "Unexpected SSEUp classification."); ResType = GetByteVectorType(RetTy); break; // AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is // returned together with the previous X87 value in %st0. case X87Up: // If X87Up is preceded by X87, we don't need to do // anything. However, in some cases with unions it may not be // preceded by X87. In such situations we follow gcc and pass the // extra bits in an SSE reg. if (Lo != X87) { HighPart = GetSSETypeAtOffset(CGT.ConvertType(RetTy), 8, RetTy, 8); if (Lo == NoClass) // Return HighPart at offset 8 in memory. return ABIArgInfo::getDirect(HighPart, 8); } break; } // If a high part was specified, merge it together with the low part. It is // known to pass in the high eightbyte of the result. We do this by forming a // first class struct aggregate with the high and low part: {low, high} if (HighPart) ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getDataLayout()); return ABIArgInfo::getDirect(ResType); } ABIArgInfo X86_64ABIInfo::classifyArgumentType( QualType Ty, unsigned freeIntRegs, unsigned &neededInt, unsigned &neededSSE, bool isNamedArg) const { Ty = useFirstFieldIfTransparentUnion(Ty); X86_64ABIInfo::Class Lo, Hi; classify(Ty, 0, Lo, Hi, isNamedArg); // Check some invariants. // FIXME: Enforce these by construction. assert((Hi != Memory || Lo == Memory) && "Invalid memory classification."); assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification."); neededInt = 0; neededSSE = 0; llvm::Type *ResType = nullptr; switch (Lo) { case NoClass: if (Hi == NoClass) return ABIArgInfo::getIgnore(); // If the low part is just padding, it takes no register, leave ResType // null. assert((Hi == SSE || Hi == Integer || Hi == X87Up) && "Unknown missing lo part"); break; // AMD64-ABI 3.2.3p3: Rule 1. If the class is MEMORY, pass the argument // on the stack. case Memory: // AMD64-ABI 3.2.3p3: Rule 5. If the class is X87, X87UP or // COMPLEX_X87, it is passed in memory. case X87: case ComplexX87: if (getRecordArgABI(Ty, getCXXABI()) == CGCXXABI::RAA_Indirect) ++neededInt; return getIndirectResult(Ty, freeIntRegs); case SSEUp: case X87Up: llvm_unreachable("Invalid classification for lo word."); // AMD64-ABI 3.2.3p3: Rule 2. If the class is INTEGER, the next // available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8 // and %r9 is used. case Integer: ++neededInt; // Pick an 8-byte type based on the preferred type. ResType = GetINTEGERTypeAtOffset(CGT.ConvertType(Ty), 0, Ty, 0); // If we have a sign or zero extended integer, make sure to return Extend // so that the parameter gets the right LLVM IR attributes. if (Hi == NoClass && isa(ResType)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); if (Ty->isIntegralOrEnumerationType() && Ty->isPromotableIntegerType()) return ABIArgInfo::getExtend(); } break; // AMD64-ABI 3.2.3p3: Rule 3. If the class is SSE, the next // available SSE register is used, the registers are taken in the // order from %xmm0 to %xmm7. case SSE: { llvm::Type *IRType = CGT.ConvertType(Ty); ResType = GetSSETypeAtOffset(IRType, 0, Ty, 0); ++neededSSE; break; } } llvm::Type *HighPart = nullptr; switch (Hi) { // Memory was handled previously, ComplexX87 and X87 should // never occur as hi classes, and X87Up must be preceded by X87, // which is passed in memory. case Memory: case X87: case ComplexX87: llvm_unreachable("Invalid classification for hi word."); case NoClass: break; case Integer: ++neededInt; // Pick an 8-byte type based on the preferred type. HighPart = GetINTEGERTypeAtOffset(CGT.ConvertType(Ty), 8, Ty, 8); if (Lo == NoClass) // Pass HighPart at offset 8 in memory. return ABIArgInfo::getDirect(HighPart, 8); break; // X87Up generally doesn't occur here (long double is passed in // memory), except in situations involving unions. case X87Up: case SSE: HighPart = GetSSETypeAtOffset(CGT.ConvertType(Ty), 8, Ty, 8); if (Lo == NoClass) // Pass HighPart at offset 8 in memory. return ABIArgInfo::getDirect(HighPart, 8); ++neededSSE; break; // AMD64-ABI 3.2.3p3: Rule 4. If the class is SSEUP, the // eightbyte is passed in the upper half of the last used SSE // register. This only happens when 128-bit vectors are passed. case SSEUp: assert(Lo == SSE && "Unexpected SSEUp classification"); ResType = GetByteVectorType(Ty); break; } // If a high part was specified, merge it together with the low part. It is // known to pass in the high eightbyte of the result. We do this by forming a // first class struct aggregate with the high and low part: {low, high} if (HighPart) ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getDataLayout()); return ABIArgInfo::getDirect(ResType); } void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); // Keep track of the number of assigned registers. unsigned freeIntRegs = 6, freeSSERegs = 8; // If the return value is indirect, then the hidden argument is consuming one // integer register. if (FI.getReturnInfo().isIndirect()) --freeIntRegs; // The chain argument effectively gives us another free register. if (FI.isChainCall()) ++freeIntRegs; unsigned NumRequiredArgs = FI.getNumRequiredArgs(); // AMD64-ABI 3.2.3p3: Once arguments are classified, the registers // get assigned (in left-to-right order) for passing as follows... unsigned ArgNo = 0; for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it, ++ArgNo) { bool IsNamedArg = ArgNo < NumRequiredArgs; unsigned neededInt, neededSSE; it->info = classifyArgumentType(it->type, freeIntRegs, neededInt, neededSSE, IsNamedArg); // AMD64-ABI 3.2.3p3: If there are no registers available for any // eightbyte of an argument, the whole argument is passed on the // stack. If registers have already been assigned for some // eightbytes of such an argument, the assignments get reverted. if (freeIntRegs >= neededInt && freeSSERegs >= neededSSE) { freeIntRegs -= neededInt; freeSSERegs -= neededSSE; } else { it->info = getIndirectResult(it->type, freeIntRegs); } } } static Address EmitX86_64VAArgFromMemory(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) { Address overflow_arg_area_p = CGF.Builder.CreateStructGEP( VAListAddr, 2, CharUnits::fromQuantity(8), "overflow_arg_area_p"); llvm::Value *overflow_arg_area = CGF.Builder.CreateLoad(overflow_arg_area_p, "overflow_arg_area"); // AMD64-ABI 3.5.7p5: Step 7. Align l->overflow_arg_area upwards to a 16 // byte boundary if alignment needed by type exceeds 8 byte boundary. // It isn't stated explicitly in the standard, but in practice we use // alignment greater than 16 where necessary. CharUnits Align = CGF.getContext().getTypeAlignInChars(Ty); if (Align > CharUnits::fromQuantity(8)) { overflow_arg_area = emitRoundPointerUpToAlignment(CGF, overflow_arg_area, Align); } // AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area. llvm::Type *LTy = CGF.ConvertTypeForMem(Ty); llvm::Value *Res = CGF.Builder.CreateBitCast(overflow_arg_area, llvm::PointerType::getUnqual(LTy)); // AMD64-ABI 3.5.7p5: Step 9. Set l->overflow_arg_area to: // l->overflow_arg_area + sizeof(type). // AMD64-ABI 3.5.7p5: Step 10. Align l->overflow_arg_area upwards to // an 8 byte boundary. uint64_t SizeInBytes = (CGF.getContext().getTypeSize(Ty) + 7) / 8; llvm::Value *Offset = llvm::ConstantInt::get(CGF.Int32Ty, (SizeInBytes + 7) & ~7); overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset, "overflow_arg_area.next"); CGF.Builder.CreateStore(overflow_arg_area, overflow_arg_area_p); // AMD64-ABI 3.5.7p5: Step 11. Return the fetched type. return Address(Res, Align); } Address X86_64ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { // Assume that va_list type is correct; should be pointer to LLVM type: // struct { // i32 gp_offset; // i32 fp_offset; // i8* overflow_arg_area; // i8* reg_save_area; // }; unsigned neededInt, neededSSE; Ty = getContext().getCanonicalType(Ty); ABIArgInfo AI = classifyArgumentType(Ty, 0, neededInt, neededSSE, /*isNamedArg*/false); // AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed // in the registers. If not go to step 7. if (!neededInt && !neededSSE) return EmitX86_64VAArgFromMemory(CGF, VAListAddr, Ty); // AMD64-ABI 3.5.7p5: Step 2. Compute num_gp to hold the number of // general purpose registers needed to pass type and num_fp to hold // the number of floating point registers needed. // AMD64-ABI 3.5.7p5: Step 3. Verify whether arguments fit into // registers. In the case: l->gp_offset > 48 - num_gp * 8 or // l->fp_offset > 304 - num_fp * 16 go to step 7. // // NOTE: 304 is a typo, there are (6 * 8 + 8 * 16) = 176 bytes of // register save space). llvm::Value *InRegs = nullptr; Address gp_offset_p = Address::invalid(), fp_offset_p = Address::invalid(); llvm::Value *gp_offset = nullptr, *fp_offset = nullptr; if (neededInt) { gp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, CharUnits::Zero(), "gp_offset_p"); gp_offset = CGF.Builder.CreateLoad(gp_offset_p, "gp_offset"); InRegs = llvm::ConstantInt::get(CGF.Int32Ty, 48 - neededInt * 8); InRegs = CGF.Builder.CreateICmpULE(gp_offset, InRegs, "fits_in_gp"); } if (neededSSE) { fp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 1, CharUnits::fromQuantity(4), "fp_offset_p"); fp_offset = CGF.Builder.CreateLoad(fp_offset_p, "fp_offset"); llvm::Value *FitsInFP = llvm::ConstantInt::get(CGF.Int32Ty, 176 - neededSSE * 16); FitsInFP = CGF.Builder.CreateICmpULE(fp_offset, FitsInFP, "fits_in_fp"); InRegs = InRegs ? CGF.Builder.CreateAnd(InRegs, FitsInFP) : FitsInFP; } llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg"); llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem"); llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end"); CGF.Builder.CreateCondBr(InRegs, InRegBlock, InMemBlock); // Emit code to load the value if it was passed in registers. CGF.EmitBlock(InRegBlock); // AMD64-ABI 3.5.7p5: Step 4. Fetch type from l->reg_save_area with // an offset of l->gp_offset and/or l->fp_offset. This may require // copying to a temporary location in case the parameter is passed // in different register classes or requires an alignment greater // than 8 for general purpose registers and 16 for XMM registers. // // FIXME: This really results in shameful code when we end up needing to // collect arguments from different places; often what should result in a // simple assembling of a structure from scattered addresses has many more // loads than necessary. Can we clean this up? llvm::Type *LTy = CGF.ConvertTypeForMem(Ty); llvm::Value *RegSaveArea = CGF.Builder.CreateLoad( CGF.Builder.CreateStructGEP(VAListAddr, 3, CharUnits::fromQuantity(16)), "reg_save_area"); Address RegAddr = Address::invalid(); if (neededInt && neededSSE) { // FIXME: Cleanup. assert(AI.isDirect() && "Unexpected ABI info for mixed regs"); llvm::StructType *ST = cast(AI.getCoerceToType()); Address Tmp = CGF.CreateMemTemp(Ty); Tmp = CGF.Builder.CreateElementBitCast(Tmp, ST); assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs"); llvm::Type *TyLo = ST->getElementType(0); llvm::Type *TyHi = ST->getElementType(1); assert((TyLo->isFPOrFPVectorTy() ^ TyHi->isFPOrFPVectorTy()) && "Unexpected ABI info for mixed regs"); llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo); llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi); llvm::Value *GPAddr = CGF.Builder.CreateGEP(RegSaveArea, gp_offset); llvm::Value *FPAddr = CGF.Builder.CreateGEP(RegSaveArea, fp_offset); llvm::Value *RegLoAddr = TyLo->isFPOrFPVectorTy() ? FPAddr : GPAddr; llvm::Value *RegHiAddr = TyLo->isFPOrFPVectorTy() ? GPAddr : FPAddr; // Copy the first element. llvm::Value *V = CGF.Builder.CreateDefaultAlignedLoad( CGF.Builder.CreateBitCast(RegLoAddr, PTyLo)); CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0, CharUnits::Zero())); // Copy the second element. V = CGF.Builder.CreateDefaultAlignedLoad( CGF.Builder.CreateBitCast(RegHiAddr, PTyHi)); CharUnits Offset = CharUnits::fromQuantity( getDataLayout().getStructLayout(ST)->getElementOffset(1)); CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1, Offset)); RegAddr = CGF.Builder.CreateElementBitCast(Tmp, LTy); } else if (neededInt) { RegAddr = Address(CGF.Builder.CreateGEP(RegSaveArea, gp_offset), CharUnits::fromQuantity(8)); RegAddr = CGF.Builder.CreateElementBitCast(RegAddr, LTy); // Copy to a temporary if necessary to ensure the appropriate alignment. std::pair SizeAlign = getContext().getTypeInfoInChars(Ty); uint64_t TySize = SizeAlign.first.getQuantity(); CharUnits TyAlign = SizeAlign.second; // Copy into a temporary if the type is more aligned than the // register save area. if (TyAlign.getQuantity() > 8) { Address Tmp = CGF.CreateMemTemp(Ty); CGF.Builder.CreateMemCpy(Tmp, RegAddr, TySize, false); RegAddr = Tmp; } } else if (neededSSE == 1) { RegAddr = Address(CGF.Builder.CreateGEP(RegSaveArea, fp_offset), CharUnits::fromQuantity(16)); RegAddr = CGF.Builder.CreateElementBitCast(RegAddr, LTy); } else { assert(neededSSE == 2 && "Invalid number of needed registers!"); // SSE registers are spaced 16 bytes apart in the register save // area, we need to collect the two eightbytes together. // The ABI isn't explicit about this, but it seems reasonable // to assume that the slots are 16-byte aligned, since the stack is // naturally 16-byte aligned and the prologue is expected to store // all the SSE registers to the RSA. Address RegAddrLo = Address(CGF.Builder.CreateGEP(RegSaveArea, fp_offset), CharUnits::fromQuantity(16)); Address RegAddrHi = CGF.Builder.CreateConstInBoundsByteGEP(RegAddrLo, CharUnits::fromQuantity(16)); llvm::Type *DoubleTy = CGF.DoubleTy; llvm::StructType *ST = llvm::StructType::get(DoubleTy, DoubleTy, nullptr); llvm::Value *V; Address Tmp = CGF.CreateMemTemp(Ty); Tmp = CGF.Builder.CreateElementBitCast(Tmp, ST); V = CGF.Builder.CreateLoad( CGF.Builder.CreateElementBitCast(RegAddrLo, DoubleTy)); CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0, CharUnits::Zero())); V = CGF.Builder.CreateLoad( CGF.Builder.CreateElementBitCast(RegAddrHi, DoubleTy)); CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1, CharUnits::fromQuantity(8))); RegAddr = CGF.Builder.CreateElementBitCast(Tmp, LTy); } // AMD64-ABI 3.5.7p5: Step 5. Set: // l->gp_offset = l->gp_offset + num_gp * 8 // l->fp_offset = l->fp_offset + num_fp * 16. if (neededInt) { llvm::Value *Offset = llvm::ConstantInt::get(CGF.Int32Ty, neededInt * 8); CGF.Builder.CreateStore(CGF.Builder.CreateAdd(gp_offset, Offset), gp_offset_p); } if (neededSSE) { llvm::Value *Offset = llvm::ConstantInt::get(CGF.Int32Ty, neededSSE * 16); CGF.Builder.CreateStore(CGF.Builder.CreateAdd(fp_offset, Offset), fp_offset_p); } CGF.EmitBranch(ContBlock); // Emit code to load the value if it was passed in memory. CGF.EmitBlock(InMemBlock); Address MemAddr = EmitX86_64VAArgFromMemory(CGF, VAListAddr, Ty); // Return the appropriate result. CGF.EmitBlock(ContBlock); Address ResAddr = emitMergePHI(CGF, RegAddr, InRegBlock, MemAddr, InMemBlock, "vaarg.addr"); return ResAddr; } Address X86_64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false, CGF.getContext().getTypeInfoInChars(Ty), CharUnits::fromQuantity(8), /*allowHigherAlign*/ false); } ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, unsigned &FreeSSERegs, bool IsReturnType) const { if (Ty->isVoidType()) return ABIArgInfo::getIgnore(); if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); TypeInfo Info = getContext().getTypeInfo(Ty); uint64_t Width = Info.Width; CharUnits Align = getContext().toCharUnitsFromBits(Info.Align); const RecordType *RT = Ty->getAs(); if (RT) { if (!IsReturnType) { if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); } if (RT->getDecl()->hasFlexibleArrayMember()) return getNaturalAlignIndirect(Ty, /*ByVal=*/false); } // vectorcall adds the concept of a homogenous vector aggregate, similar to // other targets. const Type *Base = nullptr; uint64_t NumElts = 0; if (FreeSSERegs && isHomogeneousAggregate(Ty, Base, NumElts)) { if (FreeSSERegs >= NumElts) { FreeSSERegs -= NumElts; if (IsReturnType || Ty->isBuiltinType() || Ty->isVectorType()) return ABIArgInfo::getDirect(); return ABIArgInfo::getExpand(); } return ABIArgInfo::getIndirect(Align, /*ByVal=*/false); } if (Ty->isMemberPointerType()) { // If the member pointer is represented by an LLVM int or ptr, pass it // directly. llvm::Type *LLTy = CGT.ConvertType(Ty); if (LLTy->isPointerTy() || LLTy->isIntegerTy()) return ABIArgInfo::getDirect(); } if (RT || Ty->isAnyComplexType() || Ty->isMemberPointerType()) { // MS x64 ABI requirement: "Any argument that doesn't fit in 8 bytes, or is // not 1, 2, 4, or 8 bytes, must be passed by reference." if (Width > 64 || !llvm::isPowerOf2_64(Width)) return getNaturalAlignIndirect(Ty, /*ByVal=*/false); // Otherwise, coerce it to a small integer. return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Width)); } // Bool type is always extended to the ABI, other builtin types are not // extended. const BuiltinType *BT = Ty->getAs(); if (BT && BT->getKind() == BuiltinType::Bool) return ABIArgInfo::getExtend(); // Mingw64 GCC uses the old 80 bit extended precision floating point unit. It // passes them indirectly through memory. if (IsMingw64 && BT && BT->getKind() == BuiltinType::LongDouble) { const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat(); if (LDF == &llvm::APFloat::x87DoubleExtended) return ABIArgInfo::getIndirect(Align, /*ByVal=*/false); } return ABIArgInfo::getDirect(); } void WinX86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const { bool IsVectorCall = FI.getCallingConvention() == llvm::CallingConv::X86_VectorCall; // We can use up to 4 SSE return registers with vectorcall. unsigned FreeSSERegs = IsVectorCall ? 4 : 0; if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classify(FI.getReturnType(), FreeSSERegs, true); // We can use up to 6 SSE register parameters with vectorcall. FreeSSERegs = IsVectorCall ? 6 : 0; for (auto &I : FI.arguments()) I.info = classify(I.type, FreeSSERegs, false); } Address WinX86_64ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false, CGF.getContext().getTypeInfoInChars(Ty), CharUnits::fromQuantity(8), /*allowHigherAlign*/ false); } // PowerPC-32 namespace { /// PPC32_SVR4_ABIInfo - The 32-bit PowerPC ELF (SVR4) ABI information. class PPC32_SVR4_ABIInfo : public DefaultABIInfo { bool IsSoftFloatABI; public: PPC32_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, bool SoftFloatABI) : DefaultABIInfo(CGT), IsSoftFloatABI(SoftFloatABI) {} Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; }; class PPC32TargetCodeGenInfo : public TargetCodeGenInfo { public: PPC32TargetCodeGenInfo(CodeGenTypes &CGT, bool SoftFloatABI) : TargetCodeGenInfo(new PPC32_SVR4_ABIInfo(CGT, SoftFloatABI)) {} int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override { // This is recovered from gcc output. return 1; // r1 is the dedicated stack pointer } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; }; } Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList, QualType Ty) const { if (const ComplexType *CTy = Ty->getAs()) { // TODO: Implement this. For now ignore. (void)CTy; return Address::invalid(); } // struct __va_list_tag { // unsigned char gpr; // unsigned char fpr; // unsigned short reserved; // void *overflow_arg_area; // void *reg_save_area; // }; bool isI64 = Ty->isIntegerType() && getContext().getTypeSize(Ty) == 64; bool isInt = Ty->isIntegerType() || Ty->isPointerType() || Ty->isAggregateType(); bool isF64 = Ty->isFloatingType() && getContext().getTypeSize(Ty) == 64; // All aggregates are passed indirectly? That doesn't seem consistent // with the argument-lowering code. bool isIndirect = Ty->isAggregateType(); CGBuilderTy &Builder = CGF.Builder; // The calling convention either uses 1-2 GPRs or 1 FPR. Address NumRegsAddr = Address::invalid(); if (isInt || IsSoftFloatABI) { NumRegsAddr = Builder.CreateStructGEP(VAList, 0, CharUnits::Zero(), "gpr"); } else { NumRegsAddr = Builder.CreateStructGEP(VAList, 1, CharUnits::One(), "fpr"); } llvm::Value *NumRegs = Builder.CreateLoad(NumRegsAddr, "numUsedRegs"); // "Align" the register count when TY is i64. if (isI64 || (isF64 && IsSoftFloatABI)) { NumRegs = Builder.CreateAdd(NumRegs, Builder.getInt8(1)); NumRegs = Builder.CreateAnd(NumRegs, Builder.getInt8((uint8_t) ~1U)); } llvm::Value *CC = Builder.CreateICmpULT(NumRegs, Builder.getInt8(8), "cond"); llvm::BasicBlock *UsingRegs = CGF.createBasicBlock("using_regs"); llvm::BasicBlock *UsingOverflow = CGF.createBasicBlock("using_overflow"); llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); Builder.CreateCondBr(CC, UsingRegs, UsingOverflow); llvm::Type *DirectTy = CGF.ConvertType(Ty); if (isIndirect) DirectTy = DirectTy->getPointerTo(0); // Case 1: consume registers. Address RegAddr = Address::invalid(); { CGF.EmitBlock(UsingRegs); Address RegSaveAreaPtr = Builder.CreateStructGEP(VAList, 4, CharUnits::fromQuantity(8)); RegAddr = Address(Builder.CreateLoad(RegSaveAreaPtr), CharUnits::fromQuantity(8)); assert(RegAddr.getElementType() == CGF.Int8Ty); // Floating-point registers start after the general-purpose registers. if (!(isInt || IsSoftFloatABI)) { RegAddr = Builder.CreateConstInBoundsByteGEP(RegAddr, CharUnits::fromQuantity(32)); } // Get the address of the saved value by scaling the number of // registers we've used by the number of CharUnits RegSize = CharUnits::fromQuantity((isInt || IsSoftFloatABI) ? 4 : 8); llvm::Value *RegOffset = Builder.CreateMul(NumRegs, Builder.getInt8(RegSize.getQuantity())); RegAddr = Address(Builder.CreateInBoundsGEP(CGF.Int8Ty, RegAddr.getPointer(), RegOffset), RegAddr.getAlignment().alignmentOfArrayElement(RegSize)); RegAddr = Builder.CreateElementBitCast(RegAddr, DirectTy); // Increase the used-register count. NumRegs = Builder.CreateAdd(NumRegs, Builder.getInt8((isI64 || (isF64 && IsSoftFloatABI)) ? 2 : 1)); Builder.CreateStore(NumRegs, NumRegsAddr); CGF.EmitBranch(Cont); } // Case 2: consume space in the overflow area. Address MemAddr = Address::invalid(); { CGF.EmitBlock(UsingOverflow); // Everything in the overflow area is rounded up to a size of at least 4. CharUnits OverflowAreaAlign = CharUnits::fromQuantity(4); CharUnits Size; if (!isIndirect) { auto TypeInfo = CGF.getContext().getTypeInfoInChars(Ty); Size = TypeInfo.first.RoundUpToAlignment(OverflowAreaAlign); } else { Size = CGF.getPointerSize(); } Address OverflowAreaAddr = Builder.CreateStructGEP(VAList, 3, CharUnits::fromQuantity(4)); Address OverflowArea(Builder.CreateLoad(OverflowAreaAddr, "argp.cur"), OverflowAreaAlign); // Round up address of argument to alignment CharUnits Align = CGF.getContext().getTypeAlignInChars(Ty); if (Align > OverflowAreaAlign) { llvm::Value *Ptr = OverflowArea.getPointer(); OverflowArea = Address(emitRoundPointerUpToAlignment(CGF, Ptr, Align), Align); } MemAddr = Builder.CreateElementBitCast(OverflowArea, DirectTy); // Increase the overflow area. OverflowArea = Builder.CreateConstInBoundsByteGEP(OverflowArea, Size); Builder.CreateStore(OverflowArea.getPointer(), OverflowAreaAddr); CGF.EmitBranch(Cont); } CGF.EmitBlock(Cont); // Merge the cases with a phi. Address Result = emitMergePHI(CGF, RegAddr, UsingRegs, MemAddr, UsingOverflow, "vaarg.addr"); // Load the pointer if the argument was passed indirectly. if (isIndirect) { Result = Address(Builder.CreateLoad(Result, "aggr"), getContext().getTypeAlignInChars(Ty)); } return Result; } bool PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const { // This is calculated from the LLVM and GCC tables and verified // against gcc output. AFAIK all ABIs use the same encoding. CodeGen::CGBuilderTy &Builder = CGF.Builder; llvm::IntegerType *i8 = CGF.Int8Ty; llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4); llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8); llvm::Value *Sixteen8 = llvm::ConstantInt::get(i8, 16); // 0-31: r0-31, the 4-byte general-purpose registers AssignToArrayRange(Builder, Address, Four8, 0, 31); // 32-63: fp0-31, the 8-byte floating-point registers AssignToArrayRange(Builder, Address, Eight8, 32, 63); // 64-76 are various 4-byte special-purpose registers: // 64: mq // 65: lr // 66: ctr // 67: ap // 68-75 cr0-7 // 76: xer AssignToArrayRange(Builder, Address, Four8, 64, 76); // 77-108: v0-31, the 16-byte vector registers AssignToArrayRange(Builder, Address, Sixteen8, 77, 108); // 109: vrsave // 110: vscr // 111: spe_acc // 112: spefscr // 113: sfp AssignToArrayRange(Builder, Address, Four8, 109, 113); return false; } // PowerPC-64 namespace { /// PPC64_SVR4_ABIInfo - The 64-bit PowerPC ELF (SVR4) ABI information. class PPC64_SVR4_ABIInfo : public DefaultABIInfo { public: enum ABIKind { ELFv1 = 0, ELFv2 }; private: static const unsigned GPRBits = 64; ABIKind Kind; bool HasQPX; // A vector of float or double will be promoted to <4 x f32> or <4 x f64> and // will be passed in a QPX register. bool IsQPXVectorTy(const Type *Ty) const { if (!HasQPX) return false; if (const VectorType *VT = Ty->getAs()) { unsigned NumElements = VT->getNumElements(); if (NumElements == 1) return false; if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::Double)) { if (getContext().getTypeSize(Ty) <= 256) return true; } else if (VT->getElementType()-> isSpecificBuiltinType(BuiltinType::Float)) { if (getContext().getTypeSize(Ty) <= 128) return true; } } return false; } bool IsQPXVectorTy(QualType Ty) const { return IsQPXVectorTy(Ty.getTypePtr()); } public: PPC64_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, ABIKind Kind, bool HasQPX) : DefaultABIInfo(CGT), Kind(Kind), HasQPX(HasQPX) {} bool isPromotableTypeForABI(QualType Ty) const; CharUnits getParamTypeAlignment(QualType Ty) const; ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType Ty) const; bool isHomogeneousAggregateBaseType(QualType Ty) const override; bool isHomogeneousAggregateSmallEnough(const Type *Ty, uint64_t Members) const override; // TODO: We can add more logic to computeInfo to improve performance. // Example: For aggregate arguments that fit in a register, we could // use getDirectInReg (as is done below for structs containing a single // floating-point value) to avoid pushing them to memory on function // entry. This would require changing the logic in PPCISelLowering // when lowering the parameters in the caller and args in the callee. void computeInfo(CGFunctionInfo &FI) const override { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) { // We rely on the default argument classification for the most part. // One exception: An aggregate containing a single floating-point // or vector item must be passed in a register if one is available. const Type *T = isSingleElementStruct(I.type, getContext()); if (T) { const BuiltinType *BT = T->getAs(); if (IsQPXVectorTy(T) || (T->isVectorType() && getContext().getTypeSize(T) == 128) || (BT && BT->isFloatingPoint())) { QualType QT(T, 0); I.info = ABIArgInfo::getDirectInReg(CGT.ConvertType(QT)); continue; } } I.info = classifyArgumentType(I.type); } } Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; }; class PPC64_SVR4_TargetCodeGenInfo : public TargetCodeGenInfo { public: PPC64_SVR4_TargetCodeGenInfo(CodeGenTypes &CGT, PPC64_SVR4_ABIInfo::ABIKind Kind, bool HasQPX) : TargetCodeGenInfo(new PPC64_SVR4_ABIInfo(CGT, Kind, HasQPX)) {} int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override { // This is recovered from gcc output. return 1; // r1 is the dedicated stack pointer } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; }; class PPC64TargetCodeGenInfo : public DefaultTargetCodeGenInfo { public: PPC64TargetCodeGenInfo(CodeGenTypes &CGT) : DefaultTargetCodeGenInfo(CGT) {} int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override { // This is recovered from gcc output. return 1; // r1 is the dedicated stack pointer } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; }; } // Return true if the ABI requires Ty to be passed sign- or zero- // extended to 64 bits. bool PPC64_SVR4_ABIInfo::isPromotableTypeForABI(QualType Ty) const { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); // Promotable integer types are required to be promoted by the ABI. if (Ty->isPromotableIntegerType()) return true; // In addition to the usual promotable integer types, we also need to // extend all 32-bit types, since the ABI requires promotion to 64 bits. if (const BuiltinType *BT = Ty->getAs()) switch (BT->getKind()) { case BuiltinType::Int: case BuiltinType::UInt: return true; default: break; } return false; } /// isAlignedParamType - Determine whether a type requires 16-byte or /// higher alignment in the parameter area. Always returns at least 8. CharUnits PPC64_SVR4_ABIInfo::getParamTypeAlignment(QualType Ty) const { // Complex types are passed just like their elements. if (const ComplexType *CTy = Ty->getAs()) Ty = CTy->getElementType(); // Only vector types of size 16 bytes need alignment (larger types are // passed via reference, smaller types are not aligned). if (IsQPXVectorTy(Ty)) { if (getContext().getTypeSize(Ty) > 128) return CharUnits::fromQuantity(32); return CharUnits::fromQuantity(16); } else if (Ty->isVectorType()) { return CharUnits::fromQuantity(getContext().getTypeSize(Ty) == 128 ? 16 : 8); } // For single-element float/vector structs, we consider the whole type // to have the same alignment requirements as its single element. const Type *AlignAsType = nullptr; const Type *EltType = isSingleElementStruct(Ty, getContext()); if (EltType) { const BuiltinType *BT = EltType->getAs(); if (IsQPXVectorTy(EltType) || (EltType->isVectorType() && getContext().getTypeSize(EltType) == 128) || (BT && BT->isFloatingPoint())) AlignAsType = EltType; } // Likewise for ELFv2 homogeneous aggregates. const Type *Base = nullptr; uint64_t Members = 0; if (!AlignAsType && Kind == ELFv2 && isAggregateTypeForABI(Ty) && isHomogeneousAggregate(Ty, Base, Members)) AlignAsType = Base; // With special case aggregates, only vector base types need alignment. if (AlignAsType && IsQPXVectorTy(AlignAsType)) { if (getContext().getTypeSize(AlignAsType) > 128) return CharUnits::fromQuantity(32); return CharUnits::fromQuantity(16); } else if (AlignAsType) { return CharUnits::fromQuantity(AlignAsType->isVectorType() ? 16 : 8); } // Otherwise, we only need alignment for any aggregate type that // has an alignment requirement of >= 16 bytes. if (isAggregateTypeForABI(Ty) && getContext().getTypeAlign(Ty) >= 128) { if (HasQPX && getContext().getTypeAlign(Ty) >= 256) return CharUnits::fromQuantity(32); return CharUnits::fromQuantity(16); } return CharUnits::fromQuantity(8); } /// isHomogeneousAggregate - Return true if a type is an ELFv2 homogeneous /// aggregate. Base is set to the base element type, and Members is set /// to the number of base elements. bool ABIInfo::isHomogeneousAggregate(QualType Ty, const Type *&Base, uint64_t &Members) const { if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) { uint64_t NElements = AT->getSize().getZExtValue(); if (NElements == 0) return false; if (!isHomogeneousAggregate(AT->getElementType(), Base, Members)) return false; Members *= NElements; } else if (const RecordType *RT = Ty->getAs()) { const RecordDecl *RD = RT->getDecl(); if (RD->hasFlexibleArrayMember()) return false; Members = 0; // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { for (const auto &I : CXXRD->bases()) { // Ignore empty records. if (isEmptyRecord(getContext(), I.getType(), true)) continue; uint64_t FldMembers; if (!isHomogeneousAggregate(I.getType(), Base, FldMembers)) return false; Members += FldMembers; } } for (const auto *FD : RD->fields()) { // Ignore (non-zero arrays of) empty records. QualType FT = FD->getType(); while (const ConstantArrayType *AT = getContext().getAsConstantArrayType(FT)) { if (AT->getSize().getZExtValue() == 0) return false; FT = AT->getElementType(); } if (isEmptyRecord(getContext(), FT, true)) continue; // For compatibility with GCC, ignore empty bitfields in C++ mode. if (getContext().getLangOpts().CPlusPlus && FD->isBitField() && FD->getBitWidthValue(getContext()) == 0) continue; uint64_t FldMembers; if (!isHomogeneousAggregate(FD->getType(), Base, FldMembers)) return false; Members = (RD->isUnion() ? std::max(Members, FldMembers) : Members + FldMembers); } if (!Base) return false; // Ensure there is no padding. if (getContext().getTypeSize(Base) * Members != getContext().getTypeSize(Ty)) return false; } else { Members = 1; if (const ComplexType *CT = Ty->getAs()) { Members = 2; Ty = CT->getElementType(); } // Most ABIs only support float, double, and some vector type widths. if (!isHomogeneousAggregateBaseType(Ty)) return false; // The base type must be the same for all members. Types that // agree in both total size and mode (float vs. vector) are // treated as being equivalent here. const Type *TyPtr = Ty.getTypePtr(); if (!Base) Base = TyPtr; if (Base->isVectorType() != TyPtr->isVectorType() || getContext().getTypeSize(Base) != getContext().getTypeSize(TyPtr)) return false; } return Members > 0 && isHomogeneousAggregateSmallEnough(Base, Members); } bool PPC64_SVR4_ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const { // Homogeneous aggregates for ELFv2 must have base types of float, // double, long double, or 128-bit vectors. if (const BuiltinType *BT = Ty->getAs()) { if (BT->getKind() == BuiltinType::Float || BT->getKind() == BuiltinType::Double || BT->getKind() == BuiltinType::LongDouble) return true; } if (const VectorType *VT = Ty->getAs()) { if (getContext().getTypeSize(VT) == 128 || IsQPXVectorTy(Ty)) return true; } return false; } bool PPC64_SVR4_ABIInfo::isHomogeneousAggregateSmallEnough( const Type *Base, uint64_t Members) const { // Vector types require one register, floating point types require one // or two registers depending on their size. uint32_t NumRegs = Base->isVectorType() ? 1 : (getContext().getTypeSize(Base) + 63) / 64; // Homogeneous Aggregates may occupy at most 8 registers. return Members * NumRegs <= 8; } ABIArgInfo PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const { Ty = useFirstFieldIfTransparentUnion(Ty); if (Ty->isAnyComplexType()) return ABIArgInfo::getDirect(); // Non-Altivec vector types are passed in GPRs (smaller than 16 bytes) // or via reference (larger than 16 bytes). if (Ty->isVectorType() && !IsQPXVectorTy(Ty)) { uint64_t Size = getContext().getTypeSize(Ty); if (Size > 128) return getNaturalAlignIndirect(Ty, /*ByVal=*/false); else if (Size < 128) { llvm::Type *CoerceTy = llvm::IntegerType::get(getVMContext(), Size); return ABIArgInfo::getDirect(CoerceTy); } } if (isAggregateTypeForABI(Ty)) { if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); uint64_t ABIAlign = getParamTypeAlignment(Ty).getQuantity(); uint64_t TyAlign = getContext().getTypeAlignInChars(Ty).getQuantity(); // ELFv2 homogeneous aggregates are passed as array types. const Type *Base = nullptr; uint64_t Members = 0; if (Kind == ELFv2 && isHomogeneousAggregate(Ty, Base, Members)) { llvm::Type *BaseTy = CGT.ConvertType(QualType(Base, 0)); llvm::Type *CoerceTy = llvm::ArrayType::get(BaseTy, Members); return ABIArgInfo::getDirect(CoerceTy); } // If an aggregate may end up fully in registers, we do not // use the ByVal method, but pass the aggregate as array. // This is usually beneficial since we avoid forcing the // back-end to store the argument to memory. uint64_t Bits = getContext().getTypeSize(Ty); if (Bits > 0 && Bits <= 8 * GPRBits) { llvm::Type *CoerceTy; // Types up to 8 bytes are passed as integer type (which will be // properly aligned in the argument save area doubleword). if (Bits <= GPRBits) CoerceTy = llvm::IntegerType::get(getVMContext(), llvm::RoundUpToAlignment(Bits, 8)); // Larger types are passed as arrays, with the base type selected // according to the required alignment in the save area. else { uint64_t RegBits = ABIAlign * 8; uint64_t NumRegs = llvm::RoundUpToAlignment(Bits, RegBits) / RegBits; llvm::Type *RegTy = llvm::IntegerType::get(getVMContext(), RegBits); CoerceTy = llvm::ArrayType::get(RegTy, NumRegs); } return ABIArgInfo::getDirect(CoerceTy); } // All other aggregates are passed ByVal. return ABIArgInfo::getIndirect(CharUnits::fromQuantity(ABIAlign), /*ByVal=*/true, /*Realign=*/TyAlign > ABIAlign); } return (isPromotableTypeForABI(Ty) ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } ABIArgInfo PPC64_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); if (RetTy->isAnyComplexType()) return ABIArgInfo::getDirect(); // Non-Altivec vector types are returned in GPRs (smaller than 16 bytes) // or via reference (larger than 16 bytes). if (RetTy->isVectorType() && !IsQPXVectorTy(RetTy)) { uint64_t Size = getContext().getTypeSize(RetTy); if (Size > 128) return getNaturalAlignIndirect(RetTy); else if (Size < 128) { llvm::Type *CoerceTy = llvm::IntegerType::get(getVMContext(), Size); return ABIArgInfo::getDirect(CoerceTy); } } if (isAggregateTypeForABI(RetTy)) { // ELFv2 homogeneous aggregates are returned as array types. const Type *Base = nullptr; uint64_t Members = 0; if (Kind == ELFv2 && isHomogeneousAggregate(RetTy, Base, Members)) { llvm::Type *BaseTy = CGT.ConvertType(QualType(Base, 0)); llvm::Type *CoerceTy = llvm::ArrayType::get(BaseTy, Members); return ABIArgInfo::getDirect(CoerceTy); } // ELFv2 small aggregates are returned in up to two registers. uint64_t Bits = getContext().getTypeSize(RetTy); if (Kind == ELFv2 && Bits <= 2 * GPRBits) { if (Bits == 0) return ABIArgInfo::getIgnore(); llvm::Type *CoerceTy; if (Bits > GPRBits) { CoerceTy = llvm::IntegerType::get(getVMContext(), GPRBits); CoerceTy = llvm::StructType::get(CoerceTy, CoerceTy, nullptr); } else CoerceTy = llvm::IntegerType::get(getVMContext(), llvm::RoundUpToAlignment(Bits, 8)); return ABIArgInfo::getDirect(CoerceTy); } // All other aggregates are returned indirectly. return getNaturalAlignIndirect(RetTy); } return (isPromotableTypeForABI(RetTy) ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } // Based on ARMABIInfo::EmitVAArg, adjusted for 64-bit machine. Address PPC64_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { auto TypeInfo = getContext().getTypeInfoInChars(Ty); TypeInfo.second = getParamTypeAlignment(Ty); CharUnits SlotSize = CharUnits::fromQuantity(8); // If we have a complex type and the base type is smaller than 8 bytes, // the ABI calls for the real and imaginary parts to be right-adjusted // in separate doublewords. However, Clang expects us to produce a // pointer to a structure with the two parts packed tightly. So generate // loads of the real and imaginary parts relative to the va_list pointer, // and store them to a temporary structure. if (const ComplexType *CTy = Ty->getAs()) { CharUnits EltSize = TypeInfo.first / 2; if (EltSize < SlotSize) { Address Addr = emitVoidPtrDirectVAArg(CGF, VAListAddr, CGF.Int8Ty, SlotSize * 2, SlotSize, SlotSize, /*AllowHigher*/ true); Address RealAddr = Addr; Address ImagAddr = RealAddr; if (CGF.CGM.getDataLayout().isBigEndian()) { RealAddr = CGF.Builder.CreateConstInBoundsByteGEP(RealAddr, SlotSize - EltSize); ImagAddr = CGF.Builder.CreateConstInBoundsByteGEP(ImagAddr, 2 * SlotSize - EltSize); } else { ImagAddr = CGF.Builder.CreateConstInBoundsByteGEP(RealAddr, SlotSize); } llvm::Type *EltTy = CGF.ConvertTypeForMem(CTy->getElementType()); RealAddr = CGF.Builder.CreateElementBitCast(RealAddr, EltTy); ImagAddr = CGF.Builder.CreateElementBitCast(ImagAddr, EltTy); llvm::Value *Real = CGF.Builder.CreateLoad(RealAddr, ".vareal"); llvm::Value *Imag = CGF.Builder.CreateLoad(ImagAddr, ".vaimag"); Address Temp = CGF.CreateMemTemp(Ty, "vacplx"); CGF.EmitStoreOfComplex({Real, Imag}, CGF.MakeAddrLValue(Temp, Ty), /*init*/ true); return Temp; } } // Otherwise, just use the general rule. return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*Indirect*/ false, TypeInfo, SlotSize, /*AllowHigher*/ true); } static bool PPC64_initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) { // This is calculated from the LLVM and GCC tables and verified // against gcc output. AFAIK all ABIs use the same encoding. CodeGen::CGBuilderTy &Builder = CGF.Builder; llvm::IntegerType *i8 = CGF.Int8Ty; llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4); llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8); llvm::Value *Sixteen8 = llvm::ConstantInt::get(i8, 16); // 0-31: r0-31, the 8-byte general-purpose registers AssignToArrayRange(Builder, Address, Eight8, 0, 31); // 32-63: fp0-31, the 8-byte floating-point registers AssignToArrayRange(Builder, Address, Eight8, 32, 63); // 64-76 are various 4-byte special-purpose registers: // 64: mq // 65: lr // 66: ctr // 67: ap // 68-75 cr0-7 // 76: xer AssignToArrayRange(Builder, Address, Four8, 64, 76); // 77-108: v0-31, the 16-byte vector registers AssignToArrayRange(Builder, Address, Sixteen8, 77, 108); // 109: vrsave // 110: vscr // 111: spe_acc // 112: spefscr // 113: sfp AssignToArrayRange(Builder, Address, Four8, 109, 113); return false; } bool PPC64_SVR4_TargetCodeGenInfo::initDwarfEHRegSizeTable( CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const { return PPC64_initDwarfEHRegSizeTable(CGF, Address); } bool PPC64TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const { return PPC64_initDwarfEHRegSizeTable(CGF, Address); } //===----------------------------------------------------------------------===// // AArch64 ABI Implementation //===----------------------------------------------------------------------===// namespace { class AArch64ABIInfo : public ABIInfo { public: enum ABIKind { AAPCS = 0, DarwinPCS }; private: ABIKind Kind; public: AArch64ABIInfo(CodeGenTypes &CGT, ABIKind Kind) : ABIInfo(CGT), Kind(Kind) {} private: ABIKind getABIKind() const { return Kind; } bool isDarwinPCS() const { return Kind == DarwinPCS; } ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType RetTy) const; bool isHomogeneousAggregateBaseType(QualType Ty) const override; bool isHomogeneousAggregateSmallEnough(const Type *Ty, uint64_t Members) const override; bool isIllegalVectorType(QualType Ty) const; void computeInfo(CGFunctionInfo &FI) const override { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &it : FI.arguments()) it.info = classifyArgumentType(it.type); } Address EmitDarwinVAArg(Address VAListAddr, QualType Ty, CodeGenFunction &CGF) const; Address EmitAAPCSVAArg(Address VAListAddr, QualType Ty, CodeGenFunction &CGF) const; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override { return isDarwinPCS() ? EmitDarwinVAArg(VAListAddr, Ty, CGF) : EmitAAPCSVAArg(VAListAddr, Ty, CGF); } }; class AArch64TargetCodeGenInfo : public TargetCodeGenInfo { public: AArch64TargetCodeGenInfo(CodeGenTypes &CGT, AArch64ABIInfo::ABIKind Kind) : TargetCodeGenInfo(new AArch64ABIInfo(CGT, Kind)) {} StringRef getARCRetainAutoreleasedReturnValueMarker() const override { return "mov\tfp, fp\t\t; marker for objc_retainAutoreleaseReturnValue"; } int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override { return 31; } bool doesReturnSlotInterfereWithArgs() const override { return false; } }; } ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty) const { Ty = useFirstFieldIfTransparentUnion(Ty); // Handle illegal vector types here. if (isIllegalVectorType(Ty)) { uint64_t Size = getContext().getTypeSize(Ty); if (Size <= 32) { llvm::Type *ResType = llvm::Type::getInt32Ty(getVMContext()); return ABIArgInfo::getDirect(ResType); } if (Size == 64) { llvm::Type *ResType = llvm::VectorType::get(llvm::Type::getInt32Ty(getVMContext()), 2); return ABIArgInfo::getDirect(ResType); } if (Size == 128) { llvm::Type *ResType = llvm::VectorType::get(llvm::Type::getInt32Ty(getVMContext()), 4); return ABIArgInfo::getDirect(ResType); } return getNaturalAlignIndirect(Ty, /*ByVal=*/false); } if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); return (Ty->isPromotableIntegerType() && isDarwinPCS() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } // Structures with either a non-trivial destructor or a non-trivial // copy constructor are always indirect. if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA == CGCXXABI::RAA_DirectInMemory); } // Empty records are always ignored on Darwin, but actually passed in C++ mode // elsewhere for GNU compatibility. if (isEmptyRecord(getContext(), Ty, true)) { if (!getContext().getLangOpts().CPlusPlus || isDarwinPCS()) return ABIArgInfo::getIgnore(); return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext())); } // Homogeneous Floating-point Aggregates (HFAs) need to be expanded. const Type *Base = nullptr; uint64_t Members = 0; if (isHomogeneousAggregate(Ty, Base, Members)) { return ABIArgInfo::getDirect( llvm::ArrayType::get(CGT.ConvertType(QualType(Base, 0)), Members)); } // Aggregates <= 16 bytes are passed directly in registers or on the stack. uint64_t Size = getContext().getTypeSize(Ty); if (Size <= 128) { unsigned Alignment = getContext().getTypeAlign(Ty); Size = 64 * ((Size + 63) / 64); // round up to multiple of 8 bytes // We use a pair of i64 for 16-byte aggregate with 8-byte alignment. // For aggregates with 16-byte alignment, we use i128. if (Alignment < 128 && Size == 128) { llvm::Type *BaseTy = llvm::Type::getInt64Ty(getVMContext()); return ABIArgInfo::getDirect(llvm::ArrayType::get(BaseTy, Size / 64)); } return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); } return getNaturalAlignIndirect(Ty, /*ByVal=*/false); } ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); // Large vector types should be returned via memory. if (RetTy->isVectorType() && getContext().getTypeSize(RetTy) > 128) return getNaturalAlignIndirect(RetTy); if (!isAggregateTypeForABI(RetTy)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); return (RetTy->isPromotableIntegerType() && isDarwinPCS() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } if (isEmptyRecord(getContext(), RetTy, true)) return ABIArgInfo::getIgnore(); const Type *Base = nullptr; uint64_t Members = 0; if (isHomogeneousAggregate(RetTy, Base, Members)) // Homogeneous Floating-point Aggregates (HFAs) are returned directly. return ABIArgInfo::getDirect(); // Aggregates <= 16 bytes are returned directly in registers or on the stack. uint64_t Size = getContext().getTypeSize(RetTy); if (Size <= 128) { unsigned Alignment = getContext().getTypeAlign(RetTy); Size = 64 * ((Size + 63) / 64); // round up to multiple of 8 bytes // We use a pair of i64 for 16-byte aggregate with 8-byte alignment. // For aggregates with 16-byte alignment, we use i128. if (Alignment < 128 && Size == 128) { llvm::Type *BaseTy = llvm::Type::getInt64Ty(getVMContext()); return ABIArgInfo::getDirect(llvm::ArrayType::get(BaseTy, Size / 64)); } return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); } return getNaturalAlignIndirect(RetTy); } /// isIllegalVectorType - check whether the vector type is legal for AArch64. bool AArch64ABIInfo::isIllegalVectorType(QualType Ty) const { if (const VectorType *VT = Ty->getAs()) { // Check whether VT is legal. unsigned NumElements = VT->getNumElements(); uint64_t Size = getContext().getTypeSize(VT); // NumElements should be power of 2 between 1 and 16. if ((NumElements & (NumElements - 1)) != 0 || NumElements > 16) return true; return Size != 64 && (Size != 128 || NumElements == 1); } return false; } bool AArch64ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const { // Homogeneous aggregates for AAPCS64 must have base types of a floating // point type or a short-vector type. This is the same as the 32-bit ABI, // but with the difference that any floating-point type is allowed, // including __fp16. if (const BuiltinType *BT = Ty->getAs()) { if (BT->isFloatingPoint()) return true; } else if (const VectorType *VT = Ty->getAs()) { unsigned VecSize = getContext().getTypeSize(VT); if (VecSize == 64 || VecSize == 128) return true; } return false; } bool AArch64ABIInfo::isHomogeneousAggregateSmallEnough(const Type *Base, uint64_t Members) const { return Members <= 4; } Address AArch64ABIInfo::EmitAAPCSVAArg(Address VAListAddr, QualType Ty, CodeGenFunction &CGF) const { ABIArgInfo AI = classifyArgumentType(Ty); bool IsIndirect = AI.isIndirect(); llvm::Type *BaseTy = CGF.ConvertType(Ty); if (IsIndirect) BaseTy = llvm::PointerType::getUnqual(BaseTy); else if (AI.getCoerceToType()) BaseTy = AI.getCoerceToType(); unsigned NumRegs = 1; if (llvm::ArrayType *ArrTy = dyn_cast(BaseTy)) { BaseTy = ArrTy->getElementType(); NumRegs = ArrTy->getNumElements(); } bool IsFPR = BaseTy->isFloatingPointTy() || BaseTy->isVectorTy(); // The AArch64 va_list type and handling is specified in the Procedure Call // Standard, section B.4: // // struct { // void *__stack; // void *__gr_top; // void *__vr_top; // int __gr_offs; // int __vr_offs; // }; llvm::BasicBlock *MaybeRegBlock = CGF.createBasicBlock("vaarg.maybe_reg"); llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg"); llvm::BasicBlock *OnStackBlock = CGF.createBasicBlock("vaarg.on_stack"); llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end"); auto TyInfo = getContext().getTypeInfoInChars(Ty); CharUnits TyAlign = TyInfo.second; Address reg_offs_p = Address::invalid(); llvm::Value *reg_offs = nullptr; int reg_top_index; CharUnits reg_top_offset; int RegSize = IsIndirect ? 8 : TyInfo.first.getQuantity(); if (!IsFPR) { // 3 is the field number of __gr_offs reg_offs_p = CGF.Builder.CreateStructGEP(VAListAddr, 3, CharUnits::fromQuantity(24), "gr_offs_p"); reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "gr_offs"); reg_top_index = 1; // field number for __gr_top reg_top_offset = CharUnits::fromQuantity(8); RegSize = llvm::RoundUpToAlignment(RegSize, 8); } else { // 4 is the field number of __vr_offs. reg_offs_p = CGF.Builder.CreateStructGEP(VAListAddr, 4, CharUnits::fromQuantity(28), "vr_offs_p"); reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "vr_offs"); reg_top_index = 2; // field number for __vr_top reg_top_offset = CharUnits::fromQuantity(16); RegSize = 16 * NumRegs; } //======================================= // Find out where argument was passed //======================================= // If reg_offs >= 0 we're already using the stack for this type of // argument. We don't want to keep updating reg_offs (in case it overflows, // though anyone passing 2GB of arguments, each at most 16 bytes, deserves // whatever they get). llvm::Value *UsingStack = nullptr; UsingStack = CGF.Builder.CreateICmpSGE( reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, 0)); CGF.Builder.CreateCondBr(UsingStack, OnStackBlock, MaybeRegBlock); // Otherwise, at least some kind of argument could go in these registers, the // question is whether this particular type is too big. CGF.EmitBlock(MaybeRegBlock); // Integer arguments may need to correct register alignment (for example a // "struct { __int128 a; };" gets passed in x_2N, x_{2N+1}). In this case we // align __gr_offs to calculate the potential address. if (!IsFPR && !IsIndirect && TyAlign.getQuantity() > 8) { int Align = TyAlign.getQuantity(); reg_offs = CGF.Builder.CreateAdd( reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, Align - 1), "align_regoffs"); reg_offs = CGF.Builder.CreateAnd( reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, -Align), "aligned_regoffs"); } // Update the gr_offs/vr_offs pointer for next call to va_arg on this va_list. // The fact that this is done unconditionally reflects the fact that // allocating an argument to the stack also uses up all the remaining // registers of the appropriate kind. llvm::Value *NewOffset = nullptr; NewOffset = CGF.Builder.CreateAdd( reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, RegSize), "new_reg_offs"); CGF.Builder.CreateStore(NewOffset, reg_offs_p); // Now we're in a position to decide whether this argument really was in // registers or not. llvm::Value *InRegs = nullptr; InRegs = CGF.Builder.CreateICmpSLE( NewOffset, llvm::ConstantInt::get(CGF.Int32Ty, 0), "inreg"); CGF.Builder.CreateCondBr(InRegs, InRegBlock, OnStackBlock); //======================================= // Argument was in registers //======================================= // Now we emit the code for if the argument was originally passed in // registers. First start the appropriate block: CGF.EmitBlock(InRegBlock); llvm::Value *reg_top = nullptr; Address reg_top_p = CGF.Builder.CreateStructGEP(VAListAddr, reg_top_index, reg_top_offset, "reg_top_p"); reg_top = CGF.Builder.CreateLoad(reg_top_p, "reg_top"); Address BaseAddr(CGF.Builder.CreateInBoundsGEP(reg_top, reg_offs), CharUnits::fromQuantity(IsFPR ? 16 : 8)); Address RegAddr = Address::invalid(); llvm::Type *MemTy = CGF.ConvertTypeForMem(Ty); if (IsIndirect) { // If it's been passed indirectly (actually a struct), whatever we find from // stored registers or on the stack will actually be a struct **. MemTy = llvm::PointerType::getUnqual(MemTy); } const Type *Base = nullptr; uint64_t NumMembers = 0; bool IsHFA = isHomogeneousAggregate(Ty, Base, NumMembers); if (IsHFA && NumMembers > 1) { // Homogeneous aggregates passed in registers will have their elements split // and stored 16-bytes apart regardless of size (they're notionally in qN, // qN+1, ...). We reload and store into a temporary local variable // contiguously. assert(!IsIndirect && "Homogeneous aggregates should be passed directly"); auto BaseTyInfo = getContext().getTypeInfoInChars(QualType(Base, 0)); llvm::Type *BaseTy = CGF.ConvertType(QualType(Base, 0)); llvm::Type *HFATy = llvm::ArrayType::get(BaseTy, NumMembers); Address Tmp = CGF.CreateTempAlloca(HFATy, std::max(TyAlign, BaseTyInfo.second)); // On big-endian platforms, the value will be right-aligned in its slot. int Offset = 0; if (CGF.CGM.getDataLayout().isBigEndian() && BaseTyInfo.first.getQuantity() < 16) Offset = 16 - BaseTyInfo.first.getQuantity(); for (unsigned i = 0; i < NumMembers; ++i) { CharUnits BaseOffset = CharUnits::fromQuantity(16 * i + Offset); Address LoadAddr = CGF.Builder.CreateConstInBoundsByteGEP(BaseAddr, BaseOffset); LoadAddr = CGF.Builder.CreateElementBitCast(LoadAddr, BaseTy); Address StoreAddr = CGF.Builder.CreateConstArrayGEP(Tmp, i, BaseTyInfo.first); llvm::Value *Elem = CGF.Builder.CreateLoad(LoadAddr); CGF.Builder.CreateStore(Elem, StoreAddr); } RegAddr = CGF.Builder.CreateElementBitCast(Tmp, MemTy); } else { // Otherwise the object is contiguous in memory. // It might be right-aligned in its slot. CharUnits SlotSize = BaseAddr.getAlignment(); if (CGF.CGM.getDataLayout().isBigEndian() && !IsIndirect && (IsHFA || !isAggregateTypeForABI(Ty)) && TyInfo.first < SlotSize) { CharUnits Offset = SlotSize - TyInfo.first; BaseAddr = CGF.Builder.CreateConstInBoundsByteGEP(BaseAddr, Offset); } RegAddr = CGF.Builder.CreateElementBitCast(BaseAddr, MemTy); } CGF.EmitBranch(ContBlock); //======================================= // Argument was on the stack //======================================= CGF.EmitBlock(OnStackBlock); Address stack_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, CharUnits::Zero(), "stack_p"); llvm::Value *OnStackPtr = CGF.Builder.CreateLoad(stack_p, "stack"); // Again, stack arguments may need realignment. In this case both integer and // floating-point ones might be affected. if (!IsIndirect && TyAlign.getQuantity() > 8) { int Align = TyAlign.getQuantity(); OnStackPtr = CGF.Builder.CreatePtrToInt(OnStackPtr, CGF.Int64Ty); OnStackPtr = CGF.Builder.CreateAdd( OnStackPtr, llvm::ConstantInt::get(CGF.Int64Ty, Align - 1), "align_stack"); OnStackPtr = CGF.Builder.CreateAnd( OnStackPtr, llvm::ConstantInt::get(CGF.Int64Ty, -Align), "align_stack"); OnStackPtr = CGF.Builder.CreateIntToPtr(OnStackPtr, CGF.Int8PtrTy); } Address OnStackAddr(OnStackPtr, std::max(CharUnits::fromQuantity(8), TyAlign)); // All stack slots are multiples of 8 bytes. CharUnits StackSlotSize = CharUnits::fromQuantity(8); CharUnits StackSize; if (IsIndirect) StackSize = StackSlotSize; else StackSize = TyInfo.first.RoundUpToAlignment(StackSlotSize); llvm::Value *StackSizeC = CGF.Builder.getSize(StackSize); llvm::Value *NewStack = CGF.Builder.CreateInBoundsGEP(OnStackPtr, StackSizeC, "new_stack"); // Write the new value of __stack for the next call to va_arg CGF.Builder.CreateStore(NewStack, stack_p); if (CGF.CGM.getDataLayout().isBigEndian() && !isAggregateTypeForABI(Ty) && TyInfo.first < StackSlotSize) { CharUnits Offset = StackSlotSize - TyInfo.first; OnStackAddr = CGF.Builder.CreateConstInBoundsByteGEP(OnStackAddr, Offset); } OnStackAddr = CGF.Builder.CreateElementBitCast(OnStackAddr, MemTy); CGF.EmitBranch(ContBlock); //======================================= // Tidy up //======================================= CGF.EmitBlock(ContBlock); Address ResAddr = emitMergePHI(CGF, RegAddr, InRegBlock, OnStackAddr, OnStackBlock, "vaargs.addr"); if (IsIndirect) return Address(CGF.Builder.CreateLoad(ResAddr, "vaarg.addr"), TyInfo.second); return ResAddr; } Address AArch64ABIInfo::EmitDarwinVAArg(Address VAListAddr, QualType Ty, CodeGenFunction &CGF) const { // The backend's lowering doesn't support va_arg for aggregates or // illegal vector types. Lower VAArg here for these cases and use // the LLVM va_arg instruction for everything else. if (!isAggregateTypeForABI(Ty) && !isIllegalVectorType(Ty)) return Address::invalid(); CharUnits SlotSize = CharUnits::fromQuantity(8); // Empty records are ignored for parameter passing purposes. if (isEmptyRecord(getContext(), Ty, true)) { Address Addr(CGF.Builder.CreateLoad(VAListAddr, "ap.cur"), SlotSize); Addr = CGF.Builder.CreateElementBitCast(Addr, CGF.ConvertTypeForMem(Ty)); return Addr; } // The size of the actual thing passed, which might end up just // being a pointer for indirect types. auto TyInfo = getContext().getTypeInfoInChars(Ty); // Arguments bigger than 16 bytes which aren't homogeneous // aggregates should be passed indirectly. bool IsIndirect = false; if (TyInfo.first.getQuantity() > 16) { const Type *Base = nullptr; uint64_t Members = 0; IsIndirect = !isHomogeneousAggregate(Ty, Base, Members); } return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, TyInfo, SlotSize, /*AllowHigherAlign*/ true); } //===----------------------------------------------------------------------===// // ARM ABI Implementation //===----------------------------------------------------------------------===// namespace { class ARMABIInfo : public ABIInfo { public: enum ABIKind { APCS = 0, AAPCS = 1, AAPCS_VFP = 2, AAPCS16_VFP = 3, }; private: ABIKind Kind; public: ARMABIInfo(CodeGenTypes &CGT, ABIKind _Kind) : ABIInfo(CGT), Kind(_Kind) { setCCs(); } bool isEABI() const { switch (getTarget().getTriple().getEnvironment()) { case llvm::Triple::Android: case llvm::Triple::EABI: case llvm::Triple::EABIHF: case llvm::Triple::GNUEABI: case llvm::Triple::GNUEABIHF: return true; default: return false; } } bool isEABIHF() const { switch (getTarget().getTriple().getEnvironment()) { case llvm::Triple::EABIHF: case llvm::Triple::GNUEABIHF: return true; default: return false; } } bool isAndroid() const { return (getTarget().getTriple().getEnvironment() == llvm::Triple::Android); } ABIKind getABIKind() const { return Kind; } private: ABIArgInfo classifyReturnType(QualType RetTy, bool isVariadic) const; ABIArgInfo classifyArgumentType(QualType RetTy, bool isVariadic) const; bool isIllegalVectorType(QualType Ty) const; bool isHomogeneousAggregateBaseType(QualType Ty) const override; bool isHomogeneousAggregateSmallEnough(const Type *Ty, uint64_t Members) const override; void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; llvm::CallingConv::ID getLLVMDefaultCC() const; llvm::CallingConv::ID getABIDefaultCC() const; void setCCs(); }; class ARMTargetCodeGenInfo : public TargetCodeGenInfo { public: ARMTargetCodeGenInfo(CodeGenTypes &CGT, ARMABIInfo::ABIKind K) :TargetCodeGenInfo(new ARMABIInfo(CGT, K)) {} const ARMABIInfo &getABIInfo() const { return static_cast(TargetCodeGenInfo::getABIInfo()); } int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override { return 13; } StringRef getARCRetainAutoreleasedReturnValueMarker() const override { return "mov\tr7, r7\t\t@ marker for objc_retainAutoreleaseReturnValue"; } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override { llvm::Value *Four8 = llvm::ConstantInt::get(CGF.Int8Ty, 4); // 0-15 are the 16 integer registers. AssignToArrayRange(CGF.Builder, Address, Four8, 0, 15); return false; } unsigned getSizeOfUnwindException() const override { if (getABIInfo().isEABI()) return 88; return TargetCodeGenInfo::getSizeOfUnwindException(); } void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override { const FunctionDecl *FD = dyn_cast_or_null(D); if (!FD) return; const ARMInterruptAttr *Attr = FD->getAttr(); if (!Attr) return; const char *Kind; switch (Attr->getInterrupt()) { case ARMInterruptAttr::Generic: Kind = ""; break; case ARMInterruptAttr::IRQ: Kind = "IRQ"; break; case ARMInterruptAttr::FIQ: Kind = "FIQ"; break; case ARMInterruptAttr::SWI: Kind = "SWI"; break; case ARMInterruptAttr::ABORT: Kind = "ABORT"; break; case ARMInterruptAttr::UNDEF: Kind = "UNDEF"; break; } llvm::Function *Fn = cast(GV); Fn->addFnAttr("interrupt", Kind); ARMABIInfo::ABIKind ABI = cast(getABIInfo()).getABIKind(); if (ABI == ARMABIInfo::APCS) return; // AAPCS guarantees that sp will be 8-byte aligned on any public interface, // however this is not necessarily true on taking any interrupt. Instruct // the backend to perform a realignment as part of the function prologue. llvm::AttrBuilder B; B.addStackAlignmentAttr(8); Fn->addAttributes(llvm::AttributeSet::FunctionIndex, llvm::AttributeSet::get(CGM.getLLVMContext(), llvm::AttributeSet::FunctionIndex, B)); } }; class WindowsARMTargetCodeGenInfo : public ARMTargetCodeGenInfo { - void addStackProbeSizeTargetAttribute(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &CGM) const; - public: WindowsARMTargetCodeGenInfo(CodeGenTypes &CGT, ARMABIInfo::ABIKind K) : ARMTargetCodeGenInfo(CGT, K) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override; }; - -void WindowsARMTargetCodeGenInfo::addStackProbeSizeTargetAttribute( - const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { - if (!isa(D)) - return; - if (CGM.getCodeGenOpts().StackProbeSize == 4096) - return; - - llvm::Function *F = cast(GV); - F->addFnAttr("stack-probe-size", - llvm::utostr(CGM.getCodeGenOpts().StackProbeSize)); -} void WindowsARMTargetCodeGenInfo::setTargetAttributes( const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { ARMTargetCodeGenInfo::setTargetAttributes(D, GV, CGM); addStackProbeSizeTargetAttribute(D, GV, CGM); } } void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), FI.isVariadic()); for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type, FI.isVariadic()); // Always honor user-specified calling convention. if (FI.getCallingConvention() != llvm::CallingConv::C) return; llvm::CallingConv::ID cc = getRuntimeCC(); if (cc != llvm::CallingConv::C) FI.setEffectiveCallingConvention(cc); } /// Return the default calling convention that LLVM will use. llvm::CallingConv::ID ARMABIInfo::getLLVMDefaultCC() const { // The default calling convention that LLVM will infer. if (isEABIHF() || getTarget().getTriple().isWatchOS()) return llvm::CallingConv::ARM_AAPCS_VFP; else if (isEABI()) return llvm::CallingConv::ARM_AAPCS; else return llvm::CallingConv::ARM_APCS; } /// Return the calling convention that our ABI would like us to use /// as the C calling convention. llvm::CallingConv::ID ARMABIInfo::getABIDefaultCC() const { switch (getABIKind()) { case APCS: return llvm::CallingConv::ARM_APCS; case AAPCS: return llvm::CallingConv::ARM_AAPCS; case AAPCS_VFP: return llvm::CallingConv::ARM_AAPCS_VFP; case AAPCS16_VFP: return llvm::CallingConv::ARM_AAPCS_VFP; } llvm_unreachable("bad ABI kind"); } void ARMABIInfo::setCCs() { assert(getRuntimeCC() == llvm::CallingConv::C); // Don't muddy up the IR with a ton of explicit annotations if // they'd just match what LLVM will infer from the triple. llvm::CallingConv::ID abiCC = getABIDefaultCC(); if (abiCC != getLLVMDefaultCC()) RuntimeCC = abiCC; // AAPCS apparently requires runtime support functions to be soft-float, but // that's almost certainly for historic reasons (Thumb1 not supporting VFP // most likely). It's more convenient for AAPCS16_VFP to be hard-float. switch (getABIKind()) { case APCS: case AAPCS16_VFP: if (abiCC != getLLVMDefaultCC()) BuiltinCC = abiCC; break; case AAPCS: case AAPCS_VFP: BuiltinCC = llvm::CallingConv::ARM_AAPCS; break; } } ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic) const { // 6.1.2.1 The following argument types are VFP CPRCs: // A single-precision floating-point type (including promoted // half-precision types); A double-precision floating-point type; // A 64-bit or 128-bit containerized vector type; Homogeneous Aggregate // with a Base Type of a single- or double-precision floating-point type, // 64-bit containerized vectors or 128-bit containerized vectors with one // to four Elements. bool IsEffectivelyAAPCS_VFP = getABIKind() == AAPCS_VFP && !isVariadic; Ty = useFirstFieldIfTransparentUnion(Ty); // Handle illegal vector types here. if (isIllegalVectorType(Ty)) { uint64_t Size = getContext().getTypeSize(Ty); if (Size <= 32) { llvm::Type *ResType = llvm::Type::getInt32Ty(getVMContext()); return ABIArgInfo::getDirect(ResType); } if (Size == 64) { llvm::Type *ResType = llvm::VectorType::get( llvm::Type::getInt32Ty(getVMContext()), 2); return ABIArgInfo::getDirect(ResType); } if (Size == 128) { llvm::Type *ResType = llvm::VectorType::get( llvm::Type::getInt32Ty(getVMContext()), 4); return ABIArgInfo::getDirect(ResType); } return getNaturalAlignIndirect(Ty, /*ByVal=*/false); } // __fp16 gets passed as if it were an int or float, but with the top 16 bits // unspecified. This is not done for OpenCL as it handles the half type // natively, and does not need to interwork with AAPCS code. if (Ty->isHalfType() && !getContext().getLangOpts().OpenCL) { llvm::Type *ResType = IsEffectivelyAAPCS_VFP ? llvm::Type::getFloatTy(getVMContext()) : llvm::Type::getInt32Ty(getVMContext()); return ABIArgInfo::getDirect(ResType); } if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) { Ty = EnumTy->getDecl()->getIntegerType(); } return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); } // Ignore empty records. if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); if (IsEffectivelyAAPCS_VFP) { // Homogeneous Aggregates need to be expanded when we can fit the aggregate // into VFP registers. const Type *Base = nullptr; uint64_t Members = 0; if (isHomogeneousAggregate(Ty, Base, Members)) { assert(Base && "Base class should be set for homogeneous aggregate"); // Base can be a floating-point or a vector. return ABIArgInfo::getDirect(nullptr, 0, nullptr, false); } } else if (getABIKind() == ARMABIInfo::AAPCS16_VFP) { // WatchOS does have homogeneous aggregates. Note that we intentionally use // this convention even for a variadic function: the backend will use GPRs // if needed. const Type *Base = nullptr; uint64_t Members = 0; if (isHomogeneousAggregate(Ty, Base, Members)) { assert(Base && Members <= 4 && "unexpected homogeneous aggregate"); llvm::Type *Ty = llvm::ArrayType::get(CGT.ConvertType(QualType(Base, 0)), Members); return ABIArgInfo::getDirect(Ty, 0, nullptr, false); } } if (getABIKind() == ARMABIInfo::AAPCS16_VFP && getContext().getTypeSizeInChars(Ty) > CharUnits::fromQuantity(16)) { // WatchOS is adopting the 64-bit AAPCS rule on composite types: if they're // bigger than 128-bits, they get placed in space allocated by the caller, // and a pointer is passed. return ABIArgInfo::getIndirect( CharUnits::fromQuantity(getContext().getTypeAlign(Ty) / 8), false); } // Support byval for ARM. // The ABI alignment for APCS is 4-byte and for AAPCS at least 4-byte and at // most 8-byte. We realign the indirect argument if type alignment is bigger // than ABI alignment. uint64_t ABIAlign = 4; uint64_t TyAlign = getContext().getTypeAlign(Ty) / 8; if (getABIKind() == ARMABIInfo::AAPCS_VFP || getABIKind() == ARMABIInfo::AAPCS) ABIAlign = std::min(std::max(TyAlign, (uint64_t)4), (uint64_t)8); if (getContext().getTypeSizeInChars(Ty) > CharUnits::fromQuantity(64)) { assert(getABIKind() != ARMABIInfo::AAPCS16_VFP && "unexpected byval"); return ABIArgInfo::getIndirect(CharUnits::fromQuantity(ABIAlign), /*ByVal=*/true, /*Realign=*/TyAlign > ABIAlign); } // Otherwise, pass by coercing to a structure of the appropriate size. llvm::Type* ElemTy; unsigned SizeRegs; // FIXME: Try to match the types of the arguments more accurately where // we can. if (getContext().getTypeAlign(Ty) <= 32) { ElemTy = llvm::Type::getInt32Ty(getVMContext()); SizeRegs = (getContext().getTypeSize(Ty) + 31) / 32; } else { ElemTy = llvm::Type::getInt64Ty(getVMContext()); SizeRegs = (getContext().getTypeSize(Ty) + 63) / 64; } return ABIArgInfo::getDirect(llvm::ArrayType::get(ElemTy, SizeRegs)); } static bool isIntegerLikeType(QualType Ty, ASTContext &Context, llvm::LLVMContext &VMContext) { // APCS, C Language Calling Conventions, Non-Simple Return Values: A structure // is called integer-like if its size is less than or equal to one word, and // the offset of each of its addressable sub-fields is zero. uint64_t Size = Context.getTypeSize(Ty); // Check that the type fits in a word. if (Size > 32) return false; // FIXME: Handle vector types! if (Ty->isVectorType()) return false; // Float types are never treated as "integer like". if (Ty->isRealFloatingType()) return false; // If this is a builtin or pointer type then it is ok. if (Ty->getAs() || Ty->isPointerType()) return true; // Small complex integer types are "integer like". if (const ComplexType *CT = Ty->getAs()) return isIntegerLikeType(CT->getElementType(), Context, VMContext); // Single element and zero sized arrays should be allowed, by the definition // above, but they are not. // Otherwise, it must be a record type. const RecordType *RT = Ty->getAs(); if (!RT) return false; // Ignore records with flexible arrays. const RecordDecl *RD = RT->getDecl(); if (RD->hasFlexibleArrayMember()) return false; // Check that all sub-fields are at offset 0, and are themselves "integer // like". const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); bool HadField = false; unsigned idx = 0; for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i, ++idx) { const FieldDecl *FD = *i; // Bit-fields are not addressable, we only need to verify they are "integer // like". We still have to disallow a subsequent non-bitfield, for example: // struct { int : 0; int x } // is non-integer like according to gcc. if (FD->isBitField()) { if (!RD->isUnion()) HadField = true; if (!isIntegerLikeType(FD->getType(), Context, VMContext)) return false; continue; } // Check if this field is at offset 0. if (Layout.getFieldOffset(idx) != 0) return false; if (!isIntegerLikeType(FD->getType(), Context, VMContext)) return false; // Only allow at most one field in a structure. This doesn't match the // wording above, but follows gcc in situations with a field following an // empty structure. if (!RD->isUnion()) { if (HadField) return false; HadField = true; } } return true; } ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, bool isVariadic) const { bool IsEffectivelyAAPCS_VFP = (getABIKind() == AAPCS_VFP || getABIKind() == AAPCS16_VFP) && !isVariadic; if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); // Large vector types should be returned via memory. if (RetTy->isVectorType() && getContext().getTypeSize(RetTy) > 128) { return getNaturalAlignIndirect(RetTy); } // __fp16 gets returned as if it were an int or float, but with the top 16 // bits unspecified. This is not done for OpenCL as it handles the half type // natively, and does not need to interwork with AAPCS code. if (RetTy->isHalfType() && !getContext().getLangOpts().OpenCL) { llvm::Type *ResType = IsEffectivelyAAPCS_VFP ? llvm::Type::getFloatTy(getVMContext()) : llvm::Type::getInt32Ty(getVMContext()); return ABIArgInfo::getDirect(ResType); } if (!isAggregateTypeForABI(RetTy)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); return RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect(); } // Are we following APCS? if (getABIKind() == APCS) { if (isEmptyRecord(getContext(), RetTy, false)) return ABIArgInfo::getIgnore(); // Complex types are all returned as packed integers. // // FIXME: Consider using 2 x vector types if the back end handles them // correctly. if (RetTy->isAnyComplexType()) return ABIArgInfo::getDirect(llvm::IntegerType::get( getVMContext(), getContext().getTypeSize(RetTy))); // Integer like structures are returned in r0. if (isIntegerLikeType(RetTy, getContext(), getVMContext())) { // Return in the smallest viable integer type. uint64_t Size = getContext().getTypeSize(RetTy); if (Size <= 8) return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext())); if (Size <= 16) return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext())); return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); } // Otherwise return in memory. return getNaturalAlignIndirect(RetTy); } // Otherwise this is an AAPCS variant. if (isEmptyRecord(getContext(), RetTy, true)) return ABIArgInfo::getIgnore(); // Check for homogeneous aggregates with AAPCS-VFP. if (IsEffectivelyAAPCS_VFP) { const Type *Base = nullptr; uint64_t Members = 0; if (isHomogeneousAggregate(RetTy, Base, Members)) { assert(Base && "Base class should be set for homogeneous aggregate"); // Homogeneous Aggregates are returned directly. return ABIArgInfo::getDirect(nullptr, 0, nullptr, false); } } // Aggregates <= 4 bytes are returned in r0; other aggregates // are returned indirectly. uint64_t Size = getContext().getTypeSize(RetTy); if (Size <= 32) { if (getDataLayout().isBigEndian()) // Return in 32 bit integer integer type (as if loaded by LDR, AAPCS 5.4) return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); // Return in the smallest viable integer type. if (Size <= 8) return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext())); if (Size <= 16) return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext())); return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); } else if (Size <= 128 && getABIKind() == AAPCS16_VFP) { llvm::Type *Int32Ty = llvm::Type::getInt32Ty(getVMContext()); llvm::Type *CoerceTy = llvm::ArrayType::get(Int32Ty, llvm::RoundUpToAlignment(Size, 32) / 32); return ABIArgInfo::getDirect(CoerceTy); } return getNaturalAlignIndirect(RetTy); } /// isIllegalVector - check whether Ty is an illegal vector type. bool ARMABIInfo::isIllegalVectorType(QualType Ty) const { if (const VectorType *VT = Ty->getAs ()) { if (isAndroid()) { // Android shipped using Clang 3.1, which supported a slightly different // vector ABI. The primary differences were that 3-element vector types // were legal, and so were sub 32-bit vectors (i.e. <2 x i8>). This path // accepts that legacy behavior for Android only. // Check whether VT is legal. unsigned NumElements = VT->getNumElements(); // NumElements should be power of 2 or equal to 3. if (!llvm::isPowerOf2_32(NumElements) && NumElements != 3) return true; } else { // Check whether VT is legal. unsigned NumElements = VT->getNumElements(); uint64_t Size = getContext().getTypeSize(VT); // NumElements should be power of 2. if (!llvm::isPowerOf2_32(NumElements)) return true; // Size should be greater than 32 bits. return Size <= 32; } } return false; } bool ARMABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const { // Homogeneous aggregates for AAPCS-VFP must have base types of float, // double, or 64-bit or 128-bit vectors. if (const BuiltinType *BT = Ty->getAs()) { if (BT->getKind() == BuiltinType::Float || BT->getKind() == BuiltinType::Double || BT->getKind() == BuiltinType::LongDouble) return true; } else if (const VectorType *VT = Ty->getAs()) { unsigned VecSize = getContext().getTypeSize(VT); if (VecSize == 64 || VecSize == 128) return true; } return false; } bool ARMABIInfo::isHomogeneousAggregateSmallEnough(const Type *Base, uint64_t Members) const { return Members <= 4; } Address ARMABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { CharUnits SlotSize = CharUnits::fromQuantity(4); // Empty records are ignored for parameter passing purposes. if (isEmptyRecord(getContext(), Ty, true)) { Address Addr(CGF.Builder.CreateLoad(VAListAddr), SlotSize); Addr = CGF.Builder.CreateElementBitCast(Addr, CGF.ConvertTypeForMem(Ty)); return Addr; } auto TyInfo = getContext().getTypeInfoInChars(Ty); CharUnits TyAlignForABI = TyInfo.second; // Use indirect if size of the illegal vector is bigger than 16 bytes. bool IsIndirect = false; const Type *Base = nullptr; uint64_t Members = 0; if (TyInfo.first > CharUnits::fromQuantity(16) && isIllegalVectorType(Ty)) { IsIndirect = true; // ARMv7k passes structs bigger than 16 bytes indirectly, in space // allocated by the caller. } else if (TyInfo.first > CharUnits::fromQuantity(16) && getABIKind() == ARMABIInfo::AAPCS16_VFP && !isHomogeneousAggregate(Ty, Base, Members)) { IsIndirect = true; // Otherwise, bound the type's ABI alignment. // The ABI alignment for 64-bit or 128-bit vectors is 8 for AAPCS and 4 for // APCS. For AAPCS, the ABI alignment is at least 4-byte and at most 8-byte. // Our callers should be prepared to handle an under-aligned address. } else if (getABIKind() == ARMABIInfo::AAPCS_VFP || getABIKind() == ARMABIInfo::AAPCS) { TyAlignForABI = std::max(TyAlignForABI, CharUnits::fromQuantity(4)); TyAlignForABI = std::min(TyAlignForABI, CharUnits::fromQuantity(8)); } else if (getABIKind() == ARMABIInfo::AAPCS16_VFP) { // ARMv7k allows type alignment up to 16 bytes. TyAlignForABI = std::max(TyAlignForABI, CharUnits::fromQuantity(4)); TyAlignForABI = std::min(TyAlignForABI, CharUnits::fromQuantity(16)); } else { TyAlignForABI = CharUnits::fromQuantity(4); } TyInfo.second = TyAlignForABI; return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, TyInfo, SlotSize, /*AllowHigherAlign*/ true); } //===----------------------------------------------------------------------===// // NVPTX ABI Implementation //===----------------------------------------------------------------------===// namespace { class NVPTXABIInfo : public ABIInfo { public: NVPTXABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {} ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType Ty) const; void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; }; class NVPTXTargetCodeGenInfo : public TargetCodeGenInfo { public: NVPTXTargetCodeGenInfo(CodeGenTypes &CGT) : TargetCodeGenInfo(new NVPTXABIInfo(CGT)) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const override; private: // Adds a NamedMDNode with F, Name, and Operand as operands, and adds the // resulting MDNode to the nvvm.annotations MDNode. static void addNVVMMetadata(llvm::Function *F, StringRef Name, int Operand); }; ABIArgInfo NVPTXABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); // note: this is different from default ABI if (!RetTy->isScalarType()) return ABIArgInfo::getDirect(); // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } ABIArgInfo NVPTXABIInfo::classifyArgumentType(QualType Ty) const { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); // Return aggregates type as indirect by value if (isAggregateTypeForABI(Ty)) return getNaturalAlignIndirect(Ty, /* byval */ true); return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } void NVPTXABIInfo::computeInfo(CGFunctionInfo &FI) const { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type); // Always honor user-specified calling convention. if (FI.getCallingConvention() != llvm::CallingConv::C) return; FI.setEffectiveCallingConvention(getRuntimeCC()); } Address NVPTXABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { llvm_unreachable("NVPTX does not support varargs"); } void NVPTXTargetCodeGenInfo:: setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const{ const FunctionDecl *FD = dyn_cast_or_null(D); if (!FD) return; llvm::Function *F = cast(GV); // Perform special handling in OpenCL mode if (M.getLangOpts().OpenCL) { // Use OpenCL function attributes to check for kernel functions // By default, all functions are device functions if (FD->hasAttr()) { // OpenCL __kernel functions get kernel metadata // Create !{, metadata !"kernel", i32 1} node addNVVMMetadata(F, "kernel", 1); // And kernel functions are not subject to inlining F->addFnAttr(llvm::Attribute::NoInline); } } // Perform special handling in CUDA mode. if (M.getLangOpts().CUDA) { // CUDA __global__ functions get a kernel metadata entry. Since // __global__ functions cannot be called from the device, we do not // need to set the noinline attribute. if (FD->hasAttr()) { // Create !{, metadata !"kernel", i32 1} node addNVVMMetadata(F, "kernel", 1); } if (CUDALaunchBoundsAttr *Attr = FD->getAttr()) { // Create !{, metadata !"maxntidx", i32 } node llvm::APSInt MaxThreads(32); MaxThreads = Attr->getMaxThreads()->EvaluateKnownConstInt(M.getContext()); if (MaxThreads > 0) addNVVMMetadata(F, "maxntidx", MaxThreads.getExtValue()); // min blocks is an optional argument for CUDALaunchBoundsAttr. If it was // not specified in __launch_bounds__ or if the user specified a 0 value, // we don't have to add a PTX directive. if (Attr->getMinBlocks()) { llvm::APSInt MinBlocks(32); MinBlocks = Attr->getMinBlocks()->EvaluateKnownConstInt(M.getContext()); if (MinBlocks > 0) // Create !{, metadata !"minctasm", i32 } node addNVVMMetadata(F, "minctasm", MinBlocks.getExtValue()); } } } } void NVPTXTargetCodeGenInfo::addNVVMMetadata(llvm::Function *F, StringRef Name, int Operand) { llvm::Module *M = F->getParent(); llvm::LLVMContext &Ctx = M->getContext(); // Get "nvvm.annotations" metadata node llvm::NamedMDNode *MD = M->getOrInsertNamedMetadata("nvvm.annotations"); llvm::Metadata *MDVals[] = { llvm::ConstantAsMetadata::get(F), llvm::MDString::get(Ctx, Name), llvm::ConstantAsMetadata::get( llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), Operand))}; // Append metadata to nvvm.annotations MD->addOperand(llvm::MDNode::get(Ctx, MDVals)); } } //===----------------------------------------------------------------------===// // SystemZ ABI Implementation //===----------------------------------------------------------------------===// namespace { class SystemZABIInfo : public ABIInfo { bool HasVector; public: SystemZABIInfo(CodeGenTypes &CGT, bool HV) : ABIInfo(CGT), HasVector(HV) {} bool isPromotableIntegerType(QualType Ty) const; bool isCompoundType(QualType Ty) const; bool isVectorArgumentType(QualType Ty) const; bool isFPArgumentType(QualType Ty) const; QualType GetSingleElementType(QualType Ty) const; ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType ArgTy) const; void computeInfo(CGFunctionInfo &FI) const override { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type); } Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; }; class SystemZTargetCodeGenInfo : public TargetCodeGenInfo { public: SystemZTargetCodeGenInfo(CodeGenTypes &CGT, bool HasVector) : TargetCodeGenInfo(new SystemZABIInfo(CGT, HasVector)) {} }; } bool SystemZABIInfo::isPromotableIntegerType(QualType Ty) const { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); // Promotable integer types are required to be promoted by the ABI. if (Ty->isPromotableIntegerType()) return true; // 32-bit values must also be promoted. if (const BuiltinType *BT = Ty->getAs()) switch (BT->getKind()) { case BuiltinType::Int: case BuiltinType::UInt: return true; default: return false; } return false; } bool SystemZABIInfo::isCompoundType(QualType Ty) const { return (Ty->isAnyComplexType() || Ty->isVectorType() || isAggregateTypeForABI(Ty)); } bool SystemZABIInfo::isVectorArgumentType(QualType Ty) const { return (HasVector && Ty->isVectorType() && getContext().getTypeSize(Ty) <= 128); } bool SystemZABIInfo::isFPArgumentType(QualType Ty) const { if (const BuiltinType *BT = Ty->getAs()) switch (BT->getKind()) { case BuiltinType::Float: case BuiltinType::Double: return true; default: return false; } return false; } QualType SystemZABIInfo::GetSingleElementType(QualType Ty) const { if (const RecordType *RT = Ty->getAsStructureType()) { const RecordDecl *RD = RT->getDecl(); QualType Found; // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) for (const auto &I : CXXRD->bases()) { QualType Base = I.getType(); // Empty bases don't affect things either way. if (isEmptyRecord(getContext(), Base, true)) continue; if (!Found.isNull()) return Ty; Found = GetSingleElementType(Base); } // Check the fields. for (const auto *FD : RD->fields()) { // For compatibility with GCC, ignore empty bitfields in C++ mode. // Unlike isSingleElementStruct(), empty structure and array fields // do count. So do anonymous bitfields that aren't zero-sized. if (getContext().getLangOpts().CPlusPlus && FD->isBitField() && FD->getBitWidthValue(getContext()) == 0) continue; // Unlike isSingleElementStruct(), arrays do not count. // Nested structures still do though. if (!Found.isNull()) return Ty; Found = GetSingleElementType(FD->getType()); } // Unlike isSingleElementStruct(), trailing padding is allowed. // An 8-byte aligned struct s { float f; } is passed as a double. if (!Found.isNull()) return Found; } return Ty; } Address SystemZABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { // Assume that va_list type is correct; should be pointer to LLVM type: // struct { // i64 __gpr; // i64 __fpr; // i8 *__overflow_arg_area; // i8 *__reg_save_area; // }; // Every non-vector argument occupies 8 bytes and is passed by preference // in either GPRs or FPRs. Vector arguments occupy 8 or 16 bytes and are // always passed on the stack. Ty = getContext().getCanonicalType(Ty); auto TyInfo = getContext().getTypeInfoInChars(Ty); llvm::Type *ArgTy = CGF.ConvertTypeForMem(Ty); llvm::Type *DirectTy = ArgTy; ABIArgInfo AI = classifyArgumentType(Ty); bool IsIndirect = AI.isIndirect(); bool InFPRs = false; bool IsVector = false; CharUnits UnpaddedSize; CharUnits DirectAlign; if (IsIndirect) { DirectTy = llvm::PointerType::getUnqual(DirectTy); UnpaddedSize = DirectAlign = CharUnits::fromQuantity(8); } else { if (AI.getCoerceToType()) ArgTy = AI.getCoerceToType(); InFPRs = ArgTy->isFloatTy() || ArgTy->isDoubleTy(); IsVector = ArgTy->isVectorTy(); UnpaddedSize = TyInfo.first; DirectAlign = TyInfo.second; } CharUnits PaddedSize = CharUnits::fromQuantity(8); if (IsVector && UnpaddedSize > PaddedSize) PaddedSize = CharUnits::fromQuantity(16); assert((UnpaddedSize <= PaddedSize) && "Invalid argument size."); CharUnits Padding = (PaddedSize - UnpaddedSize); llvm::Type *IndexTy = CGF.Int64Ty; llvm::Value *PaddedSizeV = llvm::ConstantInt::get(IndexTy, PaddedSize.getQuantity()); if (IsVector) { // Work out the address of a vector argument on the stack. // Vector arguments are always passed in the high bits of a // single (8 byte) or double (16 byte) stack slot. Address OverflowArgAreaPtr = CGF.Builder.CreateStructGEP(VAListAddr, 2, CharUnits::fromQuantity(16), "overflow_arg_area_ptr"); Address OverflowArgArea = Address(CGF.Builder.CreateLoad(OverflowArgAreaPtr, "overflow_arg_area"), TyInfo.second); Address MemAddr = CGF.Builder.CreateElementBitCast(OverflowArgArea, DirectTy, "mem_addr"); // Update overflow_arg_area_ptr pointer llvm::Value *NewOverflowArgArea = CGF.Builder.CreateGEP(OverflowArgArea.getPointer(), PaddedSizeV, "overflow_arg_area"); CGF.Builder.CreateStore(NewOverflowArgArea, OverflowArgAreaPtr); return MemAddr; } assert(PaddedSize.getQuantity() == 8); unsigned MaxRegs, RegCountField, RegSaveIndex; CharUnits RegPadding; if (InFPRs) { MaxRegs = 4; // Maximum of 4 FPR arguments RegCountField = 1; // __fpr RegSaveIndex = 16; // save offset for f0 RegPadding = CharUnits(); // floats are passed in the high bits of an FPR } else { MaxRegs = 5; // Maximum of 5 GPR arguments RegCountField = 0; // __gpr RegSaveIndex = 2; // save offset for r2 RegPadding = Padding; // values are passed in the low bits of a GPR } Address RegCountPtr = CGF.Builder.CreateStructGEP( VAListAddr, RegCountField, RegCountField * CharUnits::fromQuantity(8), "reg_count_ptr"); llvm::Value *RegCount = CGF.Builder.CreateLoad(RegCountPtr, "reg_count"); llvm::Value *MaxRegsV = llvm::ConstantInt::get(IndexTy, MaxRegs); llvm::Value *InRegs = CGF.Builder.CreateICmpULT(RegCount, MaxRegsV, "fits_in_regs"); llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg"); llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem"); llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end"); CGF.Builder.CreateCondBr(InRegs, InRegBlock, InMemBlock); // Emit code to load the value if it was passed in registers. CGF.EmitBlock(InRegBlock); // Work out the address of an argument register. llvm::Value *ScaledRegCount = CGF.Builder.CreateMul(RegCount, PaddedSizeV, "scaled_reg_count"); llvm::Value *RegBase = llvm::ConstantInt::get(IndexTy, RegSaveIndex * PaddedSize.getQuantity() + RegPadding.getQuantity()); llvm::Value *RegOffset = CGF.Builder.CreateAdd(ScaledRegCount, RegBase, "reg_offset"); Address RegSaveAreaPtr = CGF.Builder.CreateStructGEP(VAListAddr, 3, CharUnits::fromQuantity(24), "reg_save_area_ptr"); llvm::Value *RegSaveArea = CGF.Builder.CreateLoad(RegSaveAreaPtr, "reg_save_area"); Address RawRegAddr(CGF.Builder.CreateGEP(RegSaveArea, RegOffset, "raw_reg_addr"), PaddedSize); Address RegAddr = CGF.Builder.CreateElementBitCast(RawRegAddr, DirectTy, "reg_addr"); // Update the register count llvm::Value *One = llvm::ConstantInt::get(IndexTy, 1); llvm::Value *NewRegCount = CGF.Builder.CreateAdd(RegCount, One, "reg_count"); CGF.Builder.CreateStore(NewRegCount, RegCountPtr); CGF.EmitBranch(ContBlock); // Emit code to load the value if it was passed in memory. CGF.EmitBlock(InMemBlock); // Work out the address of a stack argument. Address OverflowArgAreaPtr = CGF.Builder.CreateStructGEP( VAListAddr, 2, CharUnits::fromQuantity(16), "overflow_arg_area_ptr"); Address OverflowArgArea = Address(CGF.Builder.CreateLoad(OverflowArgAreaPtr, "overflow_arg_area"), PaddedSize); Address RawMemAddr = CGF.Builder.CreateConstByteGEP(OverflowArgArea, Padding, "raw_mem_addr"); Address MemAddr = CGF.Builder.CreateElementBitCast(RawMemAddr, DirectTy, "mem_addr"); // Update overflow_arg_area_ptr pointer llvm::Value *NewOverflowArgArea = CGF.Builder.CreateGEP(OverflowArgArea.getPointer(), PaddedSizeV, "overflow_arg_area"); CGF.Builder.CreateStore(NewOverflowArgArea, OverflowArgAreaPtr); CGF.EmitBranch(ContBlock); // Return the appropriate result. CGF.EmitBlock(ContBlock); Address ResAddr = emitMergePHI(CGF, RegAddr, InRegBlock, MemAddr, InMemBlock, "va_arg.addr"); if (IsIndirect) ResAddr = Address(CGF.Builder.CreateLoad(ResAddr, "indirect_arg"), TyInfo.second); return ResAddr; } ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); if (isVectorArgumentType(RetTy)) return ABIArgInfo::getDirect(); if (isCompoundType(RetTy) || getContext().getTypeSize(RetTy) > 64) return getNaturalAlignIndirect(RetTy); return (isPromotableIntegerType(RetTy) ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const { // Handle the generic C++ ABI. if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); // Integers and enums are extended to full register width. if (isPromotableIntegerType(Ty)) return ABIArgInfo::getExtend(); // Handle vector types and vector-like structure types. Note that // as opposed to float-like structure types, we do not allow any // padding for vector-like structures, so verify the sizes match. uint64_t Size = getContext().getTypeSize(Ty); QualType SingleElementTy = GetSingleElementType(Ty); if (isVectorArgumentType(SingleElementTy) && getContext().getTypeSize(SingleElementTy) == Size) return ABIArgInfo::getDirect(CGT.ConvertType(SingleElementTy)); // Values that are not 1, 2, 4 or 8 bytes in size are passed indirectly. if (Size != 8 && Size != 16 && Size != 32 && Size != 64) return getNaturalAlignIndirect(Ty, /*ByVal=*/false); // Handle small structures. if (const RecordType *RT = Ty->getAs()) { // Structures with flexible arrays have variable length, so really // fail the size test above. const RecordDecl *RD = RT->getDecl(); if (RD->hasFlexibleArrayMember()) return getNaturalAlignIndirect(Ty, /*ByVal=*/false); // The structure is passed as an unextended integer, a float, or a double. llvm::Type *PassTy; if (isFPArgumentType(SingleElementTy)) { assert(Size == 32 || Size == 64); if (Size == 32) PassTy = llvm::Type::getFloatTy(getVMContext()); else PassTy = llvm::Type::getDoubleTy(getVMContext()); } else PassTy = llvm::IntegerType::get(getVMContext(), Size); return ABIArgInfo::getDirect(PassTy); } // Non-structure compounds are passed indirectly. if (isCompoundType(Ty)) return getNaturalAlignIndirect(Ty, /*ByVal=*/false); return ABIArgInfo::getDirect(nullptr); } //===----------------------------------------------------------------------===// // MSP430 ABI Implementation //===----------------------------------------------------------------------===// namespace { class MSP430TargetCodeGenInfo : public TargetCodeGenInfo { public: MSP430TargetCodeGenInfo(CodeGenTypes &CGT) : TargetCodeGenInfo(new DefaultABIInfo(CGT)) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const override; }; } void MSP430TargetCodeGenInfo::setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const { if (const FunctionDecl *FD = dyn_cast_or_null(D)) { if (const MSP430InterruptAttr *attr = FD->getAttr()) { // Handle 'interrupt' attribute: llvm::Function *F = cast(GV); // Step 1: Set ISR calling convention. F->setCallingConv(llvm::CallingConv::MSP430_INTR); // Step 2: Add attributes goodness. F->addFnAttr(llvm::Attribute::NoInline); // Step 3: Emit ISR vector alias. unsigned Num = attr->getNumber() / 2; llvm::GlobalAlias::create(llvm::Function::ExternalLinkage, "__isr_" + Twine(Num), F); } } } //===----------------------------------------------------------------------===// // MIPS ABI Implementation. This works for both little-endian and // big-endian variants. //===----------------------------------------------------------------------===// namespace { class MipsABIInfo : public ABIInfo { bool IsO32; unsigned MinABIStackAlignInBytes, StackAlignInBytes; void CoerceToIntArgs(uint64_t TySize, SmallVectorImpl &ArgList) const; llvm::Type* HandleAggregates(QualType Ty, uint64_t TySize) const; llvm::Type* returnAggregateInRegs(QualType RetTy, uint64_t Size) const; llvm::Type* getPaddingType(uint64_t Align, uint64_t Offset) const; public: MipsABIInfo(CodeGenTypes &CGT, bool _IsO32) : ABIInfo(CGT), IsO32(_IsO32), MinABIStackAlignInBytes(IsO32 ? 4 : 8), StackAlignInBytes(IsO32 ? 8 : 16) {} ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType RetTy, uint64_t &Offset) const; void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; bool shouldSignExtUnsignedType(QualType Ty) const override; }; class MIPSTargetCodeGenInfo : public TargetCodeGenInfo { unsigned SizeOfUnwindException; public: MIPSTargetCodeGenInfo(CodeGenTypes &CGT, bool IsO32) : TargetCodeGenInfo(new MipsABIInfo(CGT, IsO32)), SizeOfUnwindException(IsO32 ? 24 : 32) {} int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override { return 29; } void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override { const FunctionDecl *FD = dyn_cast_or_null(D); if (!FD) return; llvm::Function *Fn = cast(GV); if (FD->hasAttr()) { Fn->addFnAttr("mips16"); } else if (FD->hasAttr()) { Fn->addFnAttr("nomips16"); } const MipsInterruptAttr *Attr = FD->getAttr(); if (!Attr) return; const char *Kind; switch (Attr->getInterrupt()) { case MipsInterruptAttr::eic: Kind = "eic"; break; case MipsInterruptAttr::sw0: Kind = "sw0"; break; case MipsInterruptAttr::sw1: Kind = "sw1"; break; case MipsInterruptAttr::hw0: Kind = "hw0"; break; case MipsInterruptAttr::hw1: Kind = "hw1"; break; case MipsInterruptAttr::hw2: Kind = "hw2"; break; case MipsInterruptAttr::hw3: Kind = "hw3"; break; case MipsInterruptAttr::hw4: Kind = "hw4"; break; case MipsInterruptAttr::hw5: Kind = "hw5"; break; } Fn->addFnAttr("interrupt", Kind); } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; unsigned getSizeOfUnwindException() const override { return SizeOfUnwindException; } }; } void MipsABIInfo::CoerceToIntArgs( uint64_t TySize, SmallVectorImpl &ArgList) const { llvm::IntegerType *IntTy = llvm::IntegerType::get(getVMContext(), MinABIStackAlignInBytes * 8); // Add (TySize / MinABIStackAlignInBytes) args of IntTy. for (unsigned N = TySize / (MinABIStackAlignInBytes * 8); N; --N) ArgList.push_back(IntTy); // If necessary, add one more integer type to ArgList. unsigned R = TySize % (MinABIStackAlignInBytes * 8); if (R) ArgList.push_back(llvm::IntegerType::get(getVMContext(), R)); } // In N32/64, an aligned double precision floating point field is passed in // a register. llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty, uint64_t TySize) const { SmallVector ArgList, IntArgList; if (IsO32) { CoerceToIntArgs(TySize, ArgList); return llvm::StructType::get(getVMContext(), ArgList); } if (Ty->isComplexType()) return CGT.ConvertType(Ty); const RecordType *RT = Ty->getAs(); // Unions/vectors are passed in integer registers. if (!RT || !RT->isStructureOrClassType()) { CoerceToIntArgs(TySize, ArgList); return llvm::StructType::get(getVMContext(), ArgList); } const RecordDecl *RD = RT->getDecl(); const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); assert(!(TySize % 8) && "Size of structure must be multiple of 8."); uint64_t LastOffset = 0; unsigned idx = 0; llvm::IntegerType *I64 = llvm::IntegerType::get(getVMContext(), 64); // Iterate over fields in the struct/class and check if there are any aligned // double fields. for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i, ++idx) { const QualType Ty = i->getType(); const BuiltinType *BT = Ty->getAs(); if (!BT || BT->getKind() != BuiltinType::Double) continue; uint64_t Offset = Layout.getFieldOffset(idx); if (Offset % 64) // Ignore doubles that are not aligned. continue; // Add ((Offset - LastOffset) / 64) args of type i64. for (unsigned j = (Offset - LastOffset) / 64; j > 0; --j) ArgList.push_back(I64); // Add double type. ArgList.push_back(llvm::Type::getDoubleTy(getVMContext())); LastOffset = Offset + 64; } CoerceToIntArgs(TySize - LastOffset, IntArgList); ArgList.append(IntArgList.begin(), IntArgList.end()); return llvm::StructType::get(getVMContext(), ArgList); } llvm::Type *MipsABIInfo::getPaddingType(uint64_t OrigOffset, uint64_t Offset) const { if (OrigOffset + MinABIStackAlignInBytes > Offset) return nullptr; return llvm::IntegerType::get(getVMContext(), (Offset - OrigOffset) * 8); } ABIArgInfo MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const { Ty = useFirstFieldIfTransparentUnion(Ty); uint64_t OrigOffset = Offset; uint64_t TySize = getContext().getTypeSize(Ty); uint64_t Align = getContext().getTypeAlign(Ty) / 8; Align = std::min(std::max(Align, (uint64_t)MinABIStackAlignInBytes), (uint64_t)StackAlignInBytes); unsigned CurrOffset = llvm::RoundUpToAlignment(Offset, Align); Offset = CurrOffset + llvm::RoundUpToAlignment(TySize, Align * 8) / 8; if (isAggregateTypeForABI(Ty) || Ty->isVectorType()) { // Ignore empty aggregates. if (TySize == 0) return ABIArgInfo::getIgnore(); if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { Offset = OrigOffset + MinABIStackAlignInBytes; return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); } // If we have reached here, aggregates are passed directly by coercing to // another structure type. Padding is inserted if the offset of the // aggregate is unaligned. ABIArgInfo ArgInfo = ABIArgInfo::getDirect(HandleAggregates(Ty, TySize), 0, getPaddingType(OrigOffset, CurrOffset)); ArgInfo.setInReg(true); return ArgInfo; } // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); // All integral types are promoted to the GPR width. if (Ty->isIntegralOrEnumerationType()) return ABIArgInfo::getExtend(); return ABIArgInfo::getDirect( nullptr, 0, IsO32 ? nullptr : getPaddingType(OrigOffset, CurrOffset)); } llvm::Type* MipsABIInfo::returnAggregateInRegs(QualType RetTy, uint64_t Size) const { const RecordType *RT = RetTy->getAs(); SmallVector RTList; if (RT && RT->isStructureOrClassType()) { const RecordDecl *RD = RT->getDecl(); const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); unsigned FieldCnt = Layout.getFieldCount(); // N32/64 returns struct/classes in floating point registers if the // following conditions are met: // 1. The size of the struct/class is no larger than 128-bit. // 2. The struct/class has one or two fields all of which are floating // point types. // 3. The offset of the first field is zero (this follows what gcc does). // // Any other composite results are returned in integer registers. // if (FieldCnt && (FieldCnt <= 2) && !Layout.getFieldOffset(0)) { RecordDecl::field_iterator b = RD->field_begin(), e = RD->field_end(); for (; b != e; ++b) { const BuiltinType *BT = b->getType()->getAs(); if (!BT || !BT->isFloatingPoint()) break; RTList.push_back(CGT.ConvertType(b->getType())); } if (b == e) return llvm::StructType::get(getVMContext(), RTList, RD->hasAttr()); RTList.clear(); } } CoerceToIntArgs(Size, RTList); return llvm::StructType::get(getVMContext(), RTList); } ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const { uint64_t Size = getContext().getTypeSize(RetTy); if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); // O32 doesn't treat zero-sized structs differently from other structs. // However, N32/N64 ignores zero sized return values. if (!IsO32 && Size == 0) return ABIArgInfo::getIgnore(); if (isAggregateTypeForABI(RetTy) || RetTy->isVectorType()) { if (Size <= 128) { if (RetTy->isAnyComplexType()) return ABIArgInfo::getDirect(); // O32 returns integer vectors in registers and N32/N64 returns all small // aggregates in registers. if (!IsO32 || (RetTy->isVectorType() && !RetTy->hasFloatingRepresentation())) { ABIArgInfo ArgInfo = ABIArgInfo::getDirect(returnAggregateInRegs(RetTy, Size)); ArgInfo.setInReg(true); return ArgInfo; } } return getNaturalAlignIndirect(RetTy); } // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const { ABIArgInfo &RetInfo = FI.getReturnInfo(); if (!getCXXABI().classifyReturnType(FI)) RetInfo = classifyReturnType(FI.getReturnType()); // Check if a pointer to an aggregate is passed as a hidden argument. uint64_t Offset = RetInfo.isIndirect() ? MinABIStackAlignInBytes : 0; for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type, Offset); } Address MipsABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType OrigTy) const { QualType Ty = OrigTy; // Integer arguments are promoted to 32-bit on O32 and 64-bit on N32/N64. // Pointers are also promoted in the same way but this only matters for N32. unsigned SlotSizeInBits = IsO32 ? 32 : 64; unsigned PtrWidth = getTarget().getPointerWidth(0); bool DidPromote = false; if ((Ty->isIntegerType() && getContext().getIntWidth(Ty) < SlotSizeInBits) || (Ty->isPointerType() && PtrWidth < SlotSizeInBits)) { DidPromote = true; Ty = getContext().getIntTypeForBitwidth(SlotSizeInBits, Ty->isSignedIntegerType()); } auto TyInfo = getContext().getTypeInfoInChars(Ty); // The alignment of things in the argument area is never larger than // StackAlignInBytes. TyInfo.second = std::min(TyInfo.second, CharUnits::fromQuantity(StackAlignInBytes)); // MinABIStackAlignInBytes is the size of argument slots on the stack. CharUnits ArgSlotSize = CharUnits::fromQuantity(MinABIStackAlignInBytes); Address Addr = emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false, TyInfo, ArgSlotSize, /*AllowHigherAlign*/ true); // If there was a promotion, "unpromote" into a temporary. // TODO: can we just use a pointer into a subset of the original slot? if (DidPromote) { Address Temp = CGF.CreateMemTemp(OrigTy, "vaarg.promotion-temp"); llvm::Value *Promoted = CGF.Builder.CreateLoad(Addr); // Truncate down to the right width. llvm::Type *IntTy = (OrigTy->isIntegerType() ? Temp.getElementType() : CGF.IntPtrTy); llvm::Value *V = CGF.Builder.CreateTrunc(Promoted, IntTy); if (OrigTy->isPointerType()) V = CGF.Builder.CreateIntToPtr(V, Temp.getElementType()); CGF.Builder.CreateStore(V, Temp); Addr = Temp; } return Addr; } bool MipsABIInfo::shouldSignExtUnsignedType(QualType Ty) const { int TySize = getContext().getTypeSize(Ty); // MIPS64 ABI requires unsigned 32 bit integers to be sign extended. if (Ty->isUnsignedIntegerOrEnumerationType() && TySize == 32) return true; return false; } bool MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const { // This information comes from gcc's implementation, which seems to // as canonical as it gets. // Everything on MIPS is 4 bytes. Double-precision FP registers // are aliased to pairs of single-precision FP registers. llvm::Value *Four8 = llvm::ConstantInt::get(CGF.Int8Ty, 4); // 0-31 are the general purpose registers, $0 - $31. // 32-63 are the floating-point registers, $f0 - $f31. // 64 and 65 are the multiply/divide registers, $hi and $lo. // 66 is the (notional, I think) register for signal-handler return. AssignToArrayRange(CGF.Builder, Address, Four8, 0, 65); // 67-74 are the floating-point status registers, $fcc0 - $fcc7. // They are one bit wide and ignored here. // 80-111 are the coprocessor 0 registers, $c0r0 - $c0r31. // (coprocessor 1 is the FP unit) // 112-143 are the coprocessor 2 registers, $c2r0 - $c2r31. // 144-175 are the coprocessor 3 registers, $c3r0 - $c3r31. // 176-181 are the DSP accumulator registers. AssignToArrayRange(CGF.Builder, Address, Four8, 80, 181); return false; } //===----------------------------------------------------------------------===// // TCE ABI Implementation (see http://tce.cs.tut.fi). Uses mostly the defaults. // Currently subclassed only to implement custom OpenCL C function attribute // handling. //===----------------------------------------------------------------------===// namespace { class TCETargetCodeGenInfo : public DefaultTargetCodeGenInfo { public: TCETargetCodeGenInfo(CodeGenTypes &CGT) : DefaultTargetCodeGenInfo(CGT) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const override; }; void TCETargetCodeGenInfo::setTargetAttributes( const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const { const FunctionDecl *FD = dyn_cast_or_null(D); if (!FD) return; llvm::Function *F = cast(GV); if (M.getLangOpts().OpenCL) { if (FD->hasAttr()) { // OpenCL C Kernel functions are not subject to inlining F->addFnAttr(llvm::Attribute::NoInline); const ReqdWorkGroupSizeAttr *Attr = FD->getAttr(); if (Attr) { // Convert the reqd_work_group_size() attributes to metadata. llvm::LLVMContext &Context = F->getContext(); llvm::NamedMDNode *OpenCLMetadata = M.getModule().getOrInsertNamedMetadata( "opencl.kernel_wg_size_info"); SmallVector Operands; Operands.push_back(llvm::ConstantAsMetadata::get(F)); Operands.push_back( llvm::ConstantAsMetadata::get(llvm::Constant::getIntegerValue( M.Int32Ty, llvm::APInt(32, Attr->getXDim())))); Operands.push_back( llvm::ConstantAsMetadata::get(llvm::Constant::getIntegerValue( M.Int32Ty, llvm::APInt(32, Attr->getYDim())))); Operands.push_back( llvm::ConstantAsMetadata::get(llvm::Constant::getIntegerValue( M.Int32Ty, llvm::APInt(32, Attr->getZDim())))); // Add a boolean constant operand for "required" (true) or "hint" // (false) for implementing the work_group_size_hint attr later. // Currently always true as the hint is not yet implemented. Operands.push_back( llvm::ConstantAsMetadata::get(llvm::ConstantInt::getTrue(Context))); OpenCLMetadata->addOperand(llvm::MDNode::get(Context, Operands)); } } } } } //===----------------------------------------------------------------------===// // Hexagon ABI Implementation //===----------------------------------------------------------------------===// namespace { class HexagonABIInfo : public ABIInfo { public: HexagonABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {} private: ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType RetTy) const; void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; }; class HexagonTargetCodeGenInfo : public TargetCodeGenInfo { public: HexagonTargetCodeGenInfo(CodeGenTypes &CGT) :TargetCodeGenInfo(new HexagonABIInfo(CGT)) {} int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override { return 29; } }; } void HexagonABIInfo::computeInfo(CGFunctionInfo &FI) const { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type); } ABIArgInfo HexagonABIInfo::classifyArgumentType(QualType Ty) const { if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } // Ignore empty records. if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); uint64_t Size = getContext().getTypeSize(Ty); if (Size > 64) return getNaturalAlignIndirect(Ty, /*ByVal=*/true); // Pass in the smallest viable integer type. else if (Size > 32) return ABIArgInfo::getDirect(llvm::Type::getInt64Ty(getVMContext())); else if (Size > 16) return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); else if (Size > 8) return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext())); else return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext())); } ABIArgInfo HexagonABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); // Large vector types should be returned via memory. if (RetTy->isVectorType() && getContext().getTypeSize(RetTy) > 64) return getNaturalAlignIndirect(RetTy); if (!isAggregateTypeForABI(RetTy)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } if (isEmptyRecord(getContext(), RetTy, true)) return ABIArgInfo::getIgnore(); // Aggregates <= 8 bytes are returned in r0; other aggregates // are returned indirectly. uint64_t Size = getContext().getTypeSize(RetTy); if (Size <= 64) { // Return in the smallest viable integer type. if (Size <= 8) return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext())); if (Size <= 16) return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext())); if (Size <= 32) return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); return ABIArgInfo::getDirect(llvm::Type::getInt64Ty(getVMContext())); } return getNaturalAlignIndirect(RetTy, /*ByVal=*/true); } Address HexagonABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { // FIXME: Someone needs to audit that this handle alignment correctly. return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false, getContext().getTypeInfoInChars(Ty), CharUnits::fromQuantity(4), /*AllowHigherAlign*/ true); } //===----------------------------------------------------------------------===// // AMDGPU ABI Implementation //===----------------------------------------------------------------------===// namespace { class AMDGPUTargetCodeGenInfo : public TargetCodeGenInfo { public: AMDGPUTargetCodeGenInfo(CodeGenTypes &CGT) : TargetCodeGenInfo(new DefaultABIInfo(CGT)) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const override; }; } void AMDGPUTargetCodeGenInfo::setTargetAttributes( const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const { const FunctionDecl *FD = dyn_cast_or_null(D); if (!FD) return; if (const auto Attr = FD->getAttr()) { llvm::Function *F = cast(GV); uint32_t NumVGPR = Attr->getNumVGPR(); if (NumVGPR != 0) F->addFnAttr("amdgpu_num_vgpr", llvm::utostr(NumVGPR)); } if (const auto Attr = FD->getAttr()) { llvm::Function *F = cast(GV); unsigned NumSGPR = Attr->getNumSGPR(); if (NumSGPR != 0) F->addFnAttr("amdgpu_num_sgpr", llvm::utostr(NumSGPR)); } } //===----------------------------------------------------------------------===// // SPARC v9 ABI Implementation. // Based on the SPARC Compliance Definition version 2.4.1. // // Function arguments a mapped to a nominal "parameter array" and promoted to // registers depending on their type. Each argument occupies 8 or 16 bytes in // the array, structs larger than 16 bytes are passed indirectly. // // One case requires special care: // // struct mixed { // int i; // float f; // }; // // When a struct mixed is passed by value, it only occupies 8 bytes in the // parameter array, but the int is passed in an integer register, and the float // is passed in a floating point register. This is represented as two arguments // with the LLVM IR inreg attribute: // // declare void f(i32 inreg %i, float inreg %f) // // The code generator will only allocate 4 bytes from the parameter array for // the inreg arguments. All other arguments are allocated a multiple of 8 // bytes. // namespace { class SparcV9ABIInfo : public ABIInfo { public: SparcV9ABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {} private: ABIArgInfo classifyType(QualType RetTy, unsigned SizeLimit) const; void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; // Coercion type builder for structs passed in registers. The coercion type // serves two purposes: // // 1. Pad structs to a multiple of 64 bits, so they are passed 'left-aligned' // in registers. // 2. Expose aligned floating point elements as first-level elements, so the // code generator knows to pass them in floating point registers. // // We also compute the InReg flag which indicates that the struct contains // aligned 32-bit floats. // struct CoerceBuilder { llvm::LLVMContext &Context; const llvm::DataLayout &DL; SmallVector Elems; uint64_t Size; bool InReg; CoerceBuilder(llvm::LLVMContext &c, const llvm::DataLayout &dl) : Context(c), DL(dl), Size(0), InReg(false) {} // Pad Elems with integers until Size is ToSize. void pad(uint64_t ToSize) { assert(ToSize >= Size && "Cannot remove elements"); if (ToSize == Size) return; // Finish the current 64-bit word. uint64_t Aligned = llvm::RoundUpToAlignment(Size, 64); if (Aligned > Size && Aligned <= ToSize) { Elems.push_back(llvm::IntegerType::get(Context, Aligned - Size)); Size = Aligned; } // Add whole 64-bit words. while (Size + 64 <= ToSize) { Elems.push_back(llvm::Type::getInt64Ty(Context)); Size += 64; } // Final in-word padding. if (Size < ToSize) { Elems.push_back(llvm::IntegerType::get(Context, ToSize - Size)); Size = ToSize; } } // Add a floating point element at Offset. void addFloat(uint64_t Offset, llvm::Type *Ty, unsigned Bits) { // Unaligned floats are treated as integers. if (Offset % Bits) return; // The InReg flag is only required if there are any floats < 64 bits. if (Bits < 64) InReg = true; pad(Offset); Elems.push_back(Ty); Size = Offset + Bits; } // Add a struct type to the coercion type, starting at Offset (in bits). void addStruct(uint64_t Offset, llvm::StructType *StrTy) { const llvm::StructLayout *Layout = DL.getStructLayout(StrTy); for (unsigned i = 0, e = StrTy->getNumElements(); i != e; ++i) { llvm::Type *ElemTy = StrTy->getElementType(i); uint64_t ElemOffset = Offset + Layout->getElementOffsetInBits(i); switch (ElemTy->getTypeID()) { case llvm::Type::StructTyID: addStruct(ElemOffset, cast(ElemTy)); break; case llvm::Type::FloatTyID: addFloat(ElemOffset, ElemTy, 32); break; case llvm::Type::DoubleTyID: addFloat(ElemOffset, ElemTy, 64); break; case llvm::Type::FP128TyID: addFloat(ElemOffset, ElemTy, 128); break; case llvm::Type::PointerTyID: if (ElemOffset % 64 == 0) { pad(ElemOffset); Elems.push_back(ElemTy); Size += 64; } break; default: break; } } } // Check if Ty is a usable substitute for the coercion type. bool isUsableType(llvm::StructType *Ty) const { return llvm::makeArrayRef(Elems) == Ty->elements(); } // Get the coercion type as a literal struct type. llvm::Type *getType() const { if (Elems.size() == 1) return Elems.front(); else return llvm::StructType::get(Context, Elems); } }; }; } // end anonymous namespace ABIArgInfo SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const { if (Ty->isVoidType()) return ABIArgInfo::getIgnore(); uint64_t Size = getContext().getTypeSize(Ty); // Anything too big to fit in registers is passed with an explicit indirect // pointer / sret pointer. if (Size > SizeLimit) return getNaturalAlignIndirect(Ty, /*ByVal=*/false); // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); // Integer types smaller than a register are extended. if (Size < 64 && Ty->isIntegerType()) return ABIArgInfo::getExtend(); // Other non-aggregates go in registers. if (!isAggregateTypeForABI(Ty)) return ABIArgInfo::getDirect(); // If a C++ object has either a non-trivial copy constructor or a non-trivial // destructor, it is passed with an explicit indirect pointer / sret pointer. if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); // This is a small aggregate type that should be passed in registers. // Build a coercion type from the LLVM struct type. llvm::StructType *StrTy = dyn_cast(CGT.ConvertType(Ty)); if (!StrTy) return ABIArgInfo::getDirect(); CoerceBuilder CB(getVMContext(), getDataLayout()); CB.addStruct(0, StrTy); CB.pad(llvm::RoundUpToAlignment(CB.DL.getTypeSizeInBits(StrTy), 64)); // Try to use the original type for coercion. llvm::Type *CoerceTy = CB.isUsableType(StrTy) ? StrTy : CB.getType(); if (CB.InReg) return ABIArgInfo::getDirectInReg(CoerceTy); else return ABIArgInfo::getDirect(CoerceTy); } Address SparcV9ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { ABIArgInfo AI = classifyType(Ty, 16 * 8); llvm::Type *ArgTy = CGT.ConvertType(Ty); if (AI.canHaveCoerceToType() && !AI.getCoerceToType()) AI.setCoerceToType(ArgTy); CharUnits SlotSize = CharUnits::fromQuantity(8); CGBuilderTy &Builder = CGF.Builder; Address Addr(Builder.CreateLoad(VAListAddr, "ap.cur"), SlotSize); llvm::Type *ArgPtrTy = llvm::PointerType::getUnqual(ArgTy); auto TypeInfo = getContext().getTypeInfoInChars(Ty); Address ArgAddr = Address::invalid(); CharUnits Stride; switch (AI.getKind()) { case ABIArgInfo::Expand: case ABIArgInfo::InAlloca: llvm_unreachable("Unsupported ABI kind for va_arg"); case ABIArgInfo::Extend: { Stride = SlotSize; CharUnits Offset = SlotSize - TypeInfo.first; ArgAddr = Builder.CreateConstInBoundsByteGEP(Addr, Offset, "extend"); break; } case ABIArgInfo::Direct: { auto AllocSize = getDataLayout().getTypeAllocSize(AI.getCoerceToType()); Stride = CharUnits::fromQuantity(AllocSize).RoundUpToAlignment(SlotSize); ArgAddr = Addr; break; } case ABIArgInfo::Indirect: Stride = SlotSize; ArgAddr = Builder.CreateElementBitCast(Addr, ArgPtrTy, "indirect"); ArgAddr = Address(Builder.CreateLoad(ArgAddr, "indirect.arg"), TypeInfo.second); break; case ABIArgInfo::Ignore: return Address(llvm::UndefValue::get(ArgPtrTy), TypeInfo.second); } // Update VAList. llvm::Value *NextPtr = Builder.CreateConstInBoundsByteGEP(Addr.getPointer(), Stride, "ap.next"); Builder.CreateStore(NextPtr, VAListAddr); return Builder.CreateBitCast(ArgAddr, ArgPtrTy, "arg.addr"); } void SparcV9ABIInfo::computeInfo(CGFunctionInfo &FI) const { FI.getReturnInfo() = classifyType(FI.getReturnType(), 32 * 8); for (auto &I : FI.arguments()) I.info = classifyType(I.type, 16 * 8); } namespace { class SparcV9TargetCodeGenInfo : public TargetCodeGenInfo { public: SparcV9TargetCodeGenInfo(CodeGenTypes &CGT) : TargetCodeGenInfo(new SparcV9ABIInfo(CGT)) {} int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override { return 14; } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; }; } // end anonymous namespace bool SparcV9TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const { // This is calculated from the LLVM and GCC tables and verified // against gcc output. AFAIK all ABIs use the same encoding. CodeGen::CGBuilderTy &Builder = CGF.Builder; llvm::IntegerType *i8 = CGF.Int8Ty; llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4); llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8); // 0-31: the 8-byte general-purpose registers AssignToArrayRange(Builder, Address, Eight8, 0, 31); // 32-63: f0-31, the 4-byte floating-point registers AssignToArrayRange(Builder, Address, Four8, 32, 63); // Y = 64 // PSR = 65 // WIM = 66 // TBR = 67 // PC = 68 // NPC = 69 // FSR = 70 // CSR = 71 AssignToArrayRange(Builder, Address, Eight8, 64, 71); // 72-87: d0-15, the 8-byte floating-point registers AssignToArrayRange(Builder, Address, Eight8, 72, 87); return false; } //===----------------------------------------------------------------------===// // XCore ABI Implementation //===----------------------------------------------------------------------===// namespace { /// A SmallStringEnc instance is used to build up the TypeString by passing /// it by reference between functions that append to it. typedef llvm::SmallString<128> SmallStringEnc; /// TypeStringCache caches the meta encodings of Types. /// /// The reason for caching TypeStrings is two fold: /// 1. To cache a type's encoding for later uses; /// 2. As a means to break recursive member type inclusion. /// /// A cache Entry can have a Status of: /// NonRecursive: The type encoding is not recursive; /// Recursive: The type encoding is recursive; /// Incomplete: An incomplete TypeString; /// IncompleteUsed: An incomplete TypeString that has been used in a /// Recursive type encoding. /// /// A NonRecursive entry will have all of its sub-members expanded as fully /// as possible. Whilst it may contain types which are recursive, the type /// itself is not recursive and thus its encoding may be safely used whenever /// the type is encountered. /// /// A Recursive entry will have all of its sub-members expanded as fully as /// possible. The type itself is recursive and it may contain other types which /// are recursive. The Recursive encoding must not be used during the expansion /// of a recursive type's recursive branch. For simplicity the code uses /// IncompleteCount to reject all usage of Recursive encodings for member types. /// /// An Incomplete entry is always a RecordType and only encodes its /// identifier e.g. "s(S){}". Incomplete 'StubEnc' entries are ephemeral and /// are placed into the cache during type expansion as a means to identify and /// handle recursive inclusion of types as sub-members. If there is recursion /// the entry becomes IncompleteUsed. /// /// During the expansion of a RecordType's members: /// /// If the cache contains a NonRecursive encoding for the member type, the /// cached encoding is used; /// /// If the cache contains a Recursive encoding for the member type, the /// cached encoding is 'Swapped' out, as it may be incorrect, and... /// /// If the member is a RecordType, an Incomplete encoding is placed into the /// cache to break potential recursive inclusion of itself as a sub-member; /// /// Once a member RecordType has been expanded, its temporary incomplete /// entry is removed from the cache. If a Recursive encoding was swapped out /// it is swapped back in; /// /// If an incomplete entry is used to expand a sub-member, the incomplete /// entry is marked as IncompleteUsed. The cache keeps count of how many /// IncompleteUsed entries it currently contains in IncompleteUsedCount; /// /// If a member's encoding is found to be a NonRecursive or Recursive viz: /// IncompleteUsedCount==0, the member's encoding is added to the cache. /// Else the member is part of a recursive type and thus the recursion has /// been exited too soon for the encoding to be correct for the member. /// class TypeStringCache { enum Status {NonRecursive, Recursive, Incomplete, IncompleteUsed}; struct Entry { std::string Str; // The encoded TypeString for the type. enum Status State; // Information about the encoding in 'Str'. std::string Swapped; // A temporary place holder for a Recursive encoding // during the expansion of RecordType's members. }; std::map Map; unsigned IncompleteCount; // Number of Incomplete entries in the Map. unsigned IncompleteUsedCount; // Number of IncompleteUsed entries in the Map. public: TypeStringCache() : IncompleteCount(0), IncompleteUsedCount(0) {} void addIncomplete(const IdentifierInfo *ID, std::string StubEnc); bool removeIncomplete(const IdentifierInfo *ID); void addIfComplete(const IdentifierInfo *ID, StringRef Str, bool IsRecursive); StringRef lookupStr(const IdentifierInfo *ID); }; /// TypeString encodings for enum & union fields must be order. /// FieldEncoding is a helper for this ordering process. class FieldEncoding { bool HasName; std::string Enc; public: FieldEncoding(bool b, SmallStringEnc &e) : HasName(b), Enc(e.c_str()) {} StringRef str() {return Enc.c_str();} bool operator<(const FieldEncoding &rhs) const { if (HasName != rhs.HasName) return HasName; return Enc < rhs.Enc; } }; class XCoreABIInfo : public DefaultABIInfo { public: XCoreABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; }; class XCoreTargetCodeGenInfo : public TargetCodeGenInfo { mutable TypeStringCache TSC; public: XCoreTargetCodeGenInfo(CodeGenTypes &CGT) :TargetCodeGenInfo(new XCoreABIInfo(CGT)) {} void emitTargetMD(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const override; }; } // End anonymous namespace. Address XCoreABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { CGBuilderTy &Builder = CGF.Builder; // Get the VAList. CharUnits SlotSize = CharUnits::fromQuantity(4); Address AP(Builder.CreateLoad(VAListAddr), SlotSize); // Handle the argument. ABIArgInfo AI = classifyArgumentType(Ty); CharUnits TypeAlign = getContext().getTypeAlignInChars(Ty); llvm::Type *ArgTy = CGT.ConvertType(Ty); if (AI.canHaveCoerceToType() && !AI.getCoerceToType()) AI.setCoerceToType(ArgTy); llvm::Type *ArgPtrTy = llvm::PointerType::getUnqual(ArgTy); Address Val = Address::invalid(); CharUnits ArgSize = CharUnits::Zero(); switch (AI.getKind()) { case ABIArgInfo::Expand: case ABIArgInfo::InAlloca: llvm_unreachable("Unsupported ABI kind for va_arg"); case ABIArgInfo::Ignore: Val = Address(llvm::UndefValue::get(ArgPtrTy), TypeAlign); ArgSize = CharUnits::Zero(); break; case ABIArgInfo::Extend: case ABIArgInfo::Direct: Val = Builder.CreateBitCast(AP, ArgPtrTy); ArgSize = CharUnits::fromQuantity( getDataLayout().getTypeAllocSize(AI.getCoerceToType())); ArgSize = ArgSize.RoundUpToAlignment(SlotSize); break; case ABIArgInfo::Indirect: Val = Builder.CreateElementBitCast(AP, ArgPtrTy); Val = Address(Builder.CreateLoad(Val), TypeAlign); ArgSize = SlotSize; break; } // Increment the VAList. if (!ArgSize.isZero()) { llvm::Value *APN = Builder.CreateConstInBoundsByteGEP(AP.getPointer(), ArgSize); Builder.CreateStore(APN, VAListAddr); } return Val; } /// During the expansion of a RecordType, an incomplete TypeString is placed /// into the cache as a means to identify and break recursion. /// If there is a Recursive encoding in the cache, it is swapped out and will /// be reinserted by removeIncomplete(). /// All other types of encoding should have been used rather than arriving here. void TypeStringCache::addIncomplete(const IdentifierInfo *ID, std::string StubEnc) { if (!ID) return; Entry &E = Map[ID]; assert( (E.Str.empty() || E.State == Recursive) && "Incorrectly use of addIncomplete"); assert(!StubEnc.empty() && "Passing an empty string to addIncomplete()"); E.Swapped.swap(E.Str); // swap out the Recursive E.Str.swap(StubEnc); E.State = Incomplete; ++IncompleteCount; } /// Once the RecordType has been expanded, the temporary incomplete TypeString /// must be removed from the cache. /// If a Recursive was swapped out by addIncomplete(), it will be replaced. /// Returns true if the RecordType was defined recursively. bool TypeStringCache::removeIncomplete(const IdentifierInfo *ID) { if (!ID) return false; auto I = Map.find(ID); assert(I != Map.end() && "Entry not present"); Entry &E = I->second; assert( (E.State == Incomplete || E.State == IncompleteUsed) && "Entry must be an incomplete type"); bool IsRecursive = false; if (E.State == IncompleteUsed) { // We made use of our Incomplete encoding, thus we are recursive. IsRecursive = true; --IncompleteUsedCount; } if (E.Swapped.empty()) Map.erase(I); else { // Swap the Recursive back. E.Swapped.swap(E.Str); E.Swapped.clear(); E.State = Recursive; } --IncompleteCount; return IsRecursive; } /// Add the encoded TypeString to the cache only if it is NonRecursive or /// Recursive (viz: all sub-members were expanded as fully as possible). void TypeStringCache::addIfComplete(const IdentifierInfo *ID, StringRef Str, bool IsRecursive) { if (!ID || IncompleteUsedCount) return; // No key or it is is an incomplete sub-type so don't add. Entry &E = Map[ID]; if (IsRecursive && !E.Str.empty()) { assert(E.State==Recursive && E.Str.size() == Str.size() && "This is not the same Recursive entry"); // The parent container was not recursive after all, so we could have used // this Recursive sub-member entry after all, but we assumed the worse when // we started viz: IncompleteCount!=0. return; } assert(E.Str.empty() && "Entry already present"); E.Str = Str.str(); E.State = IsRecursive? Recursive : NonRecursive; } /// Return a cached TypeString encoding for the ID. If there isn't one, or we /// are recursively expanding a type (IncompleteCount != 0) and the cached /// encoding is Recursive, return an empty StringRef. StringRef TypeStringCache::lookupStr(const IdentifierInfo *ID) { if (!ID) return StringRef(); // We have no key. auto I = Map.find(ID); if (I == Map.end()) return StringRef(); // We have no encoding. Entry &E = I->second; if (E.State == Recursive && IncompleteCount) return StringRef(); // We don't use Recursive encodings for member types. if (E.State == Incomplete) { // The incomplete type is being used to break out of recursion. E.State = IncompleteUsed; ++IncompleteUsedCount; } return E.Str.c_str(); } /// The XCore ABI includes a type information section that communicates symbol /// type information to the linker. The linker uses this information to verify /// safety/correctness of things such as array bound and pointers et al. /// The ABI only requires C (and XC) language modules to emit TypeStrings. /// This type information (TypeString) is emitted into meta data for all global /// symbols: definitions, declarations, functions & variables. /// /// The TypeString carries type, qualifier, name, size & value details. /// Please see 'Tools Development Guide' section 2.16.2 for format details: /// https://www.xmos.com/download/public/Tools-Development-Guide%28X9114A%29.pdf /// The output is tested by test/CodeGen/xcore-stringtype.c. /// static bool getTypeString(SmallStringEnc &Enc, const Decl *D, CodeGen::CodeGenModule &CGM, TypeStringCache &TSC); /// XCore uses emitTargetMD to emit TypeString metadata for global symbols. void XCoreTargetCodeGenInfo::emitTargetMD(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { SmallStringEnc Enc; if (getTypeString(Enc, D, CGM, TSC)) { llvm::LLVMContext &Ctx = CGM.getModule().getContext(); llvm::SmallVector MDVals; MDVals.push_back(llvm::ConstantAsMetadata::get(GV)); MDVals.push_back(llvm::MDString::get(Ctx, Enc.str())); llvm::NamedMDNode *MD = CGM.getModule().getOrInsertNamedMetadata("xcore.typestrings"); MD->addOperand(llvm::MDNode::get(Ctx, MDVals)); } } static bool appendType(SmallStringEnc &Enc, QualType QType, const CodeGen::CodeGenModule &CGM, TypeStringCache &TSC); /// Helper function for appendRecordType(). /// Builds a SmallVector containing the encoded field types in declaration /// order. static bool extractFieldType(SmallVectorImpl &FE, const RecordDecl *RD, const CodeGen::CodeGenModule &CGM, TypeStringCache &TSC) { for (const auto *Field : RD->fields()) { SmallStringEnc Enc; Enc += "m("; Enc += Field->getName(); Enc += "){"; if (Field->isBitField()) { Enc += "b("; llvm::raw_svector_ostream OS(Enc); OS << Field->getBitWidthValue(CGM.getContext()); Enc += ':'; } if (!appendType(Enc, Field->getType(), CGM, TSC)) return false; if (Field->isBitField()) Enc += ')'; Enc += '}'; FE.emplace_back(!Field->getName().empty(), Enc); } return true; } /// Appends structure and union types to Enc and adds encoding to cache. /// Recursively calls appendType (via extractFieldType) for each field. /// Union types have their fields ordered according to the ABI. static bool appendRecordType(SmallStringEnc &Enc, const RecordType *RT, const CodeGen::CodeGenModule &CGM, TypeStringCache &TSC, const IdentifierInfo *ID) { // Append the cached TypeString if we have one. StringRef TypeString = TSC.lookupStr(ID); if (!TypeString.empty()) { Enc += TypeString; return true; } // Start to emit an incomplete TypeString. size_t Start = Enc.size(); Enc += (RT->isUnionType()? 'u' : 's'); Enc += '('; if (ID) Enc += ID->getName(); Enc += "){"; // We collect all encoded fields and order as necessary. bool IsRecursive = false; const RecordDecl *RD = RT->getDecl()->getDefinition(); if (RD && !RD->field_empty()) { // An incomplete TypeString stub is placed in the cache for this RecordType // so that recursive calls to this RecordType will use it whilst building a // complete TypeString for this RecordType. SmallVector FE; std::string StubEnc(Enc.substr(Start).str()); StubEnc += '}'; // StubEnc now holds a valid incomplete TypeString. TSC.addIncomplete(ID, std::move(StubEnc)); if (!extractFieldType(FE, RD, CGM, TSC)) { (void) TSC.removeIncomplete(ID); return false; } IsRecursive = TSC.removeIncomplete(ID); // The ABI requires unions to be sorted but not structures. // See FieldEncoding::operator< for sort algorithm. if (RT->isUnionType()) std::sort(FE.begin(), FE.end()); // We can now complete the TypeString. unsigned E = FE.size(); for (unsigned I = 0; I != E; ++I) { if (I) Enc += ','; Enc += FE[I].str(); } } Enc += '}'; TSC.addIfComplete(ID, Enc.substr(Start), IsRecursive); return true; } /// Appends enum types to Enc and adds the encoding to the cache. static bool appendEnumType(SmallStringEnc &Enc, const EnumType *ET, TypeStringCache &TSC, const IdentifierInfo *ID) { // Append the cached TypeString if we have one. StringRef TypeString = TSC.lookupStr(ID); if (!TypeString.empty()) { Enc += TypeString; return true; } size_t Start = Enc.size(); Enc += "e("; if (ID) Enc += ID->getName(); Enc += "){"; // We collect all encoded enumerations and order them alphanumerically. if (const EnumDecl *ED = ET->getDecl()->getDefinition()) { SmallVector FE; for (auto I = ED->enumerator_begin(), E = ED->enumerator_end(); I != E; ++I) { SmallStringEnc EnumEnc; EnumEnc += "m("; EnumEnc += I->getName(); EnumEnc += "){"; I->getInitVal().toString(EnumEnc); EnumEnc += '}'; FE.push_back(FieldEncoding(!I->getName().empty(), EnumEnc)); } std::sort(FE.begin(), FE.end()); unsigned E = FE.size(); for (unsigned I = 0; I != E; ++I) { if (I) Enc += ','; Enc += FE[I].str(); } } Enc += '}'; TSC.addIfComplete(ID, Enc.substr(Start), false); return true; } /// Appends type's qualifier to Enc. /// This is done prior to appending the type's encoding. static void appendQualifier(SmallStringEnc &Enc, QualType QT) { // Qualifiers are emitted in alphabetical order. static const char *const Table[]={"","c:","r:","cr:","v:","cv:","rv:","crv:"}; int Lookup = 0; if (QT.isConstQualified()) Lookup += 1<<0; if (QT.isRestrictQualified()) Lookup += 1<<1; if (QT.isVolatileQualified()) Lookup += 1<<2; Enc += Table[Lookup]; } /// Appends built-in types to Enc. static bool appendBuiltinType(SmallStringEnc &Enc, const BuiltinType *BT) { const char *EncType; switch (BT->getKind()) { case BuiltinType::Void: EncType = "0"; break; case BuiltinType::Bool: EncType = "b"; break; case BuiltinType::Char_U: EncType = "uc"; break; case BuiltinType::UChar: EncType = "uc"; break; case BuiltinType::SChar: EncType = "sc"; break; case BuiltinType::UShort: EncType = "us"; break; case BuiltinType::Short: EncType = "ss"; break; case BuiltinType::UInt: EncType = "ui"; break; case BuiltinType::Int: EncType = "si"; break; case BuiltinType::ULong: EncType = "ul"; break; case BuiltinType::Long: EncType = "sl"; break; case BuiltinType::ULongLong: EncType = "ull"; break; case BuiltinType::LongLong: EncType = "sll"; break; case BuiltinType::Float: EncType = "ft"; break; case BuiltinType::Double: EncType = "d"; break; case BuiltinType::LongDouble: EncType = "ld"; break; default: return false; } Enc += EncType; return true; } /// Appends a pointer encoding to Enc before calling appendType for the pointee. static bool appendPointerType(SmallStringEnc &Enc, const PointerType *PT, const CodeGen::CodeGenModule &CGM, TypeStringCache &TSC) { Enc += "p("; if (!appendType(Enc, PT->getPointeeType(), CGM, TSC)) return false; Enc += ')'; return true; } /// Appends array encoding to Enc before calling appendType for the element. static bool appendArrayType(SmallStringEnc &Enc, QualType QT, const ArrayType *AT, const CodeGen::CodeGenModule &CGM, TypeStringCache &TSC, StringRef NoSizeEnc) { if (AT->getSizeModifier() != ArrayType::Normal) return false; Enc += "a("; if (const ConstantArrayType *CAT = dyn_cast(AT)) CAT->getSize().toStringUnsigned(Enc); else Enc += NoSizeEnc; // Global arrays use "*", otherwise it is "". Enc += ':'; // The Qualifiers should be attached to the type rather than the array. appendQualifier(Enc, QT); if (!appendType(Enc, AT->getElementType(), CGM, TSC)) return false; Enc += ')'; return true; } /// Appends a function encoding to Enc, calling appendType for the return type /// and the arguments. static bool appendFunctionType(SmallStringEnc &Enc, const FunctionType *FT, const CodeGen::CodeGenModule &CGM, TypeStringCache &TSC) { Enc += "f{"; if (!appendType(Enc, FT->getReturnType(), CGM, TSC)) return false; Enc += "}("; if (const FunctionProtoType *FPT = FT->getAs()) { // N.B. we are only interested in the adjusted param types. auto I = FPT->param_type_begin(); auto E = FPT->param_type_end(); if (I != E) { do { if (!appendType(Enc, *I, CGM, TSC)) return false; ++I; if (I != E) Enc += ','; } while (I != E); if (FPT->isVariadic()) Enc += ",va"; } else { if (FPT->isVariadic()) Enc += "va"; else Enc += '0'; } } Enc += ')'; return true; } /// Handles the type's qualifier before dispatching a call to handle specific /// type encodings. static bool appendType(SmallStringEnc &Enc, QualType QType, const CodeGen::CodeGenModule &CGM, TypeStringCache &TSC) { QualType QT = QType.getCanonicalType(); if (const ArrayType *AT = QT->getAsArrayTypeUnsafe()) // The Qualifiers should be attached to the type rather than the array. // Thus we don't call appendQualifier() here. return appendArrayType(Enc, QT, AT, CGM, TSC, ""); appendQualifier(Enc, QT); if (const BuiltinType *BT = QT->getAs()) return appendBuiltinType(Enc, BT); if (const PointerType *PT = QT->getAs()) return appendPointerType(Enc, PT, CGM, TSC); if (const EnumType *ET = QT->getAs()) return appendEnumType(Enc, ET, TSC, QT.getBaseTypeIdentifier()); if (const RecordType *RT = QT->getAsStructureType()) return appendRecordType(Enc, RT, CGM, TSC, QT.getBaseTypeIdentifier()); if (const RecordType *RT = QT->getAsUnionType()) return appendRecordType(Enc, RT, CGM, TSC, QT.getBaseTypeIdentifier()); if (const FunctionType *FT = QT->getAs()) return appendFunctionType(Enc, FT, CGM, TSC); return false; } static bool getTypeString(SmallStringEnc &Enc, const Decl *D, CodeGen::CodeGenModule &CGM, TypeStringCache &TSC) { if (!D) return false; if (const FunctionDecl *FD = dyn_cast(D)) { if (FD->getLanguageLinkage() != CLanguageLinkage) return false; return appendType(Enc, FD->getType(), CGM, TSC); } if (const VarDecl *VD = dyn_cast(D)) { if (VD->getLanguageLinkage() != CLanguageLinkage) return false; QualType QT = VD->getType().getCanonicalType(); if (const ArrayType *AT = QT->getAsArrayTypeUnsafe()) { // Global ArrayTypes are given a size of '*' if the size is unknown. // The Qualifiers should be attached to the type rather than the array. // Thus we don't call appendQualifier() here. return appendArrayType(Enc, QT, AT, CGM, TSC, "*"); } return appendType(Enc, QT, CGM, TSC); } return false; } //===----------------------------------------------------------------------===// // Driver code //===----------------------------------------------------------------------===// const llvm::Triple &CodeGenModule::getTriple() const { return getTarget().getTriple(); } bool CodeGenModule::supportsCOMDAT() const { return !getTriple().isOSBinFormatMachO(); } const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { if (TheTargetCodeGenInfo) return *TheTargetCodeGenInfo; const llvm::Triple &Triple = getTarget().getTriple(); switch (Triple.getArch()) { default: return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo(Types)); case llvm::Triple::le32: return *(TheTargetCodeGenInfo = new PNaClTargetCodeGenInfo(Types)); case llvm::Triple::mips: case llvm::Triple::mipsel: if (Triple.getOS() == llvm::Triple::NaCl) return *(TheTargetCodeGenInfo = new PNaClTargetCodeGenInfo(Types)); return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, true)); case llvm::Triple::mips64: case llvm::Triple::mips64el: return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, false)); case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: { AArch64ABIInfo::ABIKind Kind = AArch64ABIInfo::AAPCS; if (getTarget().getABI() == "darwinpcs") Kind = AArch64ABIInfo::DarwinPCS; return *(TheTargetCodeGenInfo = new AArch64TargetCodeGenInfo(Types, Kind)); } case llvm::Triple::wasm32: case llvm::Triple::wasm64: return *(TheTargetCodeGenInfo = new WebAssemblyTargetCodeGenInfo(Types)); case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: { if (Triple.getOS() == llvm::Triple::Win32) { TheTargetCodeGenInfo = new WindowsARMTargetCodeGenInfo(Types, ARMABIInfo::AAPCS_VFP); return *TheTargetCodeGenInfo; } ARMABIInfo::ABIKind Kind = ARMABIInfo::AAPCS; StringRef ABIStr = getTarget().getABI(); if (ABIStr == "apcs-gnu") Kind = ARMABIInfo::APCS; else if (ABIStr == "aapcs16") Kind = ARMABIInfo::AAPCS16_VFP; else if (CodeGenOpts.FloatABI == "hard" || (CodeGenOpts.FloatABI != "soft" && Triple.getEnvironment() == llvm::Triple::GNUEABIHF)) Kind = ARMABIInfo::AAPCS_VFP; return *(TheTargetCodeGenInfo = new ARMTargetCodeGenInfo(Types, Kind)); } case llvm::Triple::ppc: return *(TheTargetCodeGenInfo = new PPC32TargetCodeGenInfo(Types, CodeGenOpts.FloatABI == "soft")); case llvm::Triple::ppc64: if (Triple.isOSBinFormatELF()) { PPC64_SVR4_ABIInfo::ABIKind Kind = PPC64_SVR4_ABIInfo::ELFv1; if (getTarget().getABI() == "elfv2") Kind = PPC64_SVR4_ABIInfo::ELFv2; bool HasQPX = getTarget().getABI() == "elfv1-qpx"; return *(TheTargetCodeGenInfo = new PPC64_SVR4_TargetCodeGenInfo(Types, Kind, HasQPX)); } else return *(TheTargetCodeGenInfo = new PPC64TargetCodeGenInfo(Types)); case llvm::Triple::ppc64le: { assert(Triple.isOSBinFormatELF() && "PPC64 LE non-ELF not supported!"); PPC64_SVR4_ABIInfo::ABIKind Kind = PPC64_SVR4_ABIInfo::ELFv2; if (getTarget().getABI() == "elfv1" || getTarget().getABI() == "elfv1-qpx") Kind = PPC64_SVR4_ABIInfo::ELFv1; bool HasQPX = getTarget().getABI() == "elfv1-qpx"; return *(TheTargetCodeGenInfo = new PPC64_SVR4_TargetCodeGenInfo(Types, Kind, HasQPX)); } case llvm::Triple::nvptx: case llvm::Triple::nvptx64: return *(TheTargetCodeGenInfo = new NVPTXTargetCodeGenInfo(Types)); case llvm::Triple::msp430: return *(TheTargetCodeGenInfo = new MSP430TargetCodeGenInfo(Types)); case llvm::Triple::systemz: { bool HasVector = getTarget().getABI() == "vector"; return *(TheTargetCodeGenInfo = new SystemZTargetCodeGenInfo(Types, HasVector)); } case llvm::Triple::tce: return *(TheTargetCodeGenInfo = new TCETargetCodeGenInfo(Types)); case llvm::Triple::x86: { bool IsDarwinVectorABI = Triple.isOSDarwin(); bool RetSmallStructInRegABI = X86_32TargetCodeGenInfo::isStructReturnInRegABI(Triple, CodeGenOpts); bool IsWin32FloatStructABI = Triple.isOSWindows() && !Triple.isOSCygMing(); if (Triple.getOS() == llvm::Triple::Win32) { return *(TheTargetCodeGenInfo = new WinX86_32TargetCodeGenInfo( Types, IsDarwinVectorABI, RetSmallStructInRegABI, IsWin32FloatStructABI, CodeGenOpts.NumRegisterParameters)); } else { return *(TheTargetCodeGenInfo = new X86_32TargetCodeGenInfo( Types, IsDarwinVectorABI, RetSmallStructInRegABI, IsWin32FloatStructABI, CodeGenOpts.NumRegisterParameters, CodeGenOpts.FloatABI == "soft")); } } case llvm::Triple::x86_64: { StringRef ABI = getTarget().getABI(); X86AVXABILevel AVXLevel = (ABI == "avx512" ? X86AVXABILevel::AVX512 : ABI == "avx" ? X86AVXABILevel::AVX : X86AVXABILevel::None); switch (Triple.getOS()) { case llvm::Triple::Win32: return *(TheTargetCodeGenInfo = new WinX86_64TargetCodeGenInfo(Types, AVXLevel)); case llvm::Triple::PS4: return *(TheTargetCodeGenInfo = new PS4TargetCodeGenInfo(Types, AVXLevel)); default: return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo(Types, AVXLevel)); } } case llvm::Triple::hexagon: return *(TheTargetCodeGenInfo = new HexagonTargetCodeGenInfo(Types)); case llvm::Triple::r600: return *(TheTargetCodeGenInfo = new AMDGPUTargetCodeGenInfo(Types)); case llvm::Triple::amdgcn: return *(TheTargetCodeGenInfo = new AMDGPUTargetCodeGenInfo(Types)); case llvm::Triple::sparcv9: return *(TheTargetCodeGenInfo = new SparcV9TargetCodeGenInfo(Types)); case llvm::Triple::xcore: return *(TheTargetCodeGenInfo = new XCoreTargetCodeGenInfo(Types)); } } Index: projects/clang380-import/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp =================================================================== --- projects/clang380-import/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp (revision 295858) +++ projects/clang380-import/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp (revision 295859) @@ -1,4530 +1,4546 @@ //===--- ToolChains.cpp - ToolChain Implementations -------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "ToolChains.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" #include "clang/Basic/VirtualFileSystem.h" #include "clang/Config/config.h" // for GCC_INSTALL_PREFIX #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/OptTable.h" #include "llvm/Option/Option.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" #include "llvm/Support/TargetParser.h" #include "llvm/Support/raw_ostream.h" #include // ::getenv #include using namespace clang::driver; using namespace clang::driver::toolchains; using namespace clang; using namespace llvm::opt; MachO::MachO(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args) { // We expect 'as', 'ld', etc. to be adjacent to our install dir. getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); } /// Darwin - Darwin tool chain for i386 and x86_64. Darwin::Darwin(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : MachO(D, Triple, Args), TargetInitialized(false) {} types::ID MachO::LookupTypeForExtension(const char *Ext) const { types::ID Ty = types::lookupTypeForExtension(Ext); // Darwin always preprocesses assembly files (unless -x is used explicitly). if (Ty == types::TY_PP_Asm) return types::TY_Asm; return Ty; } bool MachO::HasNativeLLVMSupport() const { return true; } /// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0. ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const { if (isTargetWatchOSBased()) return ObjCRuntime(ObjCRuntime::WatchOS, TargetVersion); if (isTargetIOSBased()) return ObjCRuntime(ObjCRuntime::iOS, TargetVersion); if (isNonFragile) return ObjCRuntime(ObjCRuntime::MacOSX, TargetVersion); return ObjCRuntime(ObjCRuntime::FragileMacOSX, TargetVersion); } /// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2. bool Darwin::hasBlocksRuntime() const { if (isTargetWatchOSBased()) return true; else if (isTargetIOSBased()) return !isIPhoneOSVersionLT(3, 2); else { assert(isTargetMacOS() && "unexpected darwin target"); return !isMacosxVersionLT(10, 6); } } // This is just a MachO name translation routine and there's no // way to join this into ARMTargetParser without breaking all // other assumptions. Maybe MachO should consider standardising // their nomenclature. static const char *ArmMachOArchName(StringRef Arch) { return llvm::StringSwitch(Arch) .Case("armv6k", "armv6") .Case("armv6m", "armv6m") .Case("armv5tej", "armv5") .Case("xscale", "xscale") .Case("armv4t", "armv4t") .Case("armv7", "armv7") .Cases("armv7a", "armv7-a", "armv7") .Cases("armv7r", "armv7-r", "armv7") .Cases("armv7em", "armv7e-m", "armv7em") .Cases("armv7k", "armv7-k", "armv7k") .Cases("armv7m", "armv7-m", "armv7m") .Cases("armv7s", "armv7-s", "armv7s") .Default(nullptr); } static const char *ArmMachOArchNameCPU(StringRef CPU) { unsigned ArchKind = llvm::ARM::parseCPUArch(CPU); if (ArchKind == llvm::ARM::AK_INVALID) return nullptr; StringRef Arch = llvm::ARM::getArchName(ArchKind); // FIXME: Make sure this MachO triple mangling is really necessary. // ARMv5* normalises to ARMv5. if (Arch.startswith("armv5")) Arch = Arch.substr(0, 5); // ARMv6*, except ARMv6M, normalises to ARMv6. else if (Arch.startswith("armv6") && !Arch.endswith("6m")) Arch = Arch.substr(0, 5); // ARMv7A normalises to ARMv7. else if (Arch.endswith("v7a")) Arch = Arch.substr(0, 5); return Arch.data(); } static bool isSoftFloatABI(const ArgList &Args) { Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, options::OPT_mfloat_abi_EQ); if (!A) return false; return A->getOption().matches(options::OPT_msoft_float) || (A->getOption().matches(options::OPT_mfloat_abi_EQ) && A->getValue() == StringRef("soft")); } StringRef MachO::getMachOArchName(const ArgList &Args) const { switch (getTriple().getArch()) { default: return getDefaultUniversalArchName(); case llvm::Triple::aarch64: return "arm64"; case llvm::Triple::thumb: case llvm::Triple::arm: if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) if (const char *Arch = ArmMachOArchName(A->getValue())) return Arch; if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) if (const char *Arch = ArmMachOArchNameCPU(A->getValue())) return Arch; return "arm"; } } Darwin::~Darwin() {} MachO::~MachO() {} std::string MachO::ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const { llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); return Triple.getTriple(); } std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const { llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); // If the target isn't initialized (e.g., an unknown Darwin platform, return // the default triple). if (!isTargetInitialized()) return Triple.getTriple(); SmallString<16> Str; if (isTargetWatchOSBased()) Str += "watchos"; else if (isTargetTvOSBased()) Str += "tvos"; else if (isTargetIOSBased()) Str += "ios"; else Str += "macosx"; Str += getTargetVersion().getAsString(); Triple.setOSName(Str); return Triple.getTriple(); } void Generic_ELF::anchor() {} Tool *MachO::getTool(Action::ActionClass AC) const { switch (AC) { case Action::LipoJobClass: if (!Lipo) Lipo.reset(new tools::darwin::Lipo(*this)); return Lipo.get(); case Action::DsymutilJobClass: if (!Dsymutil) Dsymutil.reset(new tools::darwin::Dsymutil(*this)); return Dsymutil.get(); case Action::VerifyDebugInfoJobClass: if (!VerifyDebug) VerifyDebug.reset(new tools::darwin::VerifyDebug(*this)); return VerifyDebug.get(); default: return ToolChain::getTool(AC); } } Tool *MachO::buildLinker() const { return new tools::darwin::Linker(*this); } Tool *MachO::buildAssembler() const { return new tools::darwin::Assembler(*this); } DarwinClang::DarwinClang(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Darwin(D, Triple, Args) {} void DarwinClang::addClangWarningOptions(ArgStringList &CC1Args) const { // For modern targets, promote certain warnings to errors. if (isTargetWatchOSBased() || getTriple().isArch64Bit()) { // Always enable -Wdeprecated-objc-isa-usage and promote it // to an error. CC1Args.push_back("-Wdeprecated-objc-isa-usage"); CC1Args.push_back("-Werror=deprecated-objc-isa-usage"); // For iOS and watchOS, also error about implicit function declarations, // as that can impact calling conventions. if (!isTargetMacOS()) CC1Args.push_back("-Werror=implicit-function-declaration"); } } /// \brief Determine whether Objective-C automated reference counting is /// enabled. static bool isObjCAutoRefCount(const ArgList &Args) { return Args.hasFlag(options::OPT_fobjc_arc, options::OPT_fno_objc_arc, false); } void DarwinClang::AddLinkARCArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Avoid linking compatibility stubs on i386 mac. if (isTargetMacOS() && getArch() == llvm::Triple::x86) return; ObjCRuntime runtime = getDefaultObjCRuntime(/*nonfragile*/ true); if ((runtime.hasNativeARC() || !isObjCAutoRefCount(Args)) && runtime.hasSubscripting()) return; CmdArgs.push_back("-force_load"); SmallString<128> P(getDriver().ClangExecutable); llvm::sys::path::remove_filename(P); // 'clang' llvm::sys::path::remove_filename(P); // 'bin' llvm::sys::path::append(P, "lib", "arc", "libarclite_"); // Mash in the platform. if (isTargetWatchOSSimulator()) P += "watchsimulator"; else if (isTargetWatchOS()) P += "watchos"; else if (isTargetTvOSSimulator()) P += "appletvsimulator"; else if (isTargetTvOS()) P += "appletvos"; else if (isTargetIOSSimulator()) P += "iphonesimulator"; else if (isTargetIPhoneOS()) P += "iphoneos"; else P += "macosx"; P += ".a"; CmdArgs.push_back(Args.MakeArgString(P)); } void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, StringRef DarwinLibName, bool AlwaysLink, bool IsEmbedded, bool AddRPath) const { SmallString<128> Dir(getDriver().ResourceDir); llvm::sys::path::append(Dir, "lib", IsEmbedded ? "macho_embedded" : "darwin"); SmallString<128> P(Dir); llvm::sys::path::append(P, DarwinLibName); // For now, allow missing resource libraries to support developers who may // not have compiler-rt checked out or integrated into their build (unless // we explicitly force linking with this library). if (AlwaysLink || getVFS().exists(P)) CmdArgs.push_back(Args.MakeArgString(P)); // Adding the rpaths might negatively interact when other rpaths are involved, // so we should make sure we add the rpaths last, after all user-specified // rpaths. This is currently true from this place, but we need to be // careful if this function is ever called before user's rpaths are emitted. if (AddRPath) { assert(DarwinLibName.endswith(".dylib") && "must be a dynamic library"); // Add @executable_path to rpath to support having the dylib copied with // the executable. CmdArgs.push_back("-rpath"); CmdArgs.push_back("@executable_path"); // Add the path to the resource dir to rpath to support using the dylib // from the default location without copying. CmdArgs.push_back("-rpath"); CmdArgs.push_back(Args.MakeArgString(Dir)); } } void Darwin::addProfileRTLibs(const ArgList &Args, ArgStringList &CmdArgs) const { if (!needsProfileRT(Args)) return; // TODO: Clean this up once autoconf is gone SmallString<128> P(getDriver().ResourceDir); llvm::sys::path::append(P, "lib", "darwin"); const char *Library = "libclang_rt.profile_osx.a"; // Select the appropriate runtime library for the target. if (isTargetWatchOS()) { Library = "libclang_rt.profile_watchos.a"; } else if (isTargetWatchOSSimulator()) { llvm::sys::path::append(P, "libclang_rt.profile_watchossim.a"); Library = getVFS().exists(P) ? "libclang_rt.profile_watchossim.a" : "libclang_rt.profile_watchos.a"; } else if (isTargetTvOS()) { Library = "libclang_rt.profile_tvos.a"; } else if (isTargetTvOSSimulator()) { llvm::sys::path::append(P, "libclang_rt.profile_tvossim.a"); Library = getVFS().exists(P) ? "libclang_rt.profile_tvossim.a" : "libclang_rt.profile_tvos.a"; } else if (isTargetIPhoneOS()) { Library = "libclang_rt.profile_ios.a"; } else if (isTargetIOSSimulator()) { llvm::sys::path::append(P, "libclang_rt.profile_iossim.a"); Library = getVFS().exists(P) ? "libclang_rt.profile_iossim.a" : "libclang_rt.profile_ios.a"; } else { assert(isTargetMacOS() && "unexpected non MacOS platform"); } AddLinkRuntimeLib(Args, CmdArgs, Library, /*AlwaysLink*/ true); return; } void DarwinClang::AddLinkSanitizerLibArgs(const ArgList &Args, ArgStringList &CmdArgs, StringRef Sanitizer) const { if (!Args.hasArg(options::OPT_dynamiclib) && !Args.hasArg(options::OPT_bundle)) { // Sanitizer runtime libraries requires C++. AddCXXStdlibLibArgs(Args, CmdArgs); } // ASan is not supported on watchOS. assert(isTargetMacOS() || isTargetIOSSimulator()); StringRef OS = isTargetMacOS() ? "osx" : "iossim"; AddLinkRuntimeLib( Args, CmdArgs, (Twine("libclang_rt.") + Sanitizer + "_" + OS + "_dynamic.dylib").str(), /*AlwaysLink*/ true, /*IsEmbedded*/ false, /*AddRPath*/ true); if (GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) { // Add explicit dependcy on -lc++abi, as -lc++ doesn't re-export // all RTTI-related symbols that UBSan uses. CmdArgs.push_back("-lc++abi"); } } void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Darwin only supports the compiler-rt based runtime libraries. switch (GetRuntimeLibType(Args)) { case ToolChain::RLT_CompilerRT: break; default: getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform) << Args.getLastArg(options::OPT_rtlib_EQ)->getValue() << "darwin"; return; } // Darwin doesn't support real static executables, don't link any runtime // libraries with -static. if (Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_fapple_kext) || Args.hasArg(options::OPT_mkernel)) return; // Reject -static-libgcc for now, we can deal with this when and if someone // cares. This is useful in situations where someone wants to statically link // something like libstdc++, and needs its runtime support routines. if (const Arg *A = Args.getLastArg(options::OPT_static_libgcc)) { getDriver().Diag(diag::err_drv_unsupported_opt) << A->getAsString(Args); return; } const SanitizerArgs &Sanitize = getSanitizerArgs(); if (Sanitize.needsAsanRt()) AddLinkSanitizerLibArgs(Args, CmdArgs, "asan"); if (Sanitize.needsUbsanRt()) AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan"); if (Sanitize.needsTsanRt()) AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan"); // Otherwise link libSystem, then the dynamic runtime library, and finally any // target specific static runtime library. CmdArgs.push_back("-lSystem"); // Select the dynamic runtime library and the target specific static library. if (isTargetWatchOSBased()) { // We currently always need a static runtime library for watchOS. AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.watchos.a"); } else if (isTargetTvOSBased()) { // We currently always need a static runtime library for tvOS. AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.tvos.a"); } else if (isTargetIOSBased()) { // If we are compiling as iOS / simulator, don't attempt to link libgcc_s.1, // it never went into the SDK. // Linking against libgcc_s.1 isn't needed for iOS 5.0+ if (isIPhoneOSVersionLT(5, 0) && !isTargetIOSSimulator() && getTriple().getArch() != llvm::Triple::aarch64) CmdArgs.push_back("-lgcc_s.1"); // We currently always need a static runtime library for iOS. AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.ios.a"); } else { assert(isTargetMacOS() && "unexpected non MacOS platform"); // The dynamic runtime library was merged with libSystem for 10.6 and // beyond; only 10.4 and 10.5 need an additional runtime library. if (isMacosxVersionLT(10, 5)) CmdArgs.push_back("-lgcc_s.10.4"); else if (isMacosxVersionLT(10, 6)) CmdArgs.push_back("-lgcc_s.10.5"); // For OS X, we thought we would only need a static runtime library when // targeting 10.4, to provide versions of the static functions which were // omitted from 10.4.dylib. // // Unfortunately, that turned out to not be true, because Darwin system // headers can still use eprintf on i386, and it is not exported from // libSystem. Therefore, we still must provide a runtime library just for // the tiny tiny handful of projects that *might* use that symbol. if (isMacosxVersionLT(10, 5)) { AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.10.4.a"); } else { if (getTriple().getArch() == llvm::Triple::x86) AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.eprintf.a"); AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.osx.a"); } } } void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { const OptTable &Opts = getDriver().getOpts(); // Support allowing the SDKROOT environment variable used by xcrun and other // Xcode tools to define the default sysroot, by making it the default for // isysroot. if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { // Warn if the path does not exist. if (!getVFS().exists(A->getValue())) getDriver().Diag(clang::diag::warn_missing_sysroot) << A->getValue(); } else { if (char *env = ::getenv("SDKROOT")) { // We only use this value as the default if it is an absolute path, // exists, and it is not the root path. if (llvm::sys::path::is_absolute(env) && getVFS().exists(env) && StringRef(env) != "/") { Args.append(Args.MakeSeparateArg( nullptr, Opts.getOption(options::OPT_isysroot), env)); } } } Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ); Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ); Arg *TvOSVersion = Args.getLastArg(options::OPT_mtvos_version_min_EQ); Arg *WatchOSVersion = Args.getLastArg(options::OPT_mwatchos_version_min_EQ); if (OSXVersion && (iOSVersion || TvOSVersion || WatchOSVersion)) { getDriver().Diag(diag::err_drv_argument_not_allowed_with) << OSXVersion->getAsString(Args) << (iOSVersion ? iOSVersion : TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args); iOSVersion = TvOSVersion = WatchOSVersion = nullptr; } else if (iOSVersion && (TvOSVersion || WatchOSVersion)) { getDriver().Diag(diag::err_drv_argument_not_allowed_with) << iOSVersion->getAsString(Args) << (TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args); TvOSVersion = WatchOSVersion = nullptr; } else if (TvOSVersion && WatchOSVersion) { getDriver().Diag(diag::err_drv_argument_not_allowed_with) << TvOSVersion->getAsString(Args) << WatchOSVersion->getAsString(Args); WatchOSVersion = nullptr; } else if (!OSXVersion && !iOSVersion && !TvOSVersion && !WatchOSVersion) { // If no deployment target was specified on the command line, check for // environment defines. std::string OSXTarget; std::string iOSTarget; std::string TvOSTarget; std::string WatchOSTarget; if (char *env = ::getenv("MACOSX_DEPLOYMENT_TARGET")) OSXTarget = env; if (char *env = ::getenv("IPHONEOS_DEPLOYMENT_TARGET")) iOSTarget = env; if (char *env = ::getenv("TVOS_DEPLOYMENT_TARGET")) TvOSTarget = env; if (char *env = ::getenv("WATCHOS_DEPLOYMENT_TARGET")) WatchOSTarget = env; // If there is no command-line argument to specify the Target version and // no environment variable defined, see if we can set the default based // on -isysroot. if (OSXTarget.empty() && iOSTarget.empty() && WatchOSTarget.empty() && TvOSTarget.empty() && Args.hasArg(options::OPT_isysroot)) { if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { StringRef isysroot = A->getValue(); // Assume SDK has path: SOME_PATH/SDKs/PlatformXX.YY.sdk size_t BeginSDK = isysroot.rfind("SDKs/"); size_t EndSDK = isysroot.rfind(".sdk"); if (BeginSDK != StringRef::npos && EndSDK != StringRef::npos) { StringRef SDK = isysroot.slice(BeginSDK + 5, EndSDK); // Slice the version number out. // Version number is between the first and the last number. size_t StartVer = SDK.find_first_of("0123456789"); size_t EndVer = SDK.find_last_of("0123456789"); if (StartVer != StringRef::npos && EndVer > StartVer) { StringRef Version = SDK.slice(StartVer, EndVer + 1); if (SDK.startswith("iPhoneOS") || SDK.startswith("iPhoneSimulator")) iOSTarget = Version; else if (SDK.startswith("MacOSX")) OSXTarget = Version; else if (SDK.startswith("WatchOS") || SDK.startswith("WatchSimulator")) WatchOSTarget = Version; else if (SDK.startswith("AppleTVOS") || SDK.startswith("AppleTVSimulator")) TvOSTarget = Version; } } } } // If no OSX or iOS target has been specified, try to guess platform // from arch name and compute the version from the triple. if (OSXTarget.empty() && iOSTarget.empty() && TvOSTarget.empty() && WatchOSTarget.empty()) { StringRef MachOArchName = getMachOArchName(Args); unsigned Major, Minor, Micro; if (MachOArchName == "armv7" || MachOArchName == "armv7s" || MachOArchName == "arm64") { getTriple().getiOSVersion(Major, Minor, Micro); llvm::raw_string_ostream(iOSTarget) << Major << '.' << Minor << '.' << Micro; } else if (MachOArchName == "armv7k") { getTriple().getWatchOSVersion(Major, Minor, Micro); llvm::raw_string_ostream(WatchOSTarget) << Major << '.' << Minor << '.' << Micro; } else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" && MachOArchName != "armv7em") { if (!getTriple().getMacOSXVersion(Major, Minor, Micro)) { getDriver().Diag(diag::err_drv_invalid_darwin_version) << getTriple().getOSName(); } llvm::raw_string_ostream(OSXTarget) << Major << '.' << Minor << '.' << Micro; } } // Do not allow conflicts with the watchOS target. if (!WatchOSTarget.empty() && (!iOSTarget.empty() || !TvOSTarget.empty())) { getDriver().Diag(diag::err_drv_conflicting_deployment_targets) << "WATCHOS_DEPLOYMENT_TARGET" << (!iOSTarget.empty() ? "IPHONEOS_DEPLOYMENT_TARGET" : "TVOS_DEPLOYMENT_TARGET"); } // Do not allow conflicts with the tvOS target. if (!TvOSTarget.empty() && !iOSTarget.empty()) { getDriver().Diag(diag::err_drv_conflicting_deployment_targets) << "TVOS_DEPLOYMENT_TARGET" << "IPHONEOS_DEPLOYMENT_TARGET"; } // Allow conflicts among OSX and iOS for historical reasons, but choose the // default platform. if (!OSXTarget.empty() && (!iOSTarget.empty() || !WatchOSTarget.empty() || !TvOSTarget.empty())) { if (getTriple().getArch() == llvm::Triple::arm || getTriple().getArch() == llvm::Triple::aarch64 || getTriple().getArch() == llvm::Triple::thumb) OSXTarget = ""; else iOSTarget = WatchOSTarget = TvOSTarget = ""; } if (!OSXTarget.empty()) { const Option O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); OSXVersion = Args.MakeJoinedArg(nullptr, O, OSXTarget); Args.append(OSXVersion); } else if (!iOSTarget.empty()) { const Option O = Opts.getOption(options::OPT_miphoneos_version_min_EQ); iOSVersion = Args.MakeJoinedArg(nullptr, O, iOSTarget); Args.append(iOSVersion); } else if (!TvOSTarget.empty()) { const Option O = Opts.getOption(options::OPT_mtvos_version_min_EQ); TvOSVersion = Args.MakeJoinedArg(nullptr, O, TvOSTarget); Args.append(TvOSVersion); } else if (!WatchOSTarget.empty()) { const Option O = Opts.getOption(options::OPT_mwatchos_version_min_EQ); WatchOSVersion = Args.MakeJoinedArg(nullptr, O, WatchOSTarget); Args.append(WatchOSVersion); } } DarwinPlatformKind Platform; if (OSXVersion) Platform = MacOS; else if (iOSVersion) Platform = IPhoneOS; else if (TvOSVersion) Platform = TvOS; else if (WatchOSVersion) Platform = WatchOS; else llvm_unreachable("Unable to infer Darwin variant"); // Set the tool chain target information. unsigned Major, Minor, Micro; bool HadExtra; if (Platform == MacOS) { assert((!iOSVersion && !TvOSVersion && !WatchOSVersion) && "Unknown target platform!"); if (!Driver::GetReleaseVersion(OSXVersion->getValue(), Major, Minor, Micro, HadExtra) || HadExtra || Major != 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << OSXVersion->getAsString(Args); } else if (Platform == IPhoneOS) { assert(iOSVersion && "Unknown target platform!"); if (!Driver::GetReleaseVersion(iOSVersion->getValue(), Major, Minor, Micro, HadExtra) || HadExtra || Major >= 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << iOSVersion->getAsString(Args); } else if (Platform == TvOS) { if (!Driver::GetReleaseVersion(TvOSVersion->getValue(), Major, Minor, Micro, HadExtra) || HadExtra || Major >= 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << TvOSVersion->getAsString(Args); } else if (Platform == WatchOS) { if (!Driver::GetReleaseVersion(WatchOSVersion->getValue(), Major, Minor, Micro, HadExtra) || HadExtra || Major >= 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << WatchOSVersion->getAsString(Args); } else llvm_unreachable("unknown kind of Darwin platform"); // Recognize iOS targets with an x86 architecture as the iOS simulator. if (iOSVersion && (getTriple().getArch() == llvm::Triple::x86 || getTriple().getArch() == llvm::Triple::x86_64)) Platform = IPhoneOSSimulator; if (TvOSVersion && (getTriple().getArch() == llvm::Triple::x86 || getTriple().getArch() == llvm::Triple::x86_64)) Platform = TvOSSimulator; if (WatchOSVersion && (getTriple().getArch() == llvm::Triple::x86 || getTriple().getArch() == llvm::Triple::x86_64)) Platform = WatchOSSimulator; setTarget(Platform, Major, Minor, Micro); } void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CXXStdlibType Type = GetCXXStdlibType(Args); switch (Type) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); break; case ToolChain::CST_Libstdcxx: // Unfortunately, -lstdc++ doesn't always exist in the standard search path; // it was previously found in the gcc lib dir. However, for all the Darwin // platforms we care about it was -lstdc++.6, so we search for that // explicitly if we can't see an obvious -lstdc++ candidate. // Check in the sysroot first. if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { SmallString<128> P(A->getValue()); llvm::sys::path::append(P, "usr", "lib", "libstdc++.dylib"); if (!getVFS().exists(P)) { llvm::sys::path::remove_filename(P); llvm::sys::path::append(P, "libstdc++.6.dylib"); if (getVFS().exists(P)) { CmdArgs.push_back(Args.MakeArgString(P)); return; } } } // Otherwise, look in the root. // FIXME: This should be removed someday when we don't have to care about // 10.6 and earlier, where /usr/lib/libstdc++.dylib does not exist. if (!getVFS().exists("/usr/lib/libstdc++.dylib") && getVFS().exists("/usr/lib/libstdc++.6.dylib")) { CmdArgs.push_back("/usr/lib/libstdc++.6.dylib"); return; } // Otherwise, let the linker search. CmdArgs.push_back("-lstdc++"); break; } } void DarwinClang::AddCCKextLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // For Darwin platforms, use the compiler-rt-based support library // instead of the gcc-provided one (which is also incidentally // only present in the gcc lib dir, which makes it hard to find). SmallString<128> P(getDriver().ResourceDir); llvm::sys::path::append(P, "lib", "darwin"); // Use the newer cc_kext for iOS ARM after 6.0. if (isTargetWatchOS()) { llvm::sys::path::append(P, "libclang_rt.cc_kext_watchos.a"); } else if (isTargetTvOS()) { llvm::sys::path::append(P, "libclang_rt.cc_kext_tvos.a"); } else if (isTargetIPhoneOS()) { llvm::sys::path::append(P, "libclang_rt.cc_kext_ios.a"); } else { llvm::sys::path::append(P, "libclang_rt.cc_kext.a"); } // For now, allow missing resource libraries to support developers who may // not have compiler-rt checked out or integrated into their build. if (getVFS().exists(P)) CmdArgs.push_back(Args.MakeArgString(P)); } DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args, const char *BoundArch) const { DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); const OptTable &Opts = getDriver().getOpts(); // FIXME: We really want to get out of the tool chain level argument // translation business, as it makes the driver functionality much // more opaque. For now, we follow gcc closely solely for the // purpose of easily achieving feature parity & testability. Once we // have something that works, we should reevaluate each translation // and try to push it down into tool specific logic. for (Arg *A : Args) { if (A->getOption().matches(options::OPT_Xarch__)) { // Skip this argument unless the architecture matches either the toolchain // triple arch, or the arch being bound. llvm::Triple::ArchType XarchArch = tools::darwin::getArchTypeForMachOArchName(A->getValue(0)); if (!(XarchArch == getArch() || (BoundArch && XarchArch == tools::darwin::getArchTypeForMachOArchName(BoundArch)))) continue; Arg *OriginalArg = A; unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); unsigned Prev = Index; std::unique_ptr XarchArg(Opts.ParseOneArg(Args, Index)); // If the argument parsing failed or more than one argument was // consumed, the -Xarch_ argument's parameter tried to consume // extra arguments. Emit an error and ignore. // // We also want to disallow any options which would alter the // driver behavior; that isn't going to work in our model. We // use isDriverOption() as an approximation, although things // like -O4 are going to slip through. if (!XarchArg || Index > Prev + 1) { getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) << A->getAsString(Args); continue; } else if (XarchArg->getOption().hasFlag(options::DriverOption)) { getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) << A->getAsString(Args); continue; } XarchArg->setBaseArg(A); A = XarchArg.release(); DAL->AddSynthesizedArg(A); // Linker input arguments require custom handling. The problem is that we // have already constructed the phase actions, so we can not treat them as // "input arguments". if (A->getOption().hasFlag(options::LinkerInput)) { // Convert the argument into individual Zlinker_input_args. for (const char *Value : A->getValues()) { DAL->AddSeparateArg( OriginalArg, Opts.getOption(options::OPT_Zlinker_input), Value); } continue; } } // Sob. These is strictly gcc compatible for the time being. Apple // gcc translates options twice, which means that self-expanding // options add duplicates. switch ((options::ID)A->getOption().getID()) { default: DAL->append(A); break; case options::OPT_mkernel: case options::OPT_fapple_kext: DAL->append(A); DAL->AddFlagArg(A, Opts.getOption(options::OPT_static)); break; case options::OPT_dependency_file: DAL->AddSeparateArg(A, Opts.getOption(options::OPT_MF), A->getValue()); break; case options::OPT_gfull: DAL->AddFlagArg(A, Opts.getOption(options::OPT_g_Flag)); DAL->AddFlagArg( A, Opts.getOption(options::OPT_fno_eliminate_unused_debug_symbols)); break; case options::OPT_gused: DAL->AddFlagArg(A, Opts.getOption(options::OPT_g_Flag)); DAL->AddFlagArg( A, Opts.getOption(options::OPT_feliminate_unused_debug_symbols)); break; case options::OPT_shared: DAL->AddFlagArg(A, Opts.getOption(options::OPT_dynamiclib)); break; case options::OPT_fconstant_cfstrings: DAL->AddFlagArg(A, Opts.getOption(options::OPT_mconstant_cfstrings)); break; case options::OPT_fno_constant_cfstrings: DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_constant_cfstrings)); break; case options::OPT_Wnonportable_cfstrings: DAL->AddFlagArg(A, Opts.getOption(options::OPT_mwarn_nonportable_cfstrings)); break; case options::OPT_Wno_nonportable_cfstrings: DAL->AddFlagArg( A, Opts.getOption(options::OPT_mno_warn_nonportable_cfstrings)); break; case options::OPT_fpascal_strings: DAL->AddFlagArg(A, Opts.getOption(options::OPT_mpascal_strings)); break; case options::OPT_fno_pascal_strings: DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_pascal_strings)); break; } } if (getTriple().getArch() == llvm::Triple::x86 || getTriple().getArch() == llvm::Triple::x86_64) if (!Args.hasArgNoClaim(options::OPT_mtune_EQ)) DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mtune_EQ), "core2"); // Add the arch options based on the particular spelling of -arch, to match // how the driver driver works. if (BoundArch) { StringRef Name = BoundArch; const Option MCpu = Opts.getOption(options::OPT_mcpu_EQ); const Option MArch = Opts.getOption(options::OPT_march_EQ); // This code must be kept in sync with LLVM's getArchTypeForDarwinArch, // which defines the list of which architectures we accept. if (Name == "ppc") ; else if (Name == "ppc601") DAL->AddJoinedArg(nullptr, MCpu, "601"); else if (Name == "ppc603") DAL->AddJoinedArg(nullptr, MCpu, "603"); else if (Name == "ppc604") DAL->AddJoinedArg(nullptr, MCpu, "604"); else if (Name == "ppc604e") DAL->AddJoinedArg(nullptr, MCpu, "604e"); else if (Name == "ppc750") DAL->AddJoinedArg(nullptr, MCpu, "750"); else if (Name == "ppc7400") DAL->AddJoinedArg(nullptr, MCpu, "7400"); else if (Name == "ppc7450") DAL->AddJoinedArg(nullptr, MCpu, "7450"); else if (Name == "ppc970") DAL->AddJoinedArg(nullptr, MCpu, "970"); else if (Name == "ppc64" || Name == "ppc64le") DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64)); else if (Name == "i386") ; else if (Name == "i486") DAL->AddJoinedArg(nullptr, MArch, "i486"); else if (Name == "i586") DAL->AddJoinedArg(nullptr, MArch, "i586"); else if (Name == "i686") DAL->AddJoinedArg(nullptr, MArch, "i686"); else if (Name == "pentium") DAL->AddJoinedArg(nullptr, MArch, "pentium"); else if (Name == "pentium2") DAL->AddJoinedArg(nullptr, MArch, "pentium2"); else if (Name == "pentpro") DAL->AddJoinedArg(nullptr, MArch, "pentiumpro"); else if (Name == "pentIIm3") DAL->AddJoinedArg(nullptr, MArch, "pentium2"); else if (Name == "x86_64") DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64)); else if (Name == "x86_64h") { DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64)); DAL->AddJoinedArg(nullptr, MArch, "x86_64h"); } else if (Name == "arm") DAL->AddJoinedArg(nullptr, MArch, "armv4t"); else if (Name == "armv4t") DAL->AddJoinedArg(nullptr, MArch, "armv4t"); else if (Name == "armv5") DAL->AddJoinedArg(nullptr, MArch, "armv5tej"); else if (Name == "xscale") DAL->AddJoinedArg(nullptr, MArch, "xscale"); else if (Name == "armv6") DAL->AddJoinedArg(nullptr, MArch, "armv6k"); else if (Name == "armv6m") DAL->AddJoinedArg(nullptr, MArch, "armv6m"); else if (Name == "armv7") DAL->AddJoinedArg(nullptr, MArch, "armv7a"); else if (Name == "armv7em") DAL->AddJoinedArg(nullptr, MArch, "armv7em"); else if (Name == "armv7k") DAL->AddJoinedArg(nullptr, MArch, "armv7k"); else if (Name == "armv7m") DAL->AddJoinedArg(nullptr, MArch, "armv7m"); else if (Name == "armv7s") DAL->AddJoinedArg(nullptr, MArch, "armv7s"); } return DAL; } void MachO::AddLinkRuntimeLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Embedded targets are simple at the moment, not supporting sanitizers and // with different libraries for each member of the product { static, PIC } x // { hard-float, soft-float } llvm::SmallString<32> CompilerRT = StringRef("libclang_rt."); CompilerRT += (tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard) ? "hard" : "soft"; CompilerRT += Args.hasArg(options::OPT_fPIC) ? "_pic.a" : "_static.a"; AddLinkRuntimeLib(Args, CmdArgs, CompilerRT, false, true); } DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, const char *BoundArch) const { // First get the generic Apple args, before moving onto Darwin-specific ones. DerivedArgList *DAL = MachO::TranslateArgs(Args, BoundArch); const OptTable &Opts = getDriver().getOpts(); // If no architecture is bound, none of the translations here are relevant. if (!BoundArch) return DAL; // Add an explicit version min argument for the deployment target. We do this // after argument translation because -Xarch_ arguments may add a version min // argument. AddDeploymentTarget(*DAL); // For iOS 6, undo the translation to add -static for -mkernel/-fapple-kext. // FIXME: It would be far better to avoid inserting those -static arguments, // but we can't check the deployment target in the translation code until // it is set here. if (isTargetWatchOSBased() || (isTargetIOSBased() && !isIPhoneOSVersionLT(6, 0))) { for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie; ) { Arg *A = *it; ++it; if (A->getOption().getID() != options::OPT_mkernel && A->getOption().getID() != options::OPT_fapple_kext) continue; assert(it != ie && "unexpected argument translation"); A = *it; assert(A->getOption().getID() == options::OPT_static && "missing expected -static argument"); it = DAL->getArgs().erase(it); } } // Default to use libc++ on OS X 10.9+ and iOS 7+. if (((isTargetMacOS() && !isMacosxVersionLT(10, 9)) || (isTargetIOSBased() && !isIPhoneOSVersionLT(7, 0)) || isTargetWatchOSBased()) && !Args.getLastArg(options::OPT_stdlib_EQ)) DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_stdlib_EQ), "libc++"); // Validate the C++ standard library choice. CXXStdlibType Type = GetCXXStdlibType(*DAL); if (Type == ToolChain::CST_Libcxx) { // Check whether the target provides libc++. StringRef where; // Complain about targeting iOS < 5.0 in any way. if (isTargetIOSBased() && isIPhoneOSVersionLT(5, 0)) where = "iOS 5.0"; if (where != StringRef()) { getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) << where; } } return DAL; } bool MachO::IsUnwindTablesDefault() const { return getArch() == llvm::Triple::x86_64; } bool MachO::UseDwarfDebugFlags() const { if (const char *S = ::getenv("RC_DEBUG_OPTIONS")) return S[0] != '\0'; return false; } bool Darwin::UseSjLjExceptions(const ArgList &Args) const { // Darwin uses SjLj exceptions on ARM. if (getTriple().getArch() != llvm::Triple::arm && getTriple().getArch() != llvm::Triple::thumb) return false; // Only watchOS uses the new DWARF/Compact unwinding method. return !isTargetWatchOS(); } bool MachO::isPICDefault() const { return true; } bool MachO::isPIEDefault() const { return false; } bool MachO::isPICDefaultForced() const { return (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::aarch64); } bool MachO::SupportsProfiling() const { // Profiling instrumentation is only supported on x86. return getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::x86_64; } void Darwin::addMinVersionArgs(const ArgList &Args, ArgStringList &CmdArgs) const { VersionTuple TargetVersion = getTargetVersion(); if (isTargetWatchOS()) CmdArgs.push_back("-watchos_version_min"); else if (isTargetWatchOSSimulator()) CmdArgs.push_back("-watchos_simulator_version_min"); else if (isTargetTvOS()) CmdArgs.push_back("-tvos_version_min"); else if (isTargetTvOSSimulator()) CmdArgs.push_back("-tvos_simulator_version_min"); else if (isTargetIOSSimulator()) CmdArgs.push_back("-ios_simulator_version_min"); else if (isTargetIOSBased()) CmdArgs.push_back("-iphoneos_version_min"); else { assert(isTargetMacOS() && "unexpected target"); CmdArgs.push_back("-macosx_version_min"); } CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); } void Darwin::addStartObjectFileArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Derived from startfile spec. if (Args.hasArg(options::OPT_dynamiclib)) { // Derived from darwin_dylib1 spec. if (isTargetWatchOSBased()) { ; // watchOS does not need dylib1.o. } else if (isTargetIOSSimulator()) { ; // iOS simulator does not need dylib1.o. } else if (isTargetIPhoneOS()) { if (isIPhoneOSVersionLT(3, 1)) CmdArgs.push_back("-ldylib1.o"); } else { if (isMacosxVersionLT(10, 5)) CmdArgs.push_back("-ldylib1.o"); else if (isMacosxVersionLT(10, 6)) CmdArgs.push_back("-ldylib1.10.5.o"); } } else { if (Args.hasArg(options::OPT_bundle)) { if (!Args.hasArg(options::OPT_static)) { // Derived from darwin_bundle1 spec. if (isTargetWatchOSBased()) { ; // watchOS does not need bundle1.o. } else if (isTargetIOSSimulator()) { ; // iOS simulator does not need bundle1.o. } else if (isTargetIPhoneOS()) { if (isIPhoneOSVersionLT(3, 1)) CmdArgs.push_back("-lbundle1.o"); } else { if (isMacosxVersionLT(10, 6)) CmdArgs.push_back("-lbundle1.o"); } } } else { if (Args.hasArg(options::OPT_pg) && SupportsProfiling()) { if (Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_object) || Args.hasArg(options::OPT_preload)) { CmdArgs.push_back("-lgcrt0.o"); } else { CmdArgs.push_back("-lgcrt1.o"); // darwin_crt2 spec is empty. } // By default on OS X 10.8 and later, we don't link with a crt1.o // file and the linker knows to use _main as the entry point. But, // when compiling with -pg, we need to link with the gcrt1.o file, // so pass the -no_new_main option to tell the linker to use the // "start" symbol as the entry point. if (isTargetMacOS() && !isMacosxVersionLT(10, 8)) CmdArgs.push_back("-no_new_main"); } else { if (Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_object) || Args.hasArg(options::OPT_preload)) { CmdArgs.push_back("-lcrt0.o"); } else { // Derived from darwin_crt1 spec. if (isTargetWatchOSBased()) { ; // watchOS does not need crt1.o. } else if (isTargetIOSSimulator()) { ; // iOS simulator does not need crt1.o. } else if (isTargetIPhoneOS()) { if (getArch() == llvm::Triple::aarch64) ; // iOS does not need any crt1 files for arm64 else if (isIPhoneOSVersionLT(3, 1)) CmdArgs.push_back("-lcrt1.o"); else if (isIPhoneOSVersionLT(6, 0)) CmdArgs.push_back("-lcrt1.3.1.o"); } else { if (isMacosxVersionLT(10, 5)) CmdArgs.push_back("-lcrt1.o"); else if (isMacosxVersionLT(10, 6)) CmdArgs.push_back("-lcrt1.10.5.o"); else if (isMacosxVersionLT(10, 8)) CmdArgs.push_back("-lcrt1.10.6.o"); // darwin_crt2 spec is empty. } } } } } if (!isTargetIPhoneOS() && Args.hasArg(options::OPT_shared_libgcc) && !isTargetWatchOS() && isMacosxVersionLT(10, 5)) { const char *Str = Args.MakeArgString(GetFilePath("crt3.o")); CmdArgs.push_back(Str); } } bool Darwin::SupportsObjCGC() const { return isTargetMacOS(); } void Darwin::CheckObjCARC() const { if (isTargetIOSBased() || isTargetWatchOSBased() || (isTargetMacOS() && !isMacosxVersionLT(10, 6))) return; getDriver().Diag(diag::err_arc_unsupported_on_toolchain); } SanitizerMask Darwin::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); if (isTargetMacOS() || isTargetIOSSimulator()) Res |= SanitizerKind::Address; if (isTargetMacOS()) { if (!isMacosxVersionLT(10, 9)) Res |= SanitizerKind::Vptr; Res |= SanitizerKind::SafeStack; Res |= SanitizerKind::Thread; } return Res; } /// Generic_GCC - A tool chain using the 'gcc' command to perform /// all subcommands; this relies on gcc translating the majority of /// command line options. /// \brief Parse a GCCVersion object out of a string of text. /// /// This is the primary means of forming GCCVersion objects. /*static*/ Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) { const GCCVersion BadVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; std::pair First = VersionText.split('.'); std::pair Second = First.second.split('.'); GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0) return BadVersion; GoodVersion.MajorStr = First.first.str(); if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0) return BadVersion; GoodVersion.MinorStr = Second.first.str(); // First look for a number prefix and parse that if present. Otherwise just // stash the entire patch string in the suffix, and leave the number // unspecified. This covers versions strings such as: // 4.4 // 4.4.0 // 4.4.x // 4.4.2-rc4 // 4.4.x-patched // And retains any patch number it finds. StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str(); if (!PatchText.empty()) { if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) { // Try to parse the number and any suffix. if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) || GoodVersion.Patch < 0) return BadVersion; GoodVersion.PatchSuffix = PatchText.substr(EndNumber); } } return GoodVersion; } /// \brief Less-than for GCCVersion, implementing a Strict Weak Ordering. bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor, int RHSPatch, StringRef RHSPatchSuffix) const { if (Major != RHSMajor) return Major < RHSMajor; if (Minor != RHSMinor) return Minor < RHSMinor; if (Patch != RHSPatch) { // Note that versions without a specified patch sort higher than those with // a patch. if (RHSPatch == -1) return true; if (Patch == -1) return false; // Otherwise just sort on the patch itself. return Patch < RHSPatch; } if (PatchSuffix != RHSPatchSuffix) { // Sort empty suffixes higher. if (RHSPatchSuffix.empty()) return true; if (PatchSuffix.empty()) return false; // Provide a lexicographic sort to make this a total ordering. return PatchSuffix < RHSPatchSuffix; } // The versions are equal. return false; } static llvm::StringRef getGCCToolchainDir(const ArgList &Args) { const Arg *A = Args.getLastArg(options::OPT_gcc_toolchain); if (A) return A->getValue(); return GCC_INSTALL_PREFIX; } /// \brief Initialize a GCCInstallationDetector from the driver. /// /// This performs all of the autodetection and sets up the various paths. /// Once constructed, a GCCInstallationDetector is essentially immutable. /// /// FIXME: We shouldn't need an explicit TargetTriple parameter here, and /// should instead pull the target out of the driver. This is currently /// necessary because the driver doesn't store the final version of the target /// triple. void Generic_GCC::GCCInstallationDetector::init( const llvm::Triple &TargetTriple, const ArgList &Args, ArrayRef ExtraTripleAliases) { llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant() : TargetTriple.get32BitArchVariant(); // The library directories which may contain GCC installations. SmallVector CandidateLibDirs, CandidateBiarchLibDirs; // The compatible GCC triples for this particular architecture. SmallVector CandidateTripleAliases; SmallVector CandidateBiarchTripleAliases; CollectLibDirsAndTriples(TargetTriple, BiarchVariantTriple, CandidateLibDirs, CandidateTripleAliases, CandidateBiarchLibDirs, CandidateBiarchTripleAliases); // Compute the set of prefixes for our search. SmallVector Prefixes(D.PrefixDirs.begin(), D.PrefixDirs.end()); StringRef GCCToolchainDir = getGCCToolchainDir(Args); if (GCCToolchainDir != "") { if (GCCToolchainDir.back() == '/') GCCToolchainDir = GCCToolchainDir.drop_back(); // remove the / Prefixes.push_back(GCCToolchainDir); } else { // If we have a SysRoot, try that first. if (!D.SysRoot.empty()) { Prefixes.push_back(D.SysRoot); Prefixes.push_back(D.SysRoot + "/usr"); } // Then look for gcc installed alongside clang. Prefixes.push_back(D.InstalledDir + "/.."); // And finally in /usr. if (D.SysRoot.empty()) Prefixes.push_back("/usr"); } // Loop over the various components which exist and select the best GCC // installation available. GCC installs are ranked by version number. Version = GCCVersion::Parse("0.0.0"); for (const std::string &Prefix : Prefixes) { if (!D.getVFS().exists(Prefix)) continue; for (StringRef Suffix : CandidateLibDirs) { const std::string LibDir = Prefix + Suffix.str(); if (!D.getVFS().exists(LibDir)) continue; for (StringRef Candidate : ExtraTripleAliases) // Try these first. ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); for (StringRef Candidate : CandidateTripleAliases) ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); } for (StringRef Suffix : CandidateBiarchLibDirs) { const std::string LibDir = Prefix + Suffix.str(); if (!D.getVFS().exists(LibDir)) continue; for (StringRef Candidate : CandidateBiarchTripleAliases) ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate, /*NeedsBiarchSuffix=*/ true); } } } void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { for (const auto &InstallPath : CandidateGCCInstallPaths) OS << "Found candidate GCC installation: " << InstallPath << "\n"; if (!GCCInstallPath.empty()) OS << "Selected GCC installation: " << GCCInstallPath << "\n"; for (const auto &Multilib : Multilibs) OS << "Candidate multilib: " << Multilib << "\n"; if (Multilibs.size() != 0 || !SelectedMultilib.isDefault()) OS << "Selected multilib: " << SelectedMultilib << "\n"; } bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { if (BiarchSibling.hasValue()) { M = BiarchSibling.getValue(); return true; } return false; } /*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples( const llvm::Triple &TargetTriple, const llvm::Triple &BiarchTriple, SmallVectorImpl &LibDirs, SmallVectorImpl &TripleAliases, SmallVectorImpl &BiarchLibDirs, SmallVectorImpl &BiarchTripleAliases) { // Declare a bunch of static data sets that we'll select between below. These // are specifically designed to always refer to string literals to avoid any // lifetime or initialization issues. static const char *const AArch64LibDirs[] = {"/lib64", "/lib"}; static const char *const AArch64Triples[] = { "aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-linux-android", "aarch64-redhat-linux"}; static const char *const AArch64beLibDirs[] = {"/lib"}; static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu", "aarch64_be-linux-gnu"}; static const char *const ARMLibDirs[] = {"/lib"}; static const char *const ARMTriples[] = {"arm-linux-gnueabi", "arm-linux-androideabi"}; static const char *const ARMHFTriples[] = {"arm-linux-gnueabihf", "armv7hl-redhat-linux-gnueabi"}; static const char *const ARMebLibDirs[] = {"/lib"}; static const char *const ARMebTriples[] = {"armeb-linux-gnueabi", "armeb-linux-androideabi"}; static const char *const ARMebHFTriples[] = { "armeb-linux-gnueabihf", "armebv7hl-redhat-linux-gnueabi"}; static const char *const X86_64LibDirs[] = {"/lib64", "/lib"}; static const char *const X86_64Triples[] = { "x86_64-linux-gnu", "x86_64-unknown-linux-gnu", "x86_64-pc-linux-gnu", "x86_64-redhat-linux6E", "x86_64-redhat-linux", "x86_64-suse-linux", "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", "x86_64-slackware-linux", "x86_64-linux-android", "x86_64-unknown-linux"}; static const char *const X32LibDirs[] = {"/libx32"}; static const char *const X86LibDirs[] = {"/lib32", "/lib"}; static const char *const X86Triples[] = { "i686-linux-gnu", "i686-pc-linux-gnu", "i486-linux-gnu", "i386-linux-gnu", "i386-redhat-linux6E", "i686-redhat-linux", "i586-redhat-linux", "i386-redhat-linux", "i586-suse-linux", "i486-slackware-linux", "i686-montavista-linux", "i686-linux-android", "i586-linux-gnu"}; static const char *const MIPSLibDirs[] = {"/lib"}; static const char *const MIPSTriples[] = {"mips-linux-gnu", "mips-mti-linux", "mips-mti-linux-gnu", "mips-img-linux-gnu"}; static const char *const MIPSELLibDirs[] = {"/lib"}; static const char *const MIPSELTriples[] = { "mipsel-linux-gnu", "mipsel-linux-android", "mips-img-linux-gnu"}; static const char *const MIPS64LibDirs[] = {"/lib64", "/lib"}; static const char *const MIPS64Triples[] = { "mips64-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu", "mips64-linux-gnuabi64"}; static const char *const MIPS64ELLibDirs[] = {"/lib64", "/lib"}; static const char *const MIPS64ELTriples[] = { "mips64el-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu", "mips64el-linux-android", "mips64el-linux-gnuabi64"}; static const char *const PPCLibDirs[] = {"/lib32", "/lib"}; static const char *const PPCTriples[] = { "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-linux-gnuspe", "powerpc-suse-linux", "powerpc-montavista-linuxspe"}; static const char *const PPC64LibDirs[] = {"/lib64", "/lib"}; static const char *const PPC64Triples[] = { "powerpc64-linux-gnu", "powerpc64-unknown-linux-gnu", "powerpc64-suse-linux", "ppc64-redhat-linux"}; static const char *const PPC64LELibDirs[] = {"/lib64", "/lib"}; static const char *const PPC64LETriples[] = { "powerpc64le-linux-gnu", "powerpc64le-unknown-linux-gnu", "powerpc64le-suse-linux", "ppc64le-redhat-linux"}; static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"}; static const char *const SPARCv8Triples[] = {"sparc-linux-gnu", "sparcv8-linux-gnu"}; static const char *const SPARCv9LibDirs[] = {"/lib64", "/lib"}; static const char *const SPARCv9Triples[] = {"sparc64-linux-gnu", "sparcv9-linux-gnu"}; static const char *const SystemZLibDirs[] = {"/lib64", "/lib"}; static const char *const SystemZTriples[] = { "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu", "s390x-suse-linux", "s390x-redhat-linux"}; // Solaris. static const char *const SolarisSPARCLibDirs[] = {"/gcc"}; static const char *const SolarisSPARCTriples[] = {"sparc-sun-solaris2.11", "i386-pc-solaris2.11"}; using std::begin; using std::end; if (TargetTriple.getOS() == llvm::Triple::Solaris) { LibDirs.append(begin(SolarisSPARCLibDirs), end(SolarisSPARCLibDirs)); TripleAliases.append(begin(SolarisSPARCTriples), end(SolarisSPARCTriples)); return; } switch (TargetTriple.getArch()) { case llvm::Triple::aarch64: LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); TripleAliases.append(begin(AArch64Triples), end(AArch64Triples)); BiarchLibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); BiarchTripleAliases.append(begin(AArch64Triples), end(AArch64Triples)); break; case llvm::Triple::aarch64_be: LibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs)); TripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples)); BiarchLibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs)); BiarchTripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples)); break; case llvm::Triple::arm: case llvm::Triple::thumb: LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs)); if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { TripleAliases.append(begin(ARMHFTriples), end(ARMHFTriples)); } else { TripleAliases.append(begin(ARMTriples), end(ARMTriples)); } break; case llvm::Triple::armeb: case llvm::Triple::thumbeb: LibDirs.append(begin(ARMebLibDirs), end(ARMebLibDirs)); if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { TripleAliases.append(begin(ARMebHFTriples), end(ARMebHFTriples)); } else { TripleAliases.append(begin(ARMebTriples), end(ARMebTriples)); } break; case llvm::Triple::x86_64: LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); TripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); // x32 is always available when x86_64 is available, so adding it as // secondary arch with x86_64 triples if (TargetTriple.getEnvironment() == llvm::Triple::GNUX32) { BiarchLibDirs.append(begin(X32LibDirs), end(X32LibDirs)); BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); } else { BiarchLibDirs.append(begin(X86LibDirs), end(X86LibDirs)); BiarchTripleAliases.append(begin(X86Triples), end(X86Triples)); } break; case llvm::Triple::x86: LibDirs.append(begin(X86LibDirs), end(X86LibDirs)); TripleAliases.append(begin(X86Triples), end(X86Triples)); BiarchLibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); break; case llvm::Triple::mips: LibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs)); TripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); BiarchLibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs)); BiarchTripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples)); break; case llvm::Triple::mipsel: LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); TripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); TripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); BiarchTripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); break; case llvm::Triple::mips64: LibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs)); TripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples)); BiarchLibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs)); BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); break; case llvm::Triple::mips64el: LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); TripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); BiarchTripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); break; case llvm::Triple::ppc: LibDirs.append(begin(PPCLibDirs), end(PPCLibDirs)); TripleAliases.append(begin(PPCTriples), end(PPCTriples)); BiarchLibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs)); BiarchTripleAliases.append(begin(PPC64Triples), end(PPC64Triples)); break; case llvm::Triple::ppc64: LibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs)); TripleAliases.append(begin(PPC64Triples), end(PPC64Triples)); BiarchLibDirs.append(begin(PPCLibDirs), end(PPCLibDirs)); BiarchTripleAliases.append(begin(PPCTriples), end(PPCTriples)); break; case llvm::Triple::ppc64le: LibDirs.append(begin(PPC64LELibDirs), end(PPC64LELibDirs)); TripleAliases.append(begin(PPC64LETriples), end(PPC64LETriples)); break; case llvm::Triple::sparc: case llvm::Triple::sparcel: LibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs)); TripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples)); BiarchLibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs)); BiarchTripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples)); break; case llvm::Triple::sparcv9: LibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs)); TripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples)); BiarchLibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs)); BiarchTripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples)); break; case llvm::Triple::systemz: LibDirs.append(begin(SystemZLibDirs), end(SystemZLibDirs)); TripleAliases.append(begin(SystemZTriples), end(SystemZTriples)); break; default: // By default, just rely on the standard lib directories and the original // triple. break; } // Always append the drivers target triple to the end, in case it doesn't // match any of our aliases. TripleAliases.push_back(TargetTriple.str()); // Also include the multiarch variant if it's different. if (TargetTriple.str() != BiarchTriple.str()) BiarchTripleAliases.push_back(BiarchTriple.str()); } // \brief -- try common CUDA installation paths looking for files we need for // CUDA compilation. void Generic_GCC::CudaInstallationDetector::init( const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args) { SmallVector CudaPathCandidates; if (Args.hasArg(options::OPT_cuda_path_EQ)) CudaPathCandidates.push_back( Args.getLastArgValue(options::OPT_cuda_path_EQ)); else { CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda"); CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-7.5"); CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-7.0"); } for (const auto &CudaPath : CudaPathCandidates) { if (CudaPath.empty() || !D.getVFS().exists(CudaPath)) continue; CudaInstallPath = CudaPath; CudaIncludePath = CudaInstallPath + "/include"; CudaLibDevicePath = CudaInstallPath + "/nvvm/libdevice"; CudaLibPath = CudaInstallPath + (TargetTriple.isArch64Bit() ? "/lib64" : "/lib"); if (!(D.getVFS().exists(CudaIncludePath) && D.getVFS().exists(CudaLibPath) && D.getVFS().exists(CudaLibDevicePath))) continue; std::error_code EC; for (llvm::sys::fs::directory_iterator LI(CudaLibDevicePath, EC), LE; !EC && LI != LE; LI = LI.increment(EC)) { StringRef FilePath = LI->path(); StringRef FileName = llvm::sys::path::filename(FilePath); // Process all bitcode filenames that look like libdevice.compute_XX.YY.bc const StringRef LibDeviceName = "libdevice."; if (!(FileName.startswith(LibDeviceName) && FileName.endswith(".bc"))) continue; StringRef GpuArch = FileName.slice( LibDeviceName.size(), FileName.find('.', LibDeviceName.size())); CudaLibDeviceMap[GpuArch] = FilePath.str(); // Insert map entries for specifc devices with this compute capability. if (GpuArch == "compute_20") { CudaLibDeviceMap["sm_20"] = FilePath; CudaLibDeviceMap["sm_21"] = FilePath; } else if (GpuArch == "compute_30") { CudaLibDeviceMap["sm_30"] = FilePath; CudaLibDeviceMap["sm_32"] = FilePath; } else if (GpuArch == "compute_35") { CudaLibDeviceMap["sm_35"] = FilePath; CudaLibDeviceMap["sm_37"] = FilePath; } } IsValid = true; break; } } void Generic_GCC::CudaInstallationDetector::print(raw_ostream &OS) const { if (isValid()) OS << "Found CUDA installation: " << CudaInstallPath << "\n"; } namespace { // Filter to remove Multilibs that don't exist as a suffix to Path class FilterNonExistent { StringRef Base; vfs::FileSystem &VFS; public: FilterNonExistent(StringRef Base, vfs::FileSystem &VFS) : Base(Base), VFS(VFS) {} bool operator()(const Multilib &M) { return !VFS.exists(Base + M.gccSuffix() + "/crtbegin.o"); } }; } // end anonymous namespace static void addMultilibFlag(bool Enabled, const char *const Flag, std::vector &Flags) { if (Enabled) Flags.push_back(std::string("+") + Flag); else Flags.push_back(std::string("-") + Flag); } static bool isMipsArch(llvm::Triple::ArchType Arch) { return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel || Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el; } static bool isMips32(llvm::Triple::ArchType Arch) { return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel; } static bool isMips64(llvm::Triple::ArchType Arch) { return Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el; } static bool isMipsEL(llvm::Triple::ArchType Arch) { return Arch == llvm::Triple::mipsel || Arch == llvm::Triple::mips64el; } static bool isMips16(const ArgList &Args) { Arg *A = Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16); return A && A->getOption().matches(options::OPT_mips16); } static bool isMicroMips(const ArgList &Args) { Arg *A = Args.getLastArg(options::OPT_mmicromips, options::OPT_mno_micromips); return A && A->getOption().matches(options::OPT_mmicromips); } namespace { struct DetectedMultilibs { /// The set of multilibs that the detected installation supports. MultilibSet Multilibs; /// The primary multilib appropriate for the given flags. Multilib SelectedMultilib; /// On Biarch systems, this corresponds to the default multilib when /// targeting the non-default multilib. Otherwise, it is empty. llvm::Optional BiarchSibling; }; } // end anonymous namespace static Multilib makeMultilib(StringRef commonSuffix) { return Multilib(commonSuffix, commonSuffix, commonSuffix); } static bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, DetectedMultilibs &Result) { // Some MIPS toolchains put libraries and object files compiled // using different options in to the sub-directoris which names // reflects the flags used for compilation. For example sysroot // directory might looks like the following examples: // // /usr // /lib <= crt*.o files compiled with '-mips32' // /mips16 // /usr // /lib <= crt*.o files compiled with '-mips16' // /el // /usr // /lib <= crt*.o files compiled with '-mips16 -EL' // // or // // /usr // /lib <= crt*.o files compiled with '-mips32r2' // /mips16 // /usr // /lib <= crt*.o files compiled with '-mips32r2 -mips16' // /mips32 // /usr // /lib <= crt*.o files compiled with '-mips32' FilterNonExistent NonExistent(Path, D.getVFS()); // Check for FSF toolchain multilibs MultilibSet FSFMipsMultilibs; { auto MArchMips32 = makeMultilib("/mips32") .flag("+m32") .flag("-m64") .flag("-mmicromips") .flag("+march=mips32"); auto MArchMicroMips = makeMultilib("/micromips") .flag("+m32") .flag("-m64") .flag("+mmicromips"); auto MArchMips64r2 = makeMultilib("/mips64r2") .flag("-m32") .flag("+m64") .flag("+march=mips64r2"); auto MArchMips64 = makeMultilib("/mips64").flag("-m32").flag("+m64").flag( "-march=mips64r2"); auto MArchDefault = makeMultilib("") .flag("+m32") .flag("-m64") .flag("-mmicromips") .flag("+march=mips32r2"); auto Mips16 = makeMultilib("/mips16").flag("+mips16"); auto UCLibc = makeMultilib("/uclibc").flag("+muclibc"); auto MAbi64 = makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); auto BigEndian = makeMultilib("").flag("+EB").flag("-EL"); auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); auto SoftFloat = makeMultilib("/sof").flag("+msoft-float"); auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); FSFMipsMultilibs = MultilibSet() .Either(MArchMips32, MArchMicroMips, MArchMips64r2, MArchMips64, MArchDefault) .Maybe(UCLibc) .Maybe(Mips16) .FilterOut("/mips64/mips16") .FilterOut("/mips64r2/mips16") .FilterOut("/micromips/mips16") .Maybe(MAbi64) .FilterOut("/micromips/64") .FilterOut("/mips32/64") .FilterOut("^/64") .FilterOut("/mips16/64") .Either(BigEndian, LittleEndian) .Maybe(SoftFloat) .Maybe(Nan2008) .FilterOut(".*sof/nan2008") .FilterOut(NonExistent) .setIncludeDirsCallback([](StringRef InstallDir, StringRef TripleStr, const Multilib &M) { std::vector Dirs; Dirs.push_back((InstallDir + "/include").str()); std::string SysRootInc = InstallDir.str() + "/../../../../sysroot"; if (StringRef(M.includeSuffix()).startswith("/uclibc")) Dirs.push_back(SysRootInc + "/uclibc/usr/include"); else Dirs.push_back(SysRootInc + "/usr/include"); return Dirs; }); } // Check for Musl toolchain multilibs MultilibSet MuslMipsMultilibs; { auto MArchMipsR2 = makeMultilib("") .osSuffix("/mips-r2-hard-musl") .flag("+EB") .flag("-EL") .flag("+march=mips32r2"); auto MArchMipselR2 = makeMultilib("/mipsel-r2-hard-musl") .flag("-EB") .flag("+EL") .flag("+march=mips32r2"); MuslMipsMultilibs = MultilibSet().Either(MArchMipsR2, MArchMipselR2); // Specify the callback that computes the include directories. MuslMipsMultilibs.setIncludeDirsCallback([]( StringRef InstallDir, StringRef TripleStr, const Multilib &M) { std::vector Dirs; Dirs.push_back( (InstallDir + "/../sysroot" + M.osSuffix() + "/usr/include").str()); return Dirs; }); } // Check for Code Sourcery toolchain multilibs MultilibSet CSMipsMultilibs; { auto MArchMips16 = makeMultilib("/mips16").flag("+m32").flag("+mips16"); auto MArchMicroMips = makeMultilib("/micromips").flag("+m32").flag("+mmicromips"); auto MArchDefault = makeMultilib("").flag("-mips16").flag("-mmicromips"); auto UCLibc = makeMultilib("/uclibc").flag("+muclibc"); auto SoftFloat = makeMultilib("/soft-float").flag("+msoft-float"); auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); auto DefaultFloat = makeMultilib("").flag("-msoft-float").flag("-mnan=2008"); auto BigEndian = makeMultilib("").flag("+EB").flag("-EL"); auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); // Note that this one's osSuffix is "" auto MAbi64 = makeMultilib("") .gccSuffix("/64") .includeSuffix("/64") .flag("+mabi=n64") .flag("-mabi=n32") .flag("-m32"); CSMipsMultilibs = MultilibSet() .Either(MArchMips16, MArchMicroMips, MArchDefault) .Maybe(UCLibc) .Either(SoftFloat, Nan2008, DefaultFloat) .FilterOut("/micromips/nan2008") .FilterOut("/mips16/nan2008") .Either(BigEndian, LittleEndian) .Maybe(MAbi64) .FilterOut("/mips16.*/64") .FilterOut("/micromips.*/64") .FilterOut(NonExistent) .setIncludeDirsCallback([](StringRef InstallDir, StringRef TripleStr, const Multilib &M) { std::vector Dirs; Dirs.push_back((InstallDir + "/include").str()); std::string SysRootInc = InstallDir.str() + "/../../../../" + TripleStr.str(); if (StringRef(M.includeSuffix()).startswith("/uclibc")) Dirs.push_back(SysRootInc + "/libc/uclibc/usr/include"); else Dirs.push_back(SysRootInc + "/libc/usr/include"); return Dirs; }); } MultilibSet AndroidMipsMultilibs = MultilibSet() .Maybe(Multilib("/mips-r2").flag("+march=mips32r2")) .Maybe(Multilib("/mips-r6").flag("+march=mips32r6")) .FilterOut(NonExistent); MultilibSet DebianMipsMultilibs; { Multilib MAbiN32 = Multilib().gccSuffix("/n32").includeSuffix("/n32").flag("+mabi=n32"); Multilib M64 = Multilib() .gccSuffix("/64") .includeSuffix("/64") .flag("+m64") .flag("-m32") .flag("-mabi=n32"); Multilib M32 = Multilib().flag("-m64").flag("+m32").flag("-mabi=n32"); DebianMipsMultilibs = MultilibSet().Either(M32, M64, MAbiN32).FilterOut(NonExistent); } MultilibSet ImgMultilibs; { auto Mips64r6 = makeMultilib("/mips64r6").flag("+m64").flag("-m32"); auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); auto MAbi64 = makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); ImgMultilibs = MultilibSet() .Maybe(Mips64r6) .Maybe(MAbi64) .Maybe(LittleEndian) .FilterOut(NonExistent) .setIncludeDirsCallback([](StringRef InstallDir, StringRef TripleStr, const Multilib &M) { std::vector Dirs; Dirs.push_back((InstallDir + "/include").str()); Dirs.push_back( (InstallDir + "/../../../../sysroot/usr/include").str()); return Dirs; }); } StringRef CPUName; StringRef ABIName; tools::mips::getMipsCPUAndABI(Args, TargetTriple, CPUName, ABIName); llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); Multilib::flags_list Flags; addMultilibFlag(isMips32(TargetArch), "m32", Flags); addMultilibFlag(isMips64(TargetArch), "m64", Flags); addMultilibFlag(isMips16(Args), "mips16", Flags); addMultilibFlag(CPUName == "mips32", "march=mips32", Flags); addMultilibFlag(CPUName == "mips32r2" || CPUName == "mips32r3" || CPUName == "mips32r5" || CPUName == "p5600", "march=mips32r2", Flags); addMultilibFlag(CPUName == "mips32r6", "march=mips32r6", Flags); addMultilibFlag(CPUName == "mips64", "march=mips64", Flags); addMultilibFlag(CPUName == "mips64r2" || CPUName == "mips64r3" || CPUName == "mips64r5" || CPUName == "octeon", "march=mips64r2", Flags); addMultilibFlag(isMicroMips(Args), "mmicromips", Flags); addMultilibFlag(tools::mips::isUCLibc(Args), "muclibc", Flags); addMultilibFlag(tools::mips::isNaN2008(Args, TargetTriple), "mnan=2008", Flags); addMultilibFlag(ABIName == "n32", "mabi=n32", Flags); addMultilibFlag(ABIName == "n64", "mabi=n64", Flags); addMultilibFlag(isSoftFloatABI(Args), "msoft-float", Flags); addMultilibFlag(!isSoftFloatABI(Args), "mhard-float", Flags); addMultilibFlag(isMipsEL(TargetArch), "EL", Flags); addMultilibFlag(!isMipsEL(TargetArch), "EB", Flags); if (TargetTriple.isAndroid()) { // Select Android toolchain. It's the only choice in that case. if (AndroidMipsMultilibs.select(Flags, Result.SelectedMultilib)) { Result.Multilibs = AndroidMipsMultilibs; return true; } return false; } if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies && TargetTriple.getOS() == llvm::Triple::Linux && TargetTriple.getEnvironment() == llvm::Triple::UnknownEnvironment) { if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilib)) { Result.Multilibs = MuslMipsMultilibs; return true; } return false; } if (TargetTriple.getVendor() == llvm::Triple::ImaginationTechnologies && TargetTriple.getOS() == llvm::Triple::Linux && TargetTriple.getEnvironment() == llvm::Triple::GNU) { // Select mips-img-linux-gnu toolchain. if (ImgMultilibs.select(Flags, Result.SelectedMultilib)) { Result.Multilibs = ImgMultilibs; return true; } return false; } // Sort candidates. Toolchain that best meets the directories goes first. // Then select the first toolchains matches command line flags. MultilibSet *candidates[] = {&DebianMipsMultilibs, &FSFMipsMultilibs, &CSMipsMultilibs}; std::sort( std::begin(candidates), std::end(candidates), [](MultilibSet *a, MultilibSet *b) { return a->size() > b->size(); }); for (const auto &candidate : candidates) { if (candidate->select(Flags, Result.SelectedMultilib)) { if (candidate == &DebianMipsMultilibs) Result.BiarchSibling = Multilib(); Result.Multilibs = *candidate; return true; } } { // Fallback to the regular toolchain-tree structure. Multilib Default; Result.Multilibs.push_back(Default); Result.Multilibs.FilterOut(NonExistent); if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) { Result.BiarchSibling = Multilib(); return true; } } return false; } static bool findBiarchMultilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, bool NeedsBiarchSuffix, DetectedMultilibs &Result) { // Some versions of SUSE and Fedora on ppc64 put 32-bit libs // in what would normally be GCCInstallPath and put the 64-bit // libs in a subdirectory named 64. The simple logic we follow is that // *if* there is a subdirectory of the right name with crtbegin.o in it, // we use that. If not, and if not a biarch triple alias, we look for // crtbegin.o without the subdirectory. Multilib Default; Multilib Alt64 = Multilib() .gccSuffix("/64") .includeSuffix("/64") .flag("-m32") .flag("+m64") .flag("-mx32"); Multilib Alt32 = Multilib() .gccSuffix("/32") .includeSuffix("/32") .flag("+m32") .flag("-m64") .flag("-mx32"); Multilib Altx32 = Multilib() .gccSuffix("/x32") .includeSuffix("/x32") .flag("-m32") .flag("-m64") .flag("+mx32"); FilterNonExistent NonExistent(Path, D.getVFS()); // Determine default multilib from: 32, 64, x32 // Also handle cases such as 64 on 32, 32 on 64, etc. enum { UNKNOWN, WANT32, WANT64, WANTX32 } Want = UNKNOWN; const bool IsX32 = TargetTriple.getEnvironment() == llvm::Triple::GNUX32; if (TargetTriple.isArch32Bit() && !NonExistent(Alt32)) Want = WANT64; else if (TargetTriple.isArch64Bit() && IsX32 && !NonExistent(Altx32)) Want = WANT64; else if (TargetTriple.isArch64Bit() && !IsX32 && !NonExistent(Alt64)) Want = WANT32; else { if (TargetTriple.isArch32Bit()) Want = NeedsBiarchSuffix ? WANT64 : WANT32; else if (IsX32) Want = NeedsBiarchSuffix ? WANT64 : WANTX32; else Want = NeedsBiarchSuffix ? WANT32 : WANT64; } if (Want == WANT32) Default.flag("+m32").flag("-m64").flag("-mx32"); else if (Want == WANT64) Default.flag("-m32").flag("+m64").flag("-mx32"); else if (Want == WANTX32) Default.flag("-m32").flag("-m64").flag("+mx32"); else return false; Result.Multilibs.push_back(Default); Result.Multilibs.push_back(Alt64); Result.Multilibs.push_back(Alt32); Result.Multilibs.push_back(Altx32); Result.Multilibs.FilterOut(NonExistent); Multilib::flags_list Flags; addMultilibFlag(TargetTriple.isArch64Bit() && !IsX32, "m64", Flags); addMultilibFlag(TargetTriple.isArch32Bit(), "m32", Flags); addMultilibFlag(TargetTriple.isArch64Bit() && IsX32, "mx32", Flags); if (!Result.Multilibs.select(Flags, Result.SelectedMultilib)) return false; if (Result.SelectedMultilib == Alt64 || Result.SelectedMultilib == Alt32 || Result.SelectedMultilib == Altx32) Result.BiarchSibling = Default; return true; } void Generic_GCC::GCCInstallationDetector::scanLibDirForGCCTripleSolaris( const llvm::Triple &TargetArch, const llvm::opt::ArgList &Args, const std::string &LibDir, StringRef CandidateTriple, bool NeedsBiarchSuffix) { // Solaris is a special case. The GCC installation is under // /usr/gcc/./lib/gcc//../, so we // need to iterate twice. std::error_code EC; for (vfs::directory_iterator LI = D.getVFS().dir_begin(LibDir, EC), LE; !EC && LI != LE; LI = LI.increment(EC)) { StringRef VersionText = llvm::sys::path::filename(LI->getName()); GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); if (CandidateVersion.Major != -1) // Filter obviously bad entries. if (!CandidateGCCInstallPaths.insert(LI->getName()).second) continue; // Saw this path before; no need to look at it again. if (CandidateVersion.isOlderThan(4, 1, 1)) continue; if (CandidateVersion <= Version) continue; GCCInstallPath = LibDir + "/" + VersionText.str() + "/lib/gcc/" + CandidateTriple.str(); if (!D.getVFS().exists(GCCInstallPath)) continue; // If we make it here there has to be at least one GCC version, let's just // use the latest one. std::error_code EEC; for (vfs::directory_iterator LLI = D.getVFS().dir_begin(GCCInstallPath, EEC), LLE; !EEC && LLI != LLE; LLI = LLI.increment(EEC)) { StringRef SubVersionText = llvm::sys::path::filename(LLI->getName()); GCCVersion CandidateSubVersion = GCCVersion::Parse(SubVersionText); if (CandidateSubVersion > Version) Version = CandidateSubVersion; } GCCTriple.setTriple(CandidateTriple); GCCInstallPath += "/" + Version.Text; GCCParentLibPath = GCCInstallPath + "/../../../../"; IsValid = true; } } void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( const llvm::Triple &TargetTriple, const ArgList &Args, const std::string &LibDir, StringRef CandidateTriple, bool NeedsBiarchSuffix) { llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); // There are various different suffixes involving the triple we // check for. We also record what is necessary to walk from each back // up to the lib directory. Specifically, the number of "up" steps // in the second half of each row is 1 + the number of path separators // in the first half. const std::string LibAndInstallSuffixes[][2] = { {"/gcc/" + CandidateTriple.str(), "/../../.."}, // Debian puts cross-compilers in gcc-cross {"/gcc-cross/" + CandidateTriple.str(), "/../../.."}, {"/" + CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), "/../../../.."}, // The Freescale PPC SDK has the gcc libraries in // /usr/lib//x.y.z so have a look there as well. {"/" + CandidateTriple.str(), "/../.."}, // Ubuntu has a strange mis-matched pair of triples that this happens to // match. // FIXME: It may be worthwhile to generalize this and look for a second // triple. {"/i386-linux-gnu/gcc/" + CandidateTriple.str(), "/../../../.."}}; if (TargetTriple.getOS() == llvm::Triple::Solaris) { scanLibDirForGCCTripleSolaris(TargetTriple, Args, LibDir, CandidateTriple, NeedsBiarchSuffix); return; } // Only look at the final, weird Ubuntu suffix for i386-linux-gnu. const unsigned NumLibSuffixes = (llvm::array_lengthof(LibAndInstallSuffixes) - (TargetArch != llvm::Triple::x86)); for (unsigned i = 0; i < NumLibSuffixes; ++i) { StringRef LibSuffix = LibAndInstallSuffixes[i][0]; std::error_code EC; for (vfs::directory_iterator LI = D.getVFS().dir_begin(LibDir + LibSuffix, EC), LE; !EC && LI != LE; LI = LI.increment(EC)) { StringRef VersionText = llvm::sys::path::filename(LI->getName()); GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); if (CandidateVersion.Major != -1) // Filter obviously bad entries. if (!CandidateGCCInstallPaths.insert(LI->getName()).second) continue; // Saw this path before; no need to look at it again. if (CandidateVersion.isOlderThan(4, 1, 1)) continue; if (CandidateVersion <= Version) continue; DetectedMultilibs Detected; // Debian mips multilibs behave more like the rest of the biarch ones, // so handle them there if (isMipsArch(TargetArch)) { if (!findMIPSMultilibs(D, TargetTriple, LI->getName(), Args, Detected)) continue; } else if (!findBiarchMultilibs(D, TargetTriple, LI->getName(), Args, NeedsBiarchSuffix, Detected)) { continue; } Multilibs = Detected.Multilibs; SelectedMultilib = Detected.SelectedMultilib; BiarchSibling = Detected.BiarchSibling; Version = CandidateVersion; GCCTriple.setTriple(CandidateTriple); // FIXME: We hack together the directory name here instead of // using LI to ensure stable path separators across Windows and // Linux. GCCInstallPath = LibDir + LibAndInstallSuffixes[i][0] + "/" + VersionText.str(); GCCParentLibPath = GCCInstallPath + LibAndInstallSuffixes[i][1]; IsValid = true; } } } Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args), GCCInstallation(D), CudaInstallation(D) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); } Generic_GCC::~Generic_GCC() {} Tool *Generic_GCC::getTool(Action::ActionClass AC) const { switch (AC) { case Action::PreprocessJobClass: if (!Preprocess) Preprocess.reset(new tools::gcc::Preprocessor(*this)); return Preprocess.get(); case Action::CompileJobClass: if (!Compile) Compile.reset(new tools::gcc::Compiler(*this)); return Compile.get(); default: return ToolChain::getTool(AC); } } Tool *Generic_GCC::buildAssembler() const { return new tools::gnutools::Assembler(*this); } Tool *Generic_GCC::buildLinker() const { return new tools::gcc::Linker(*this); } void Generic_GCC::printVerboseInfo(raw_ostream &OS) const { // Print the information about how we detected the GCC installation. GCCInstallation.print(OS); CudaInstallation.print(OS); } bool Generic_GCC::IsUnwindTablesDefault() const { return getArch() == llvm::Triple::x86_64; } bool Generic_GCC::isPICDefault() const { return getArch() == llvm::Triple::x86_64 && getTriple().isOSWindows(); } bool Generic_GCC::isPIEDefault() const { return false; } bool Generic_GCC::isPICDefaultForced() const { return getArch() == llvm::Triple::x86_64 && getTriple().isOSWindows(); } bool Generic_GCC::IsIntegratedAssemblerDefault() const { switch (getTriple().getArch()) { case llvm::Triple::x86: case llvm::Triple::x86_64: case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::bpfel: case llvm::Triple::bpfeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: case llvm::Triple::systemz: return true; default: return false; } } /// \brief Helper to add the variant paths of a libstdc++ installation. bool Generic_GCC::addLibStdCXXIncludePaths( Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple, StringRef TargetMultiarchTriple, Twine IncludeSuffix, const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (!getVFS().exists(Base + Suffix)) return false; addSystemInclude(DriverArgs, CC1Args, Base + Suffix); // The vanilla GCC layout of libstdc++ headers uses a triple subdirectory. If // that path exists or we have neither a GCC nor target multiarch triple, use // this vanilla search path. if ((GCCMultiarchTriple.empty() && TargetMultiarchTriple.empty()) || getVFS().exists(Base + Suffix + "/" + GCCTriple + IncludeSuffix)) { addSystemInclude(DriverArgs, CC1Args, Base + Suffix + "/" + GCCTriple + IncludeSuffix); } else { // Otherwise try to use multiarch naming schemes which have normalized the // triples and put the triple before the suffix. // // GCC surprisingly uses *both* the GCC triple with a multilib suffix and // the target triple, so we support that here. addSystemInclude(DriverArgs, CC1Args, Base + "/" + GCCMultiarchTriple + Suffix + IncludeSuffix); addSystemInclude(DriverArgs, CC1Args, Base + "/" + TargetMultiarchTriple + Suffix); } addSystemInclude(DriverArgs, CC1Args, Base + Suffix + "/backward"); return true; } void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args) const { const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion(); bool UseInitArrayDefault = getTriple().getArch() == llvm::Triple::aarch64 || getTriple().getArch() == llvm::Triple::aarch64_be || (getTriple().getOS() == llvm::Triple::Linux && (!V.isOlderThan(4, 7, 0) || getTriple().isAndroid())) || getTriple().getOS() == llvm::Triple::NaCl || (getTriple().getVendor() == llvm::Triple::MipsTechnologies && !getTriple().hasEnvironment()); if (DriverArgs.hasFlag(options::OPT_fuse_init_array, options::OPT_fno_use_init_array, UseInitArrayDefault)) CC1Args.push_back("-fuse-init-array"); } /// Mips Toolchain MipsLLVMToolChain::MipsLLVMToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Linux(D, Triple, Args) { // Select the correct multilib according to the given arguments. DetectedMultilibs Result; findMIPSMultilibs(D, Triple, "", Args, Result); Multilibs = Result.Multilibs; SelectedMultilib = Result.SelectedMultilib; // Find out the library suffix based on the ABI. LibSuffix = tools::mips::getMipsABILibSuffix(Args, Triple); getFilePaths().clear(); getFilePaths().push_back(computeSysRoot() + "/usr/lib" + LibSuffix); // Use LLD by default. DefaultLinker = "lld"; } void MipsLLVMToolChain::AddClangSystemIncludeArgs( const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdinc)) return; const Driver &D = getDriver(); if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { SmallString<128> P(D.ResourceDir); llvm::sys::path::append(P, "include"); addSystemInclude(DriverArgs, CC1Args, P); } if (DriverArgs.hasArg(options::OPT_nostdlibinc)) return; const auto &Callback = Multilibs.includeDirsCallback(); if (Callback) { const auto IncludePaths = Callback(D.getInstalledDir(), getTripleString(), SelectedMultilib); for (const auto &Path : IncludePaths) addExternCSystemIncludeIfExists(DriverArgs, CC1Args, Path); } } Tool *MipsLLVMToolChain::buildLinker() const { return new tools::gnutools::Linker(*this); } std::string MipsLLVMToolChain::computeSysRoot() const { if (!getDriver().SysRoot.empty()) return getDriver().SysRoot + SelectedMultilib.osSuffix(); const std::string InstalledDir(getDriver().getInstalledDir()); std::string SysRootPath = InstalledDir + "/../sysroot" + SelectedMultilib.osSuffix(); if (llvm::sys::fs::exists(SysRootPath)) return SysRootPath; return std::string(); } ToolChain::CXXStdlibType MipsLLVMToolChain::GetCXXStdlibType(const ArgList &Args) const { Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); if (A) { StringRef Value = A->getValue(); if (Value != "libc++") getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); } return ToolChain::CST_Libcxx; } void MipsLLVMToolChain::AddClangCXXStdlibIncludeArgs( const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) return; assert((GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) && "Only -lc++ (aka libcxx) is suported in this toolchain."); const auto &Callback = Multilibs.includeDirsCallback(); if (Callback) { const auto IncludePaths = Callback(getDriver().getInstalledDir(), getTripleString(), SelectedMultilib); for (const auto &Path : IncludePaths) { if (llvm::sys::fs::exists(Path + "/c++/v1")) { addSystemInclude(DriverArgs, CC1Args, Path + "/c++/v1"); break; } } } } void MipsLLVMToolChain::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { assert((GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) && "Only -lc++ (aka libxx) is suported in this toolchain."); CmdArgs.push_back("-lc++"); CmdArgs.push_back("-lc++abi"); CmdArgs.push_back("-lunwind"); } std::string MipsLLVMToolChain::getCompilerRT(const ArgList &Args, StringRef Component, bool Shared) const { SmallString<128> Path(getDriver().ResourceDir); llvm::sys::path::append(Path, SelectedMultilib.osSuffix(), "lib" + LibSuffix, getOS()); llvm::sys::path::append(Path, Twine("libclang_rt." + Component + "-" + "mips" + (Shared ? ".so" : ".a"))); return Path.str(); } /// Hexagon Toolchain std::string HexagonToolChain::getHexagonTargetDir( const std::string &InstalledDir, const SmallVectorImpl &PrefixDirs) const { std::string InstallRelDir; const Driver &D = getDriver(); // Locate the rest of the toolchain ... for (auto &I : PrefixDirs) if (D.getVFS().exists(I)) return I; if (getVFS().exists(InstallRelDir = InstalledDir + "/../target")) return InstallRelDir; std::string PrefixRelDir = std::string(LLVM_PREFIX) + "/target"; if (getVFS().exists(PrefixRelDir)) return PrefixRelDir; return InstallRelDir; } Optional HexagonToolChain::getSmallDataThreshold( const ArgList &Args) { StringRef Gn = ""; if (Arg *A = Args.getLastArg(options::OPT_G, options::OPT_G_EQ, options::OPT_msmall_data_threshold_EQ)) { Gn = A->getValue(); } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic, options::OPT_fPIC)) { Gn = "0"; } unsigned G; if (!Gn.getAsInteger(10, G)) return G; return None; } void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args, ToolChain::path_list &LibPaths) const { const Driver &D = getDriver(); //---------------------------------------------------------------------------- // -L Args //---------------------------------------------------------------------------- for (Arg *A : Args.filtered(options::OPT_L)) for (const char *Value : A->getValues()) LibPaths.push_back(Value); //---------------------------------------------------------------------------- // Other standard paths //---------------------------------------------------------------------------- std::vector RootDirs; std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(), std::back_inserter(RootDirs)); std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), D.PrefixDirs); if (std::find(RootDirs.begin(), RootDirs.end(), TargetDir) == RootDirs.end()) RootDirs.push_back(TargetDir); bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC); // Assume G0 with -shared. bool HasG0 = Args.hasArg(options::OPT_shared); if (auto G = getSmallDataThreshold(Args)) HasG0 = G.getValue() == 0; const std::string CpuVer = GetTargetCPUVersion(Args).str(); for (auto &Dir : RootDirs) { std::string LibDir = Dir + "/hexagon/lib"; std::string LibDirCpu = LibDir + '/' + CpuVer; if (HasG0) { if (HasPIC) LibPaths.push_back(LibDirCpu + "/G0/pic"); LibPaths.push_back(LibDirCpu + "/G0"); } LibPaths.push_back(LibDirCpu); LibPaths.push_back(LibDir); } } HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args) : Linux(D, Triple, Args) { const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), D.PrefixDirs); // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to // program paths const std::string BinDir(TargetDir + "/bin"); if (D.getVFS().exists(BinDir)) getProgramPaths().push_back(BinDir); ToolChain::path_list &LibPaths = getFilePaths(); // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets // 'elf' OS type, so the Linux paths are not appropriate. When we actually // support 'linux' we'll need to fix this up LibPaths.clear(); getHexagonLibraryPaths(Args, LibPaths); } HexagonToolChain::~HexagonToolChain() {} Tool *HexagonToolChain::buildAssembler() const { return new tools::hexagon::Assembler(*this); } Tool *HexagonToolChain::buildLinker() const { return new tools::hexagon::Linker(*this); } void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdinc) || DriverArgs.hasArg(options::OPT_nostdlibinc)) return; const Driver &D = getDriver(); std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), D.PrefixDirs); addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include"); } void HexagonToolChain::AddClangCXXStdlibIncludeArgs( const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) return; const Driver &D = getDriver(); std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs); addSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include/c++"); } ToolChain::CXXStdlibType HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const { Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); if (!A) return ToolChain::CST_Libstdcxx; StringRef Value = A->getValue(); if (Value != "libstdc++") getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); return ToolChain::CST_Libstdcxx; } // // Returns the default CPU for Hexagon. This is the default compilation target // if no Hexagon processor is selected at the command-line. // const StringRef HexagonToolChain::GetDefaultCPU() { return "hexagonv60"; } const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) { Arg *CpuArg = nullptr; if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ, options::OPT_march_EQ)) CpuArg = A; StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU(); if (CPU.startswith("hexagon")) return CPU.substr(sizeof("hexagon") - 1); return CPU; } // End Hexagon /// AMDGPU Toolchain AMDGPUToolChain::AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { } Tool *AMDGPUToolChain::buildLinker() const { return new tools::amdgpu::Linker(*this); } // End AMDGPU /// NaCl Toolchain NaClToolChain::NaClToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { // Remove paths added by Generic_GCC. NaCl Toolchain cannot use the // default paths, and must instead only use the paths provided // with this toolchain based on architecture. path_list &file_paths = getFilePaths(); path_list &prog_paths = getProgramPaths(); file_paths.clear(); prog_paths.clear(); // Path for library files (libc.a, ...) std::string FilePath(getDriver().Dir + "/../"); // Path for tools (clang, ld, etc..) std::string ProgPath(getDriver().Dir + "/../"); // Path for toolchain libraries (libgcc.a, ...) std::string ToolPath(getDriver().ResourceDir + "/lib/"); switch (Triple.getArch()) { case llvm::Triple::x86: file_paths.push_back(FilePath + "x86_64-nacl/lib32"); file_paths.push_back(FilePath + "i686-nacl/usr/lib"); prog_paths.push_back(ProgPath + "x86_64-nacl/bin"); file_paths.push_back(ToolPath + "i686-nacl"); break; case llvm::Triple::x86_64: file_paths.push_back(FilePath + "x86_64-nacl/lib"); file_paths.push_back(FilePath + "x86_64-nacl/usr/lib"); prog_paths.push_back(ProgPath + "x86_64-nacl/bin"); file_paths.push_back(ToolPath + "x86_64-nacl"); break; case llvm::Triple::arm: file_paths.push_back(FilePath + "arm-nacl/lib"); file_paths.push_back(FilePath + "arm-nacl/usr/lib"); prog_paths.push_back(ProgPath + "arm-nacl/bin"); file_paths.push_back(ToolPath + "arm-nacl"); break; case llvm::Triple::mipsel: file_paths.push_back(FilePath + "mipsel-nacl/lib"); file_paths.push_back(FilePath + "mipsel-nacl/usr/lib"); prog_paths.push_back(ProgPath + "bin"); file_paths.push_back(ToolPath + "mipsel-nacl"); break; default: break; } NaClArmMacrosPath = GetFilePath("nacl-arm-macros.s"); } void NaClToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { const Driver &D = getDriver(); if (DriverArgs.hasArg(options::OPT_nostdinc)) return; if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { SmallString<128> P(D.ResourceDir); llvm::sys::path::append(P, "include"); addSystemInclude(DriverArgs, CC1Args, P.str()); } if (DriverArgs.hasArg(options::OPT_nostdlibinc)) return; SmallString<128> P(D.Dir + "/../"); switch (getTriple().getArch()) { case llvm::Triple::x86: // x86 is special because multilib style uses x86_64-nacl/include for libc // headers but the SDK wants i686-nacl/usr/include. The other architectures // have the same substring. llvm::sys::path::append(P, "i686-nacl/usr/include"); addSystemInclude(DriverArgs, CC1Args, P.str()); llvm::sys::path::remove_filename(P); llvm::sys::path::remove_filename(P); llvm::sys::path::remove_filename(P); llvm::sys::path::append(P, "x86_64-nacl/include"); addSystemInclude(DriverArgs, CC1Args, P.str()); return; case llvm::Triple::arm: llvm::sys::path::append(P, "arm-nacl/usr/include"); break; case llvm::Triple::x86_64: llvm::sys::path::append(P, "x86_64-nacl/usr/include"); break; case llvm::Triple::mipsel: llvm::sys::path::append(P, "mipsel-nacl/usr/include"); break; default: return; } addSystemInclude(DriverArgs, CC1Args, P.str()); llvm::sys::path::remove_filename(P); llvm::sys::path::remove_filename(P); llvm::sys::path::append(P, "include"); addSystemInclude(DriverArgs, CC1Args, P.str()); } void NaClToolChain::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Check for -stdlib= flags. We only support libc++ but this consumes the arg // if the value is libc++, and emits an error for other values. GetCXXStdlibType(Args); CmdArgs.push_back("-lc++"); } void NaClToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { const Driver &D = getDriver(); if (DriverArgs.hasArg(options::OPT_nostdlibinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) return; // Check for -stdlib= flags. We only support libc++ but this consumes the arg // if the value is libc++, and emits an error for other values. GetCXXStdlibType(DriverArgs); SmallString<128> P(D.Dir + "/../"); switch (getTriple().getArch()) { case llvm::Triple::arm: llvm::sys::path::append(P, "arm-nacl/include/c++/v1"); addSystemInclude(DriverArgs, CC1Args, P.str()); break; case llvm::Triple::x86: llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1"); addSystemInclude(DriverArgs, CC1Args, P.str()); break; case llvm::Triple::x86_64: llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1"); addSystemInclude(DriverArgs, CC1Args, P.str()); break; case llvm::Triple::mipsel: llvm::sys::path::append(P, "mipsel-nacl/include/c++/v1"); addSystemInclude(DriverArgs, CC1Args, P.str()); break; default: break; } } ToolChain::CXXStdlibType NaClToolChain::GetCXXStdlibType(const ArgList &Args) const { if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { StringRef Value = A->getValue(); if (Value == "libc++") return ToolChain::CST_Libcxx; getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); } return ToolChain::CST_Libcxx; } std::string NaClToolChain::ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const { llvm::Triple TheTriple(ComputeLLVMTriple(Args, InputType)); if (TheTriple.getArch() == llvm::Triple::arm && TheTriple.getEnvironment() == llvm::Triple::UnknownEnvironment) TheTriple.setEnvironment(llvm::Triple::GNUEABIHF); return TheTriple.getTriple(); } Tool *NaClToolChain::buildLinker() const { return new tools::nacltools::Linker(*this); } Tool *NaClToolChain::buildAssembler() const { if (getTriple().getArch() == llvm::Triple::arm) return new tools::nacltools::AssemblerARM(*this); return new tools::gnutools::Assembler(*this); } // End NaCl /// TCEToolChain - A tool chain using the llvm bitcode tools to perform /// all subcommands. See http://tce.cs.tut.fi for our peculiar target. /// Currently does not support anything else but compilation. TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args) { // Path mangling to find libexec std::string Path(getDriver().Dir); Path += "/../libexec"; getProgramPaths().push_back(Path); } TCEToolChain::~TCEToolChain() {} bool TCEToolChain::IsMathErrnoDefault() const { return true; } bool TCEToolChain::isPICDefault() const { return false; } bool TCEToolChain::isPIEDefault() const { return false; } bool TCEToolChain::isPICDefaultForced() const { return false; } // CloudABI - CloudABI tool chain which can call ld(1) directly. CloudABI::CloudABI(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { SmallString<128> P(getDriver().Dir); llvm::sys::path::append(P, "..", getTriple().str(), "lib"); getFilePaths().push_back(P.str()); } void CloudABI::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc) && DriverArgs.hasArg(options::OPT_nostdincxx)) return; SmallString<128> P(getDriver().Dir); llvm::sys::path::append(P, "..", getTriple().str(), "include/c++/v1"); addSystemInclude(DriverArgs, CC1Args, P.str()); } void CloudABI::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CmdArgs.push_back("-lc++"); CmdArgs.push_back("-lc++abi"); CmdArgs.push_back("-lunwind"); } Tool *CloudABI::buildLinker() const { return new tools::cloudabi::Linker(*this); } /// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly. OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); } Tool *OpenBSD::buildAssembler() const { return new tools::openbsd::Assembler(*this); } Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); } /// Bitrig - Bitrig tool chain which can call as(1) and ld(1) directly. Bitrig::Bitrig(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); } Tool *Bitrig::buildAssembler() const { return new tools::bitrig::Assembler(*this); } Tool *Bitrig::buildLinker() const { return new tools::bitrig::Linker(*this); } ToolChain::CXXStdlibType Bitrig::GetCXXStdlibType(const ArgList &Args) const { if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { StringRef Value = A->getValue(); if (Value == "libstdc++") return ToolChain::CST_Libstdcxx; if (Value == "libc++") return ToolChain::CST_Libcxx; getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); } return ToolChain::CST_Libcxx; } void Bitrig::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) return; switch (GetCXXStdlibType(DriverArgs)) { case ToolChain::CST_Libcxx: addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/include/c++/v1"); break; case ToolChain::CST_Libstdcxx: addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/include/c++/stdc++"); addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/include/c++/stdc++/backward"); StringRef Triple = getTriple().str(); if (Triple.startswith("amd64")) addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/include/c++/stdc++/x86_64" + Triple.substr(5)); else addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/include/c++/stdc++/" + Triple); break; } } void Bitrig::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { switch (GetCXXStdlibType(Args)) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); CmdArgs.push_back("-lc++abi"); CmdArgs.push_back("-lpthread"); break; case ToolChain::CST_Libstdcxx: CmdArgs.push_back("-lstdc++"); break; } } /// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly. FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { // When targeting 32-bit platforms, look for '/usr/lib32/crt1.o' and fall // back to '/usr/lib' if it doesn't exist. if ((Triple.getArch() == llvm::Triple::x86 || Triple.getArch() == llvm::Triple::ppc) && D.getVFS().exists(getDriver().SysRoot + "/usr/lib32/crt1.o")) getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32"); else getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); } ToolChain::CXXStdlibType FreeBSD::GetCXXStdlibType(const ArgList &Args) const { if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { StringRef Value = A->getValue(); if (Value == "libstdc++") return ToolChain::CST_Libstdcxx; if (Value == "libc++") return ToolChain::CST_Libcxx; getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); } if (getTriple().getOSMajorVersion() >= 10) return ToolChain::CST_Libcxx; return ToolChain::CST_Libstdcxx; } void FreeBSD::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) return; switch (GetCXXStdlibType(DriverArgs)) { case ToolChain::CST_Libcxx: addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/include/c++/v1"); break; case ToolChain::CST_Libstdcxx: addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/include/c++/4.2"); addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/include/c++/4.2/backward"); break; } } +void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + CXXStdlibType Type = GetCXXStdlibType(Args); + bool Profiling = Args.hasArg(options::OPT_pg); + + switch (Type) { + case ToolChain::CST_Libcxx: + CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); + break; + + case ToolChain::CST_Libstdcxx: + CmdArgs.push_back(Profiling ? "-lstdc++_p" : "-lstdc++"); + break; + } +} + Tool *FreeBSD::buildAssembler() const { return new tools::freebsd::Assembler(*this); } Tool *FreeBSD::buildLinker() const { return new tools::freebsd::Linker(*this); } bool FreeBSD::UseSjLjExceptions(const ArgList &Args) const { // FreeBSD uses SjLj exceptions on ARM oabi. switch (getTriple().getEnvironment()) { case llvm::Triple::GNUEABIHF: case llvm::Triple::GNUEABI: case llvm::Triple::EABI: return false; default: return (getTriple().getArch() == llvm::Triple::arm || getTriple().getArch() == llvm::Triple::thumb); } } bool FreeBSD::HasNativeLLVMSupport() const { return true; } bool FreeBSD::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } SanitizerMask FreeBSD::getSupportedSanitizers() const { const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; const bool IsMIPS64 = getTriple().getArch() == llvm::Triple::mips64 || getTriple().getArch() == llvm::Triple::mips64el; SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; Res |= SanitizerKind::Vptr; if (IsX86_64 || IsMIPS64) { Res |= SanitizerKind::Leak; Res |= SanitizerKind::Thread; } if (IsX86 || IsX86_64) { Res |= SanitizerKind::SafeStack; } return Res; } /// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly. NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { if (getDriver().UseStdLib) { // When targeting a 32-bit platform, try the special directory used on // 64-bit hosts, and only fall back to the main library directory if that // doesn't work. // FIXME: It'd be nicer to test if this directory exists, but I'm not sure // what all logic is needed to emulate the '=' prefix here. switch (Triple.getArch()) { case llvm::Triple::x86: getFilePaths().push_back("=/usr/lib/i386"); break; case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: switch (Triple.getEnvironment()) { case llvm::Triple::EABI: case llvm::Triple::GNUEABI: getFilePaths().push_back("=/usr/lib/eabi"); break; case llvm::Triple::EABIHF: case llvm::Triple::GNUEABIHF: getFilePaths().push_back("=/usr/lib/eabihf"); break; default: getFilePaths().push_back("=/usr/lib/oabi"); break; } break; case llvm::Triple::mips64: case llvm::Triple::mips64el: if (tools::mips::hasMipsAbiArg(Args, "o32")) getFilePaths().push_back("=/usr/lib/o32"); else if (tools::mips::hasMipsAbiArg(Args, "64")) getFilePaths().push_back("=/usr/lib/64"); break; case llvm::Triple::ppc: getFilePaths().push_back("=/usr/lib/powerpc"); break; case llvm::Triple::sparc: getFilePaths().push_back("=/usr/lib/sparc"); break; default: break; } getFilePaths().push_back("=/usr/lib"); } } Tool *NetBSD::buildAssembler() const { return new tools::netbsd::Assembler(*this); } Tool *NetBSD::buildLinker() const { return new tools::netbsd::Linker(*this); } ToolChain::CXXStdlibType NetBSD::GetCXXStdlibType(const ArgList &Args) const { if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { StringRef Value = A->getValue(); if (Value == "libstdc++") return ToolChain::CST_Libstdcxx; if (Value == "libc++") return ToolChain::CST_Libcxx; getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); } unsigned Major, Minor, Micro; getTriple().getOSVersion(Major, Minor, Micro); if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 49) || Major == 0) { switch (getArch()) { case llvm::Triple::aarch64: case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: case llvm::Triple::sparc: case llvm::Triple::sparcv9: case llvm::Triple::x86: case llvm::Triple::x86_64: return ToolChain::CST_Libcxx; default: break; } } return ToolChain::CST_Libstdcxx; } void NetBSD::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) return; switch (GetCXXStdlibType(DriverArgs)) { case ToolChain::CST_Libcxx: addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/include/c++/"); break; case ToolChain::CST_Libstdcxx: addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/include/g++"); addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/include/g++/backward"); break; } } /// Minix - Minix tool chain which can call as(1) and ld(1) directly. Minix::Minix(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); } Tool *Minix::buildAssembler() const { return new tools::minix::Assembler(*this); } Tool *Minix::buildLinker() const { return new tools::minix::Linker(*this); } static void addPathIfExists(const Driver &D, const Twine &Path, ToolChain::path_list &Paths) { if (D.getVFS().exists(Path)) Paths.push_back(Path.str()); } /// Solaris - Solaris tool chain which can call as(1) and ld(1) directly. Solaris::Solaris(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_GCC(D, Triple, Args) { GCCInstallation.init(Triple, Args); path_list &Paths = getFilePaths(); if (GCCInstallation.isValid()) addPathIfExists(D, GCCInstallation.getInstallPath(), Paths); addPathIfExists(D, getDriver().getInstalledDir(), Paths); if (getDriver().getInstalledDir() != getDriver().Dir) addPathIfExists(D, getDriver().Dir, Paths); addPathIfExists(D, getDriver().SysRoot + getDriver().Dir + "/../lib", Paths); std::string LibPath = "/usr/lib/"; switch (Triple.getArch()) { case llvm::Triple::x86: case llvm::Triple::sparc: break; case llvm::Triple::x86_64: LibPath += "amd64/"; break; case llvm::Triple::sparcv9: LibPath += "sparcv9/"; break; default: llvm_unreachable("Unsupported architecture"); } addPathIfExists(D, getDriver().SysRoot + LibPath, Paths); } Tool *Solaris::buildAssembler() const { return new tools::solaris::Assembler(*this); } Tool *Solaris::buildLinker() const { return new tools::solaris::Linker(*this); } void Solaris::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) return; // Include the support directory for things like xlocale and fudged system // headers. addSystemInclude(DriverArgs, CC1Args, "/usr/include/c++/v1/support/solaris"); if (GCCInstallation.isValid()) { GCCVersion Version = GCCInstallation.getVersion(); addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/gcc/" + Version.MajorStr + "." + Version.MinorStr + "/include/c++/" + Version.Text); addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/gcc/" + Version.MajorStr + "." + Version.MinorStr + "/include/c++/" + Version.Text + "/" + GCCInstallation.getTriple().str()); } } /// Distribution (very bare-bones at the moment). enum Distro { // NB: Releases of a particular Linux distro should be kept together // in this enum, because some tests are done by integer comparison against // the first and last known member in the family, e.g. IsRedHat(). ArchLinux, DebianLenny, DebianSqueeze, DebianWheezy, DebianJessie, DebianStretch, Exherbo, RHEL4, RHEL5, RHEL6, RHEL7, Fedora, OpenSUSE, UbuntuHardy, UbuntuIntrepid, UbuntuJaunty, UbuntuKarmic, UbuntuLucid, UbuntuMaverick, UbuntuNatty, UbuntuOneiric, UbuntuPrecise, UbuntuQuantal, UbuntuRaring, UbuntuSaucy, UbuntuTrusty, UbuntuUtopic, UbuntuVivid, UbuntuWily, UbuntuXenial, UnknownDistro }; static bool IsRedhat(enum Distro Distro) { return Distro == Fedora || (Distro >= RHEL4 && Distro <= RHEL7); } static bool IsOpenSUSE(enum Distro Distro) { return Distro == OpenSUSE; } static bool IsDebian(enum Distro Distro) { return Distro >= DebianLenny && Distro <= DebianStretch; } static bool IsUbuntu(enum Distro Distro) { return Distro >= UbuntuHardy && Distro <= UbuntuXenial; } static Distro DetectDistro(const Driver &D, llvm::Triple::ArchType Arch) { llvm::ErrorOr> File = llvm::MemoryBuffer::getFile("/etc/lsb-release"); if (File) { StringRef Data = File.get()->getBuffer(); SmallVector Lines; Data.split(Lines, "\n"); Distro Version = UnknownDistro; for (StringRef Line : Lines) if (Version == UnknownDistro && Line.startswith("DISTRIB_CODENAME=")) Version = llvm::StringSwitch(Line.substr(17)) .Case("hardy", UbuntuHardy) .Case("intrepid", UbuntuIntrepid) .Case("jaunty", UbuntuJaunty) .Case("karmic", UbuntuKarmic) .Case("lucid", UbuntuLucid) .Case("maverick", UbuntuMaverick) .Case("natty", UbuntuNatty) .Case("oneiric", UbuntuOneiric) .Case("precise", UbuntuPrecise) .Case("quantal", UbuntuQuantal) .Case("raring", UbuntuRaring) .Case("saucy", UbuntuSaucy) .Case("trusty", UbuntuTrusty) .Case("utopic", UbuntuUtopic) .Case("vivid", UbuntuVivid) .Case("wily", UbuntuWily) .Case("xenial", UbuntuXenial) .Default(UnknownDistro); return Version; } File = llvm::MemoryBuffer::getFile("/etc/redhat-release"); if (File) { StringRef Data = File.get()->getBuffer(); if (Data.startswith("Fedora release")) return Fedora; if (Data.startswith("Red Hat Enterprise Linux") || Data.startswith("CentOS")) { if (Data.find("release 7") != StringRef::npos) return RHEL7; else if (Data.find("release 6") != StringRef::npos) return RHEL6; else if (Data.find("release 5") != StringRef::npos) return RHEL5; else if (Data.find("release 4") != StringRef::npos) return RHEL4; } return UnknownDistro; } File = llvm::MemoryBuffer::getFile("/etc/debian_version"); if (File) { StringRef Data = File.get()->getBuffer(); if (Data[0] == '5') return DebianLenny; else if (Data.startswith("squeeze/sid") || Data[0] == '6') return DebianSqueeze; else if (Data.startswith("wheezy/sid") || Data[0] == '7') return DebianWheezy; else if (Data.startswith("jessie/sid") || Data[0] == '8') return DebianJessie; else if (Data.startswith("stretch/sid") || Data[0] == '9') return DebianStretch; return UnknownDistro; } if (D.getVFS().exists("/etc/SuSE-release")) return OpenSUSE; if (D.getVFS().exists("/etc/exherbo-release")) return Exherbo; if (D.getVFS().exists("/etc/arch-release")) return ArchLinux; return UnknownDistro; } /// \brief Get our best guess at the multiarch triple for a target. /// /// Debian-based systems are starting to use a multiarch setup where they use /// a target-triple directory in the library and header search paths. /// Unfortunately, this triple does not align with the vanilla target triple, /// so we provide a rough mapping here. static std::string getMultiarchTriple(const Driver &D, const llvm::Triple &TargetTriple, StringRef SysRoot) { llvm::Triple::EnvironmentType TargetEnvironment = TargetTriple.getEnvironment(); // For most architectures, just use whatever we have rather than trying to be // clever. switch (TargetTriple.getArch()) { default: break; // We use the existence of '/lib/' as a directory to detect some // common linux triples that don't quite match the Clang triple for both // 32-bit and 64-bit targets. Multiarch fixes its install triples to these // regardless of what the actual target triple is. case llvm::Triple::arm: case llvm::Triple::thumb: if (TargetEnvironment == llvm::Triple::GNUEABIHF) { if (D.getVFS().exists(SysRoot + "/lib/arm-linux-gnueabihf")) return "arm-linux-gnueabihf"; } else { if (D.getVFS().exists(SysRoot + "/lib/arm-linux-gnueabi")) return "arm-linux-gnueabi"; } break; case llvm::Triple::armeb: case llvm::Triple::thumbeb: if (TargetEnvironment == llvm::Triple::GNUEABIHF) { if (D.getVFS().exists(SysRoot + "/lib/armeb-linux-gnueabihf")) return "armeb-linux-gnueabihf"; } else { if (D.getVFS().exists(SysRoot + "/lib/armeb-linux-gnueabi")) return "armeb-linux-gnueabi"; } break; case llvm::Triple::x86: if (D.getVFS().exists(SysRoot + "/lib/i386-linux-gnu")) return "i386-linux-gnu"; break; case llvm::Triple::x86_64: // We don't want this for x32, otherwise it will match x86_64 libs if (TargetEnvironment != llvm::Triple::GNUX32 && D.getVFS().exists(SysRoot + "/lib/x86_64-linux-gnu")) return "x86_64-linux-gnu"; break; case llvm::Triple::aarch64: if (D.getVFS().exists(SysRoot + "/lib/aarch64-linux-gnu")) return "aarch64-linux-gnu"; break; case llvm::Triple::aarch64_be: if (D.getVFS().exists(SysRoot + "/lib/aarch64_be-linux-gnu")) return "aarch64_be-linux-gnu"; break; case llvm::Triple::mips: if (D.getVFS().exists(SysRoot + "/lib/mips-linux-gnu")) return "mips-linux-gnu"; break; case llvm::Triple::mipsel: if (D.getVFS().exists(SysRoot + "/lib/mipsel-linux-gnu")) return "mipsel-linux-gnu"; break; case llvm::Triple::mips64: if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnu")) return "mips64-linux-gnu"; if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnuabi64")) return "mips64-linux-gnuabi64"; break; case llvm::Triple::mips64el: if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnu")) return "mips64el-linux-gnu"; if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnuabi64")) return "mips64el-linux-gnuabi64"; break; case llvm::Triple::ppc: if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnuspe")) return "powerpc-linux-gnuspe"; if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnu")) return "powerpc-linux-gnu"; break; case llvm::Triple::ppc64: if (D.getVFS().exists(SysRoot + "/lib/powerpc64-linux-gnu")) return "powerpc64-linux-gnu"; break; case llvm::Triple::ppc64le: if (D.getVFS().exists(SysRoot + "/lib/powerpc64le-linux-gnu")) return "powerpc64le-linux-gnu"; break; case llvm::Triple::sparc: if (D.getVFS().exists(SysRoot + "/lib/sparc-linux-gnu")) return "sparc-linux-gnu"; break; case llvm::Triple::sparcv9: if (D.getVFS().exists(SysRoot + "/lib/sparc64-linux-gnu")) return "sparc64-linux-gnu"; break; case llvm::Triple::systemz: if (D.getVFS().exists(SysRoot + "/lib/s390x-linux-gnu")) return "s390x-linux-gnu"; break; } return TargetTriple.str(); } static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) { if (isMipsArch(Triple.getArch())) { // lib32 directory has a special meaning on MIPS targets. // It contains N32 ABI binaries. Use this folder if produce // code for N32 ABI only. if (tools::mips::hasMipsAbiArg(Args, "n32")) return "lib32"; return Triple.isArch32Bit() ? "lib" : "lib64"; } // It happens that only x86 and PPC use the 'lib32' variant of oslibdir, and // using that variant while targeting other architectures causes problems // because the libraries are laid out in shared system roots that can't cope // with a 'lib32' library search path being considered. So we only enable // them when we know we may need it. // // FIXME: This is a bit of a hack. We should really unify this code for // reasoning about oslibdir spellings with the lib dir spellings in the // GCCInstallationDetector, but that is a more significant refactoring. if (Triple.getArch() == llvm::Triple::x86 || Triple.getArch() == llvm::Triple::ppc) return "lib32"; if (Triple.getArch() == llvm::Triple::x86_64 && Triple.getEnvironment() == llvm::Triple::GNUX32) return "libx32"; return Triple.isArch32Bit() ? "lib" : "lib64"; } Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { GCCInstallation.init(Triple, Args); CudaInstallation.init(Triple, Args); Multilibs = GCCInstallation.getMultilibs(); llvm::Triple::ArchType Arch = Triple.getArch(); std::string SysRoot = computeSysRoot(); // Cross-compiling binutils and GCC installations (vanilla and openSUSE at // least) put various tools in a triple-prefixed directory off of the parent // of the GCC installation. We use the GCC triple here to ensure that we end // up with tools that support the same amount of cross compiling as the // detected GCC installation. For example, if we find a GCC installation // targeting x86_64, but it is a bi-arch GCC installation, it can also be // used to target i386. // FIXME: This seems unlikely to be Linux-specific. ToolChain::path_list &PPaths = getProgramPaths(); PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + GCCInstallation.getTriple().str() + "/bin") .str()); Distro Distro = DetectDistro(D, Arch); if (IsOpenSUSE(Distro) || IsUbuntu(Distro)) { ExtraOpts.push_back("-z"); ExtraOpts.push_back("relro"); } if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) ExtraOpts.push_back("-X"); const bool IsAndroid = Triple.isAndroid(); const bool IsMips = isMipsArch(Arch); if (IsMips && !SysRoot.empty()) ExtraOpts.push_back("--sysroot=" + SysRoot); // Do not use 'gnu' hash style for Mips targets because .gnu.hash // and the MIPS ABI require .dynsym to be sorted in different ways. // .gnu.hash needs symbols to be grouped by hash code whereas the MIPS // ABI requires a mapping between the GOT and the symbol table. // Android loader does not support .gnu.hash. if (!IsMips && !IsAndroid) { if (IsRedhat(Distro) || IsOpenSUSE(Distro) || (IsUbuntu(Distro) && Distro >= UbuntuMaverick)) ExtraOpts.push_back("--hash-style=gnu"); if (IsDebian(Distro) || IsOpenSUSE(Distro) || Distro == UbuntuLucid || Distro == UbuntuJaunty || Distro == UbuntuKarmic) ExtraOpts.push_back("--hash-style=both"); } if (IsRedhat(Distro)) ExtraOpts.push_back("--no-add-needed"); if ((IsDebian(Distro) && Distro >= DebianSqueeze) || IsOpenSUSE(Distro) || (IsRedhat(Distro) && Distro != RHEL4 && Distro != RHEL5) || (IsUbuntu(Distro) && Distro >= UbuntuKarmic)) ExtraOpts.push_back("--build-id"); if (IsOpenSUSE(Distro)) ExtraOpts.push_back("--enable-new-dtags"); // The selection of paths to try here is designed to match the patterns which // the GCC driver itself uses, as this is part of the GCC-compatible driver. // This was determined by running GCC in a fake filesystem, creating all // possible permutations of these directories, and seeing which ones it added // to the link paths. path_list &Paths = getFilePaths(); const std::string OSLibDir = getOSLibDir(Triple, Args); const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot); // Add the multilib suffixed paths where they are available. if (GCCInstallation.isValid()) { const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); const std::string &LibPath = GCCInstallation.getParentLibPath(); const Multilib &Multilib = GCCInstallation.getMultilib(); // Sourcery CodeBench MIPS toolchain holds some libraries under // a biarch-like suffix of the GCC installation. addPathIfExists(D, GCCInstallation.getInstallPath() + Multilib.gccSuffix(), Paths); // GCC cross compiling toolchains will install target libraries which ship // as part of the toolchain under // rather than as // any part of the GCC installation in // //gcc//. This decision is somewhat // debatable, but is the reality today. We need to search this tree even // when we have a sysroot somewhere else. It is the responsibility of // whomever is doing the cross build targeting a sysroot using a GCC // installation that is *not* within the system root to ensure two things: // // 1) Any DSOs that are linked in from this tree or from the install path // above must be present on the system root and found via an // appropriate rpath. // 2) There must not be libraries installed into // // unless they should be preferred over // those within the system root. // // Note that this matches the GCC behavior. See the below comment for where // Clang diverges from GCC's behavior. addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib/../" + OSLibDir + Multilib.osSuffix(), Paths); // If the GCC installation we found is inside of the sysroot, we want to // prefer libraries installed in the parent prefix of the GCC installation. // It is important to *not* use these paths when the GCC installation is // outside of the system root as that can pick up unintended libraries. // This usually happens when there is an external cross compiler on the // host system, and a more minimal sysroot available that is the target of // the cross. Note that GCC does include some of these directories in some // configurations but this seems somewhere between questionable and simply // a bug. if (StringRef(LibPath).startswith(SysRoot)) { addPathIfExists(D, LibPath + "/" + MultiarchTriple, Paths); addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths); } } // Similar to the logic for GCC above, if we currently running Clang inside // of the requested system root, add its parent library paths to // those searched. // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. if (StringRef(D.Dir).startswith(SysRoot)) { addPathIfExists(D, D.Dir + "/../lib/" + MultiarchTriple, Paths); addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths); } addPathIfExists(D, SysRoot + "/lib/" + MultiarchTriple, Paths); addPathIfExists(D, SysRoot + "/lib/../" + OSLibDir, Paths); addPathIfExists(D, SysRoot + "/usr/lib/" + MultiarchTriple, Paths); addPathIfExists(D, SysRoot + "/usr/lib/../" + OSLibDir, Paths); // Try walking via the GCC triple path in case of biarch or multiarch GCC // installations with strange symlinks. if (GCCInstallation.isValid()) { addPathIfExists(D, SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() + "/../../" + OSLibDir, Paths); // Add the 'other' biarch variant path Multilib BiarchSibling; if (GCCInstallation.getBiarchSibling(BiarchSibling)) { addPathIfExists(D, GCCInstallation.getInstallPath() + BiarchSibling.gccSuffix(), Paths); } // See comments above on the multilib variant for details of why this is // included even from outside the sysroot. const std::string &LibPath = GCCInstallation.getParentLibPath(); const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); const Multilib &Multilib = GCCInstallation.getMultilib(); addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib" + Multilib.osSuffix(), Paths); // See comments above on the multilib variant for details of why this is // only included from within the sysroot. if (StringRef(LibPath).startswith(SysRoot)) addPathIfExists(D, LibPath, Paths); } // Similar to the logic for GCC above, if we are currently running Clang // inside of the requested system root, add its parent library path to those // searched. // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. if (StringRef(D.Dir).startswith(SysRoot)) addPathIfExists(D, D.Dir + "/../lib", Paths); addPathIfExists(D, SysRoot + "/lib", Paths); addPathIfExists(D, SysRoot + "/usr/lib", Paths); } bool Linux::HasNativeLLVMSupport() const { return true; } Tool *Linux::buildLinker() const { return new tools::gnutools::Linker(*this); } Tool *Linux::buildAssembler() const { return new tools::gnutools::Assembler(*this); } std::string Linux::computeSysRoot() const { if (!getDriver().SysRoot.empty()) return getDriver().SysRoot; if (!GCCInstallation.isValid() || !isMipsArch(getTriple().getArch())) return std::string(); // Standalone MIPS toolchains use different names for sysroot folder // and put it into different places. Here we try to check some known // variants. const StringRef InstallDir = GCCInstallation.getInstallPath(); const StringRef TripleStr = GCCInstallation.getTriple().str(); const Multilib &Multilib = GCCInstallation.getMultilib(); std::string Path = (InstallDir + "/../../../../" + TripleStr + "/libc" + Multilib.osSuffix()) .str(); if (getVFS().exists(Path)) return Path; Path = (InstallDir + "/../../../../sysroot" + Multilib.osSuffix()).str(); if (getVFS().exists(Path)) return Path; return std::string(); } void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { const Driver &D = getDriver(); std::string SysRoot = computeSysRoot(); if (DriverArgs.hasArg(options::OPT_nostdinc)) return; if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include"); if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { SmallString<128> P(D.ResourceDir); llvm::sys::path::append(P, "include"); addSystemInclude(DriverArgs, CC1Args, P); } if (DriverArgs.hasArg(options::OPT_nostdlibinc)) return; // Check for configure-time C include directories. StringRef CIncludeDirs(C_INCLUDE_DIRS); if (CIncludeDirs != "") { SmallVector dirs; CIncludeDirs.split(dirs, ":"); for (StringRef dir : dirs) { StringRef Prefix = llvm::sys::path::is_absolute(dir) ? StringRef(SysRoot) : ""; addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); } return; } // Lacking those, try to detect the correct set of system includes for the // target triple. // Add include directories specific to the selected multilib set and multilib. if (GCCInstallation.isValid()) { const auto &Callback = Multilibs.includeDirsCallback(); if (Callback) { const auto IncludePaths = Callback(GCCInstallation.getInstallPath(), GCCInstallation.getTriple().str(), GCCInstallation.getMultilib()); for (const auto &Path : IncludePaths) addExternCSystemIncludeIfExists(DriverArgs, CC1Args, Path); } } // Implement generic Debian multiarch support. const StringRef X86_64MultiarchIncludeDirs[] = { "/usr/include/x86_64-linux-gnu", // FIXME: These are older forms of multiarch. It's not clear that they're // in use in any released version of Debian, so we should consider // removing them. "/usr/include/i686-linux-gnu/64", "/usr/include/i486-linux-gnu/64"}; const StringRef X86MultiarchIncludeDirs[] = { "/usr/include/i386-linux-gnu", // FIXME: These are older forms of multiarch. It's not clear that they're // in use in any released version of Debian, so we should consider // removing them. "/usr/include/x86_64-linux-gnu/32", "/usr/include/i686-linux-gnu", "/usr/include/i486-linux-gnu"}; const StringRef AArch64MultiarchIncludeDirs[] = { "/usr/include/aarch64-linux-gnu"}; const StringRef ARMMultiarchIncludeDirs[] = { "/usr/include/arm-linux-gnueabi"}; const StringRef ARMHFMultiarchIncludeDirs[] = { "/usr/include/arm-linux-gnueabihf"}; const StringRef ARMEBMultiarchIncludeDirs[] = { "/usr/include/armeb-linux-gnueabi"}; const StringRef ARMEBHFMultiarchIncludeDirs[] = { "/usr/include/armeb-linux-gnueabihf"}; const StringRef MIPSMultiarchIncludeDirs[] = {"/usr/include/mips-linux-gnu"}; const StringRef MIPSELMultiarchIncludeDirs[] = { "/usr/include/mipsel-linux-gnu"}; const StringRef MIPS64MultiarchIncludeDirs[] = { "/usr/include/mips64-linux-gnu", "/usr/include/mips64-linux-gnuabi64"}; const StringRef MIPS64ELMultiarchIncludeDirs[] = { "/usr/include/mips64el-linux-gnu", "/usr/include/mips64el-linux-gnuabi64"}; const StringRef PPCMultiarchIncludeDirs[] = { "/usr/include/powerpc-linux-gnu"}; const StringRef PPC64MultiarchIncludeDirs[] = { "/usr/include/powerpc64-linux-gnu"}; const StringRef PPC64LEMultiarchIncludeDirs[] = { "/usr/include/powerpc64le-linux-gnu"}; const StringRef SparcMultiarchIncludeDirs[] = { "/usr/include/sparc-linux-gnu"}; const StringRef Sparc64MultiarchIncludeDirs[] = { "/usr/include/sparc64-linux-gnu"}; const StringRef SYSTEMZMultiarchIncludeDirs[] = { "/usr/include/s390x-linux-gnu"}; ArrayRef MultiarchIncludeDirs; switch (getTriple().getArch()) { case llvm::Triple::x86_64: MultiarchIncludeDirs = X86_64MultiarchIncludeDirs; break; case llvm::Triple::x86: MultiarchIncludeDirs = X86MultiarchIncludeDirs; break; case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: MultiarchIncludeDirs = AArch64MultiarchIncludeDirs; break; case llvm::Triple::arm: case llvm::Triple::thumb: if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF) MultiarchIncludeDirs = ARMHFMultiarchIncludeDirs; else MultiarchIncludeDirs = ARMMultiarchIncludeDirs; break; case llvm::Triple::armeb: case llvm::Triple::thumbeb: if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF) MultiarchIncludeDirs = ARMEBHFMultiarchIncludeDirs; else MultiarchIncludeDirs = ARMEBMultiarchIncludeDirs; break; case llvm::Triple::mips: MultiarchIncludeDirs = MIPSMultiarchIncludeDirs; break; case llvm::Triple::mipsel: MultiarchIncludeDirs = MIPSELMultiarchIncludeDirs; break; case llvm::Triple::mips64: MultiarchIncludeDirs = MIPS64MultiarchIncludeDirs; break; case llvm::Triple::mips64el: MultiarchIncludeDirs = MIPS64ELMultiarchIncludeDirs; break; case llvm::Triple::ppc: MultiarchIncludeDirs = PPCMultiarchIncludeDirs; break; case llvm::Triple::ppc64: MultiarchIncludeDirs = PPC64MultiarchIncludeDirs; break; case llvm::Triple::ppc64le: MultiarchIncludeDirs = PPC64LEMultiarchIncludeDirs; break; case llvm::Triple::sparc: MultiarchIncludeDirs = SparcMultiarchIncludeDirs; break; case llvm::Triple::sparcv9: MultiarchIncludeDirs = Sparc64MultiarchIncludeDirs; break; case llvm::Triple::systemz: MultiarchIncludeDirs = SYSTEMZMultiarchIncludeDirs; break; default: break; } for (StringRef Dir : MultiarchIncludeDirs) { if (D.getVFS().exists(SysRoot + Dir)) { addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + Dir); break; } } if (getTriple().getOS() == llvm::Triple::RTEMS) return; // Add an include of '/include' directly. This isn't provided by default by // system GCCs, but is often used with cross-compiling GCCs, and harmless to // add even when Clang is acting as-if it were a system compiler. addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include"); addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); } static std::string DetectLibcxxIncludePath(StringRef base) { std::error_code EC; int MaxVersion = 0; std::string MaxVersionString = ""; for (llvm::sys::fs::directory_iterator LI(base, EC), LE; !EC && LI != LE; LI = LI.increment(EC)) { StringRef VersionText = llvm::sys::path::filename(LI->path()); int Version; if (VersionText[0] == 'v' && !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) { if (Version > MaxVersion) { MaxVersion = Version; MaxVersionString = VersionText; } } } return MaxVersion ? (base + "/" + MaxVersionString).str() : ""; } void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) return; // Check if libc++ has been enabled and provide its include paths if so. if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) { const std::string LibCXXIncludePathCandidates[] = { DetectLibcxxIncludePath(getDriver().Dir + "/../include/c++"), // We also check the system as for a long time this is the only place // Clang looked. // FIXME: We should really remove this. It doesn't make any sense. DetectLibcxxIncludePath(getDriver().SysRoot + "/usr/include/c++")}; for (const auto &IncludePath : LibCXXIncludePathCandidates) { if (IncludePath.empty() || !getVFS().exists(IncludePath)) continue; // Add the first candidate that exists. addSystemInclude(DriverArgs, CC1Args, IncludePath); break; } return; } // We need a detected GCC installation on Linux to provide libstdc++'s // headers. We handled the libc++ case above. if (!GCCInstallation.isValid()) return; // By default, look for the C++ headers in an include directory adjacent to // the lib directory of the GCC installation. Note that this is expect to be // equivalent to '/usr/include/c++/X.Y' in almost all cases. StringRef LibDir = GCCInstallation.getParentLibPath(); StringRef InstallDir = GCCInstallation.getInstallPath(); StringRef TripleStr = GCCInstallation.getTriple().str(); const Multilib &Multilib = GCCInstallation.getMultilib(); const std::string GCCMultiarchTriple = getMultiarchTriple( getDriver(), GCCInstallation.getTriple(), getDriver().SysRoot); const std::string TargetMultiarchTriple = getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); const GCCVersion &Version = GCCInstallation.getVersion(); // The primary search for libstdc++ supports multiarch variants. if (addLibStdCXXIncludePaths(LibDir.str() + "/../include", "/c++/" + Version.Text, TripleStr, GCCMultiarchTriple, TargetMultiarchTriple, Multilib.includeSuffix(), DriverArgs, CC1Args)) return; // Otherwise, fall back on a bunch of options which don't use multiarch // layouts for simplicity. const std::string LibStdCXXIncludePathCandidates[] = { // Gentoo is weird and places its headers inside the GCC install, // so if the first attempt to find the headers fails, try these patterns. InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." + Version.MinorStr, InstallDir.str() + "/include/g++-v" + Version.MajorStr, // Android standalone toolchain has C++ headers in yet another place. LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, // Freescale SDK C++ headers are directly in /usr/include/c++, // without a subdirectory corresponding to the gcc version. LibDir.str() + "/../include/c++", }; for (const auto &IncludePath : LibStdCXXIncludePathCandidates) { if (addLibStdCXXIncludePaths(IncludePath, /*Suffix*/ "", TripleStr, /*GCCMultiarchTriple*/ "", /*TargetMultiarchTriple*/ "", Multilib.includeSuffix(), DriverArgs, CC1Args)) break; } } void Linux::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nocudainc)) return; if (CudaInstallation.isValid()) { addSystemInclude(DriverArgs, CC1Args, CudaInstallation.getIncludePath()); CC1Args.push_back("-include"); CC1Args.push_back("__clang_cuda_runtime_wrapper.h"); } } bool Linux::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } SanitizerMask Linux::getSupportedSanitizers() const { const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; const bool IsMIPS64 = getTriple().getArch() == llvm::Triple::mips64 || getTriple().getArch() == llvm::Triple::mips64el; const bool IsPowerPC64 = getTriple().getArch() == llvm::Triple::ppc64 || getTriple().getArch() == llvm::Triple::ppc64le; const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 || getTriple().getArch() == llvm::Triple::aarch64_be; SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; Res |= SanitizerKind::KernelAddress; Res |= SanitizerKind::Vptr; Res |= SanitizerKind::SafeStack; if (IsX86_64 || IsMIPS64 || IsAArch64) Res |= SanitizerKind::DataFlow; if (IsX86_64 || IsMIPS64 || IsAArch64) Res |= SanitizerKind::Leak; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64) Res |= SanitizerKind::Thread; if (IsX86_64 || IsMIPS64 || IsPowerPC64 || IsAArch64) Res |= SanitizerKind::Memory; if (IsX86 || IsX86_64) { Res |= SanitizerKind::Function; } return Res; } void Linux::addProfileRTLibs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { if (!needsProfileRT(Args)) return; // Add linker option -u__llvm_runtime_variable to cause runtime // initialization module to be linked in. if (!Args.hasArg(options::OPT_coverage)) CmdArgs.push_back(Args.MakeArgString( Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); ToolChain::addProfileRTLibs(Args, CmdArgs); } /// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly. DragonFly::DragonFly(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { // Path mangling to find libexec getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); getFilePaths().push_back("/usr/lib/gcc50"); } Tool *DragonFly::buildAssembler() const { return new tools::dragonfly::Assembler(*this); } Tool *DragonFly::buildLinker() const { return new tools::dragonfly::Linker(*this); } /// Stub for CUDA toolchain. At the moment we don't have assembler or /// linker and need toolchain mainly to propagate device-side options /// to CC1. CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Linux(D, Triple, Args) {} void CudaToolChain::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { Linux::addClangTargetOptions(DriverArgs, CC1Args); CC1Args.push_back("-fcuda-is-device"); if (DriverArgs.hasArg(options::OPT_nocudalib)) return; std::string LibDeviceFile = CudaInstallation.getLibDeviceFile( DriverArgs.getLastArgValue(options::OPT_march_EQ)); if (!LibDeviceFile.empty()) { CC1Args.push_back("-mlink-cuda-bitcode"); CC1Args.push_back(DriverArgs.MakeArgString(LibDeviceFile)); // Libdevice in CUDA-7.0 requires PTX version that's more recent // than LLVM defaults to. Use PTX4.2 which is the PTX version that // came with CUDA-7.0. CC1Args.push_back("-target-feature"); CC1Args.push_back("+ptx42"); } } llvm::opt::DerivedArgList * CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, const char *BoundArch) const { DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); const OptTable &Opts = getDriver().getOpts(); for (Arg *A : Args) { if (A->getOption().matches(options::OPT_Xarch__)) { // Skip this argument unless the architecture matches BoundArch if (A->getValue(0) != StringRef(BoundArch)) continue; unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); unsigned Prev = Index; std::unique_ptr XarchArg(Opts.ParseOneArg(Args, Index)); // If the argument parsing failed or more than one argument was // consumed, the -Xarch_ argument's parameter tried to consume // extra arguments. Emit an error and ignore. // // We also want to disallow any options which would alter the // driver behavior; that isn't going to work in our model. We // use isDriverOption() as an approximation, although things // like -O4 are going to slip through. if (!XarchArg || Index > Prev + 1) { getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) << A->getAsString(Args); continue; } else if (XarchArg->getOption().hasFlag(options::DriverOption)) { getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) << A->getAsString(Args); continue; } XarchArg->setBaseArg(A); A = XarchArg.release(); DAL->AddSynthesizedArg(A); } DAL->append(A); } DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch); return DAL; } /// XCore tool chain XCoreToolChain::XCoreToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args) { // ProgramPaths are found via 'PATH' environment variable. } Tool *XCoreToolChain::buildAssembler() const { return new tools::XCore::Assembler(*this); } Tool *XCoreToolChain::buildLinker() const { return new tools::XCore::Linker(*this); } bool XCoreToolChain::isPICDefault() const { return false; } bool XCoreToolChain::isPIEDefault() const { return false; } bool XCoreToolChain::isPICDefaultForced() const { return false; } bool XCoreToolChain::SupportsProfiling() const { return false; } bool XCoreToolChain::hasBlocksRuntime() const { return false; } void XCoreToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdinc) || DriverArgs.hasArg(options::OPT_nostdlibinc)) return; if (const char *cl_include_dir = getenv("XCC_C_INCLUDE_PATH")) { SmallVector Dirs; const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'}; StringRef(cl_include_dir).split(Dirs, StringRef(EnvPathSeparatorStr)); ArrayRef DirVec(Dirs); addSystemIncludes(DriverArgs, CC1Args, DirVec); } } void XCoreToolChain::addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args) const { CC1Args.push_back("-nostdsysteminc"); } void XCoreToolChain::AddClangCXXStdlibIncludeArgs( const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdinc) || DriverArgs.hasArg(options::OPT_nostdlibinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) return; if (const char *cl_include_dir = getenv("XCC_CPLUS_INCLUDE_PATH")) { SmallVector Dirs; const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'}; StringRef(cl_include_dir).split(Dirs, StringRef(EnvPathSeparatorStr)); ArrayRef DirVec(Dirs); addSystemIncludes(DriverArgs, CC1Args, DirVec); } } void XCoreToolChain::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // We don't output any lib args. This is handled by xcc. } MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_GCC(D, Triple, Args) { // If a target of 'sparc-myriad-elf' is specified to clang, it wants to use // 'sparc-myriad--elf' (note the unknown OS) as the canonical triple. // This won't work to find gcc. Instead we give the installation detector an // extra triple, which is preferable to further hacks of the logic that at // present is based solely on getArch(). In particular, it would be wrong to // choose the myriad installation when targeting a non-myriad sparc install. switch (Triple.getArch()) { default: D.Diag(diag::err_target_unsupported_arch) << Triple.getArchName() << "myriad"; case llvm::Triple::sparc: case llvm::Triple::sparcel: case llvm::Triple::shave: GCCInstallation.init(Triple, Args, {"sparc-myriad-elf"}); } if (GCCInstallation.isValid()) { // The contents of LibDir are independent of the version of gcc. // This contains libc, libg (a superset of libc), libm, libstdc++, libssp. SmallString<128> LibDir(GCCInstallation.getParentLibPath()); if (Triple.getArch() == llvm::Triple::sparcel) llvm::sys::path::append(LibDir, "../sparc-myriad-elf/lib/le"); else llvm::sys::path::append(LibDir, "../sparc-myriad-elf/lib"); addPathIfExists(D, LibDir, getFilePaths()); // This directory contains crt{i,n,begin,end}.o as well as libgcc. // These files are tied to a particular version of gcc. SmallString<128> CompilerSupportDir(GCCInstallation.getInstallPath()); // There are actually 4 choices: {le,be} x {fpu,nofpu} // but as this toolchain is for LEON sparc, it can assume FPU. if (Triple.getArch() == llvm::Triple::sparcel) llvm::sys::path::append(CompilerSupportDir, "le"); addPathIfExists(D, CompilerSupportDir, getFilePaths()); } } MyriadToolChain::~MyriadToolChain() {} void MyriadToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (!DriverArgs.hasArg(options::OPT_nostdinc)) addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include"); } void MyriadToolChain::AddClangCXXStdlibIncludeArgs( const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) return; // Only libstdc++, for now. StringRef LibDir = GCCInstallation.getParentLibPath(); const GCCVersion &Version = GCCInstallation.getVersion(); StringRef TripleStr = GCCInstallation.getTriple().str(); const Multilib &Multilib = GCCInstallation.getMultilib(); addLibStdCXXIncludePaths( LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, "", TripleStr, "", "", Multilib.includeSuffix(), DriverArgs, CC1Args); } // MyriadToolChain handles several triples: // {shave,sparc{,el}}-myriad-{rtems,unknown}-elf Tool *MyriadToolChain::SelectTool(const JobAction &JA) const { // The inherited method works fine if not targeting the SHAVE. if (!isShaveCompilation(getTriple())) return ToolChain::SelectTool(JA); switch (JA.getKind()) { case Action::PreprocessJobClass: case Action::CompileJobClass: if (!Compiler) Compiler.reset(new tools::SHAVE::Compiler(*this)); return Compiler.get(); case Action::AssembleJobClass: if (!Assembler) Assembler.reset(new tools::SHAVE::Assembler(*this)); return Assembler.get(); default: return ToolChain::getTool(JA.getKind()); } } Tool *MyriadToolChain::buildLinker() const { return new tools::Myriad::Linker(*this); } WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args) : ToolChain(D, Triple, Args) { // Use LLD by default. DefaultLinker = "lld"; } bool WebAssembly::IsMathErrnoDefault() const { return false; } bool WebAssembly::IsObjCNonFragileABIDefault() const { return true; } bool WebAssembly::UseObjCMixedDispatch() const { return true; } bool WebAssembly::isPICDefault() const { return false; } bool WebAssembly::isPIEDefault() const { return false; } bool WebAssembly::isPICDefaultForced() const { return false; } bool WebAssembly::IsIntegratedAssemblerDefault() const { return true; } // TODO: Support Objective C stuff. bool WebAssembly::SupportsObjCGC() const { return false; } bool WebAssembly::hasBlocksRuntime() const { return false; } // TODO: Support profiling. bool WebAssembly::SupportsProfiling() const { return false; } bool WebAssembly::HasNativeLLVMSupport() const { return true; } void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasFlag(options::OPT_fuse_init_array, options::OPT_fno_use_init_array, true)) CC1Args.push_back("-fuse-init-array"); } Tool *WebAssembly::buildLinker() const { return new tools::wasm::Linker(*this); } PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { if (Args.hasArg(options::OPT_static)) D.Diag(diag::err_drv_unsupported_opt_for_target) << "-static" << "PS4"; // Determine where to find the PS4 libraries. We use SCE_PS4_SDK_DIR // if it exists; otherwise use the driver's installation path, which // should be /host_tools/bin. SmallString<512> PS4SDKDir; if (const char *EnvValue = getenv("SCE_PS4_SDK_DIR")) { if (!llvm::sys::fs::exists(EnvValue)) getDriver().Diag(clang::diag::warn_drv_ps4_sdk_dir) << EnvValue; PS4SDKDir = EnvValue; } else { PS4SDKDir = getDriver().Dir; llvm::sys::path::append(PS4SDKDir, "/../../"); } // By default, the driver won't report a warning if it can't find // PS4's include or lib directories. This behavior could be changed if // -Weverything or -Winvalid-or-nonexistent-directory options are passed. // If -isysroot was passed, use that as the SDK base path. std::string PrefixDir; if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { PrefixDir = A->getValue(); if (!llvm::sys::fs::exists(PrefixDir)) getDriver().Diag(clang::diag::warn_missing_sysroot) << PrefixDir; } else PrefixDir = PS4SDKDir.str(); SmallString<512> PS4SDKIncludeDir(PrefixDir); llvm::sys::path::append(PS4SDKIncludeDir, "target/include"); if (!Args.hasArg(options::OPT_nostdinc) && !Args.hasArg(options::OPT_nostdlibinc) && !Args.hasArg(options::OPT_isysroot) && !Args.hasArg(options::OPT__sysroot_EQ) && !llvm::sys::fs::exists(PS4SDKIncludeDir)) { getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) << "PS4 system headers" << PS4SDKIncludeDir; } SmallString<512> PS4SDKLibDir(PS4SDKDir); llvm::sys::path::append(PS4SDKLibDir, "target/lib"); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs) && !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) && !Args.hasArg(options::OPT_emit_ast) && !llvm::sys::fs::exists(PS4SDKLibDir)) { getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) << "PS4 system libraries" << PS4SDKLibDir; return; } getFilePaths().push_back(PS4SDKLibDir.str()); } Tool *PS4CPU::buildAssembler() const { return new tools::PS4cpu::Assemble(*this); } Tool *PS4CPU::buildLinker() const { return new tools::PS4cpu::Link(*this); } bool PS4CPU::isPICDefault() const { return true; } bool PS4CPU::HasNativeLLVMSupport() const { return true; } SanitizerMask PS4CPU::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; Res |= SanitizerKind::Vptr; return Res; } Index: projects/clang380-import/contrib/llvm/tools/clang/lib/Driver/ToolChains.h =================================================================== --- projects/clang380-import/contrib/llvm/tools/clang/lib/Driver/ToolChains.h (revision 295858) +++ projects/clang380-import/contrib/llvm/tools/clang/lib/Driver/ToolChains.h (revision 295859) @@ -1,1143 +1,1145 @@ //===--- ToolChains.h - ToolChain Implementations ---------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_H #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_H #include "Tools.h" #include "clang/Basic/VersionTuple.h" #include "clang/Driver/Action.h" #include "clang/Driver/Multilib.h" #include "clang/Driver/ToolChain.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/Support/Compiler.h" #include #include namespace clang { namespace driver { namespace toolchains { /// Generic_GCC - A tool chain using the 'gcc' command to perform /// all subcommands; this relies on gcc translating the majority of /// command line options. class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { public: /// \brief Struct to store and manipulate GCC versions. /// /// We rely on assumptions about the form and structure of GCC version /// numbers: they consist of at most three '.'-separated components, and each /// component is a non-negative integer except for the last component. For /// the last component we are very flexible in order to tolerate release /// candidates or 'x' wildcards. /// /// Note that the ordering established among GCCVersions is based on the /// preferred version string to use. For example we prefer versions without /// a hard-coded patch number to those with a hard coded patch number. /// /// Currently this doesn't provide any logic for textual suffixes to patches /// in the way that (for example) Debian's version format does. If that ever /// becomes necessary, it can be added. struct GCCVersion { /// \brief The unparsed text of the version. std::string Text; /// \brief The parsed major, minor, and patch numbers. int Major, Minor, Patch; /// \brief The text of the parsed major, and major+minor versions. std::string MajorStr, MinorStr; /// \brief Any textual suffix on the patch number. std::string PatchSuffix; static GCCVersion Parse(StringRef VersionText); bool isOlderThan(int RHSMajor, int RHSMinor, int RHSPatch, StringRef RHSPatchSuffix = StringRef()) const; bool operator<(const GCCVersion &RHS) const { return isOlderThan(RHS.Major, RHS.Minor, RHS.Patch, RHS.PatchSuffix); } bool operator>(const GCCVersion &RHS) const { return RHS < *this; } bool operator<=(const GCCVersion &RHS) const { return !(*this > RHS); } bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); } }; /// \brief This is a class to find a viable GCC installation for Clang to /// use. /// /// This class tries to find a GCC installation on the system, and report /// information about it. It starts from the host information provided to the /// Driver, and has logic for fuzzing that where appropriate. class GCCInstallationDetector { bool IsValid; llvm::Triple GCCTriple; const Driver &D; // FIXME: These might be better as path objects. std::string GCCInstallPath; std::string GCCParentLibPath; /// The primary multilib appropriate for the given flags. Multilib SelectedMultilib; /// On Biarch systems, this corresponds to the default multilib when /// targeting the non-default multilib. Otherwise, it is empty. llvm::Optional BiarchSibling; GCCVersion Version; // We retain the list of install paths that were considered and rejected in // order to print out detailed information in verbose mode. std::set CandidateGCCInstallPaths; /// The set of multilibs that the detected installation supports. MultilibSet Multilibs; public: explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {} void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args, ArrayRef ExtraTripleAliases = None); /// \brief Check whether we detected a valid GCC install. bool isValid() const { return IsValid; } /// \brief Get the GCC triple for the detected install. const llvm::Triple &getTriple() const { return GCCTriple; } /// \brief Get the detected GCC installation path. StringRef getInstallPath() const { return GCCInstallPath; } /// \brief Get the detected GCC parent lib path. StringRef getParentLibPath() const { return GCCParentLibPath; } /// \brief Get the detected Multilib const Multilib &getMultilib() const { return SelectedMultilib; } /// \brief Get the whole MultilibSet const MultilibSet &getMultilibs() const { return Multilibs; } /// Get the biarch sibling multilib (if it exists). /// \return true iff such a sibling exists bool getBiarchSibling(Multilib &M) const; /// \brief Get the detected GCC version string. const GCCVersion &getVersion() const { return Version; } /// \brief Print information about the detected GCC installation. void print(raw_ostream &OS) const; private: static void CollectLibDirsAndTriples(const llvm::Triple &TargetTriple, const llvm::Triple &BiarchTriple, SmallVectorImpl &LibDirs, SmallVectorImpl &TripleAliases, SmallVectorImpl &BiarchLibDirs, SmallVectorImpl &BiarchTripleAliases); void ScanLibDirForGCCTriple(const llvm::Triple &TargetArch, const llvm::opt::ArgList &Args, const std::string &LibDir, StringRef CandidateTriple, bool NeedsBiarchSuffix = false); void scanLibDirForGCCTripleSolaris(const llvm::Triple &TargetArch, const llvm::opt::ArgList &Args, const std::string &LibDir, StringRef CandidateTriple, bool NeedsBiarchSuffix = false); }; protected: GCCInstallationDetector GCCInstallation; // \brief A class to find a viable CUDA installation class CudaInstallationDetector { bool IsValid; const Driver &D; std::string CudaInstallPath; std::string CudaLibPath; std::string CudaLibDevicePath; std::string CudaIncludePath; llvm::StringMap CudaLibDeviceMap; public: CudaInstallationDetector(const Driver &D) : IsValid(false), D(D) {} void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args); /// \brief Check whether we detected a valid Cuda install. bool isValid() const { return IsValid; } /// \brief Print information about the detected CUDA installation. void print(raw_ostream &OS) const; /// \brief Get the detected Cuda installation path. StringRef getInstallPath() const { return CudaInstallPath; } /// \brief Get the detected Cuda Include path. StringRef getIncludePath() const { return CudaIncludePath; } /// \brief Get the detected Cuda library path. StringRef getLibPath() const { return CudaLibPath; } /// \brief Get the detected Cuda device library path. StringRef getLibDevicePath() const { return CudaLibDevicePath; } /// \brief Get libdevice file for given architecture std::string getLibDeviceFile(StringRef Gpu) const { return CudaLibDeviceMap.lookup(Gpu); } }; CudaInstallationDetector CudaInstallation; public: Generic_GCC(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); ~Generic_GCC() override; void printVerboseInfo(raw_ostream &OS) const override; bool IsUnwindTablesDefault() const override; bool isPICDefault() const override; bool isPIEDefault() const override; bool isPICDefaultForced() const override; bool IsIntegratedAssemblerDefault() const override; protected: Tool *getTool(Action::ActionClass AC) const override; Tool *buildAssembler() const override; Tool *buildLinker() const override; /// \name ToolChain Implementation Helper Functions /// @{ /// \brief Check whether the target triple's architecture is 64-bits. bool isTarget64Bit() const { return getTriple().isArch64Bit(); } /// \brief Check whether the target triple's architecture is 32-bits. bool isTarget32Bit() const { return getTriple().isArch32Bit(); } bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple, StringRef TargetMultiarchTriple, Twine IncludeSuffix, const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const; /// @} private: mutable std::unique_ptr Preprocess; mutable std::unique_ptr Compile; }; class LLVM_LIBRARY_VISIBILITY MachO : public ToolChain { protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; Tool *getTool(Action::ActionClass AC) const override; private: mutable std::unique_ptr Lipo; mutable std::unique_ptr Dsymutil; mutable std::unique_ptr VerifyDebug; public: MachO(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); ~MachO() override; /// @name MachO specific toolchain API /// { /// Get the "MachO" arch name for a particular compiler invocation. For /// example, Apple treats different ARM variations as distinct architectures. StringRef getMachOArchName(const llvm::opt::ArgList &Args) const; /// Add the linker arguments to link the ARC runtime library. virtual void AddLinkARCArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const {} /// Add the linker arguments to link the compiler runtime library. virtual void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; virtual void addStartObjectFileArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { } virtual void addMinVersionArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const {} /// On some iOS platforms, kernel and kernel modules were built statically. Is /// this such a target? virtual bool isKernelStatic() const { return false; } /// Is the target either iOS or an iOS simulator? bool isTargetIOSBased() const { return false; } void AddLinkRuntimeLib(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, StringRef DarwinLibName, bool AlwaysLink = false, bool IsEmbedded = false, bool AddRPath = false) const; /// Add any profiling runtime libraries that are needed. This is essentially a /// MachO specific version of addProfileRT in Tools.cpp. void addProfileRTLibs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override { // There aren't any profiling libs for embedded targets currently. } /// } /// @name ToolChain Implementation /// { std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, types::ID InputType) const override; types::ID LookupTypeForExtension(const char *Ext) const override; bool HasNativeLLVMSupport() const override; llvm::opt::DerivedArgList * TranslateArgs(const llvm::opt::DerivedArgList &Args, const char *BoundArch) const override; bool IsBlocksDefault() const override { // Always allow blocks on Apple; users interested in versioning are // expected to use /usr/include/Block.h. return true; } bool IsIntegratedAssemblerDefault() const override { // Default integrated assembler to on for Apple's MachO targets. return true; } bool IsMathErrnoDefault() const override { return false; } bool IsEncodeExtendedBlockSignatureDefault() const override { return true; } bool IsObjCNonFragileABIDefault() const override { // Non-fragile ABI is default for everything but i386. return getTriple().getArch() != llvm::Triple::x86; } bool UseObjCMixedDispatch() const override { return true; } bool IsUnwindTablesDefault() const override; RuntimeLibType GetDefaultRuntimeLibType() const override { return ToolChain::RLT_CompilerRT; } bool isPICDefault() const override; bool isPIEDefault() const override; bool isPICDefaultForced() const override; bool SupportsProfiling() const override; bool SupportsObjCGC() const override { return false; } bool UseDwarfDebugFlags() const override; bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override { return false; } /// } }; /// Darwin - The base Darwin tool chain. class LLVM_LIBRARY_VISIBILITY Darwin : public MachO { public: /// Whether the information on the target has been initialized. // // FIXME: This should be eliminated. What we want to do is make this part of // the "default target for arguments" selection process, once we get out of // the argument translation business. mutable bool TargetInitialized; enum DarwinPlatformKind { MacOS, IPhoneOS, IPhoneOSSimulator, TvOS, TvOSSimulator, WatchOS, WatchOSSimulator }; mutable DarwinPlatformKind TargetPlatform; /// The OS version we are targeting. mutable VersionTuple TargetVersion; private: void AddDeploymentTarget(llvm::opt::DerivedArgList &Args) const; public: Darwin(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); ~Darwin() override; std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, types::ID InputType) const override; /// @name Apple Specific Toolchain Implementation /// { void addMinVersionArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; void addStartObjectFileArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; bool isKernelStatic() const override { return (!(isTargetIPhoneOS() && !isIPhoneOSVersionLT(6, 0)) && !isTargetWatchOS()); } void addProfileRTLibs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; protected: /// } /// @name Darwin specific Toolchain functions /// { // FIXME: Eliminate these ...Target functions and derive separate tool chains // for these targets and put version in constructor. void setTarget(DarwinPlatformKind Platform, unsigned Major, unsigned Minor, unsigned Micro) const { // FIXME: For now, allow reinitialization as long as values don't // change. This will go away when we move away from argument translation. if (TargetInitialized && TargetPlatform == Platform && TargetVersion == VersionTuple(Major, Minor, Micro)) return; assert(!TargetInitialized && "Target already initialized!"); TargetInitialized = true; TargetPlatform = Platform; TargetVersion = VersionTuple(Major, Minor, Micro); } bool isTargetIPhoneOS() const { assert(TargetInitialized && "Target not initialized!"); return TargetPlatform == IPhoneOS || TargetPlatform == TvOS; } bool isTargetIOSSimulator() const { assert(TargetInitialized && "Target not initialized!"); return TargetPlatform == IPhoneOSSimulator || TargetPlatform == TvOSSimulator; } bool isTargetIOSBased() const { assert(TargetInitialized && "Target not initialized!"); return isTargetIPhoneOS() || isTargetIOSSimulator(); } bool isTargetTvOS() const { assert(TargetInitialized && "Target not initialized!"); return TargetPlatform == TvOS; } bool isTargetTvOSSimulator() const { assert(TargetInitialized && "Target not initialized!"); return TargetPlatform == TvOSSimulator; } bool isTargetTvOSBased() const { assert(TargetInitialized && "Target not initialized!"); return TargetPlatform == TvOS || TargetPlatform == TvOSSimulator; } bool isTargetWatchOS() const { assert(TargetInitialized && "Target not initialized!"); return TargetPlatform == WatchOS; } bool isTargetWatchOSSimulator() const { assert(TargetInitialized && "Target not initialized!"); return TargetPlatform == WatchOSSimulator; } bool isTargetWatchOSBased() const { assert(TargetInitialized && "Target not initialized!"); return TargetPlatform == WatchOS || TargetPlatform == WatchOSSimulator; } bool isTargetMacOS() const { assert(TargetInitialized && "Target not initialized!"); return TargetPlatform == MacOS; } bool isTargetInitialized() const { return TargetInitialized; } VersionTuple getTargetVersion() const { assert(TargetInitialized && "Target not initialized!"); return TargetVersion; } bool isIPhoneOSVersionLT(unsigned V0, unsigned V1 = 0, unsigned V2 = 0) const { assert(isTargetIOSBased() && "Unexpected call for non iOS target!"); return TargetVersion < VersionTuple(V0, V1, V2); } bool isMacosxVersionLT(unsigned V0, unsigned V1 = 0, unsigned V2 = 0) const { assert(isTargetMacOS() && "Unexpected call for non OS X target!"); return TargetVersion < VersionTuple(V0, V1, V2); } public: /// } /// @name ToolChain Implementation /// { // Darwin tools support multiple architecture (e.g., i386 and x86_64) and // most development is done against SDKs, so compiling for a different // architecture should not get any special treatment. bool isCrossCompiling() const override { return false; } llvm::opt::DerivedArgList * TranslateArgs(const llvm::opt::DerivedArgList &Args, const char *BoundArch) const override; ObjCRuntime getDefaultObjCRuntime(bool isNonFragile) const override; bool hasBlocksRuntime() const override; bool UseObjCMixedDispatch() const override { // This is only used with the non-fragile ABI and non-legacy dispatch. // Mixed dispatch is used everywhere except OS X before 10.6. return !(isTargetMacOS() && isMacosxVersionLT(10, 6)); } unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { // Stack protectors default to on for user code on 10.5, // and for everything in 10.6 and beyond if (isTargetIOSBased() || isTargetWatchOSBased()) return 1; else if (isTargetMacOS() && !isMacosxVersionLT(10, 6)) return 1; else if (isTargetMacOS() && !isMacosxVersionLT(10, 5) && !KernelOrKext) return 1; return 0; } bool SupportsObjCGC() const override; void CheckObjCARC() const override; bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override; SanitizerMask getSupportedSanitizers() const override; }; /// DarwinClang - The Darwin toolchain used by Clang. class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin { public: DarwinClang(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); /// @name Apple ToolChain Implementation /// { void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; void AddCCKextLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override; void AddLinkARCArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; unsigned GetDefaultDwarfVersion() const override { return 2; } // Until dtrace (via CTF) and LLDB can deal with distributed debug info, // Darwin defaults to standalone/full debug info. bool GetDefaultStandaloneDebug() const override { return true; } llvm::DebuggerKind getDefaultDebuggerTuning() const override { return llvm::DebuggerKind::LLDB; } /// } private: void AddLinkSanitizerLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, StringRef Sanitizer) const; }; class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC { virtual void anchor(); public: Generic_ELF(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args) : Generic_GCC(D, Triple, Args) {} void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; }; class LLVM_LIBRARY_VISIBILITY CloudABI : public Generic_ELF { public: CloudABI(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); bool HasNativeLLVMSupport() const override { return true; } bool IsMathErrnoDefault() const override { return false; } bool IsObjCNonFragileABIDefault() const override { return true; } CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override { return ToolChain::CST_Libcxx; } void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; bool isPIEDefault() const override { return false; } protected: Tool *buildLinker() const override; }; class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_GCC { public: Solaris(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); bool IsIntegratedAssemblerDefault() const override { return true; } void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; unsigned GetDefaultDwarfVersion() const override { return 2; } protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; }; class LLVM_LIBRARY_VISIBILITY MinGW : public ToolChain { public: MinGW(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); bool IsIntegratedAssemblerDefault() const override; bool IsUnwindTablesDefault() const override; bool isPICDefault() const override; bool isPIEDefault() const override; bool isPICDefaultForced() const override; bool UseSEHExceptions() const; void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; protected: Tool *getTool(Action::ActionClass AC) const override; Tool *buildLinker() const override; Tool *buildAssembler() const override; private: std::string Base; std::string GccLibDir; std::string Ver; std::string Arch; mutable std::unique_ptr Preprocessor; mutable std::unique_ptr Compiler; void findGccLibDir(); }; class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_ELF { public: OpenBSD(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); bool IsMathErrnoDefault() const override { return false; } bool IsObjCNonFragileABIDefault() const override { return true; } bool isPIEDefault() const override { return true; } unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { return 2; } unsigned GetDefaultDwarfVersion() const override { return 2; } protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; }; class LLVM_LIBRARY_VISIBILITY Bitrig : public Generic_ELF { public: Bitrig(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); bool IsMathErrnoDefault() const override { return false; } bool IsObjCNonFragileABIDefault() const override { return true; } CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { return 1; } protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; }; class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF { public: FreeBSD(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); bool HasNativeLLVMSupport() const override; bool IsMathErrnoDefault() const override { return false; } bool IsObjCNonFragileABIDefault() const override { return true; } CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override; bool isPIEDefault() const override; SanitizerMask getSupportedSanitizers() const override; unsigned GetDefaultDwarfVersion() const override { return 2; } // Until dtrace (via CTF) and LLDB can deal with distributed debug info, // FreeBSD defaults to standalone/full debug info. bool GetDefaultStandaloneDebug() const override { return true; } protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; }; class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF { public: NetBSD(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); bool IsMathErrnoDefault() const override { return false; } bool IsObjCNonFragileABIDefault() const override { return true; } CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; bool IsUnwindTablesDefault() const override { return true; } protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; }; class LLVM_LIBRARY_VISIBILITY Minix : public Generic_ELF { public: Minix(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; }; class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_ELF { public: DragonFly(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); bool IsMathErrnoDefault() const override { return false; } protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; }; class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF { public: Linux(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); bool HasNativeLLVMSupport() const override; void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; bool isPIEDefault() const override; SanitizerMask getSupportedSanitizers() const override; void addProfileRTLibs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; virtual std::string computeSysRoot() const; std::vector ExtraOpts; protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; }; class LLVM_LIBRARY_VISIBILITY CudaToolChain : public Linux { public: CudaToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); llvm::opt::DerivedArgList * TranslateArgs(const llvm::opt::DerivedArgList &Args, const char *BoundArch) const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; }; class LLVM_LIBRARY_VISIBILITY MipsLLVMToolChain : public Linux { protected: Tool *buildLinker() const override; public: MipsLLVMToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component, bool Shared = false) const override; std::string computeSysRoot() const override; RuntimeLibType GetDefaultRuntimeLibType() const override { return GCCInstallation.isValid() ? RuntimeLibType::RLT_Libgcc : RuntimeLibType::RLT_CompilerRT; } private: Multilib SelectedMultilib; std::string LibSuffix; }; class LLVM_LIBRARY_VISIBILITY HexagonToolChain : public Linux { protected: GCCVersion GCCLibAndIncVersion; Tool *buildAssembler() const override; Tool *buildLinker() const override; public: HexagonToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); ~HexagonToolChain() override; void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; } bool IsIntegratedAssemblerDefault() const override { return true; } std::string getHexagonTargetDir( const std::string &InstalledDir, const SmallVectorImpl &PrefixDirs) const; void getHexagonLibraryPaths(const llvm::opt::ArgList &Args, ToolChain::path_list &LibPaths) const; static const StringRef GetDefaultCPU(); static const StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args); static Optional getSmallDataThreshold( const llvm::opt::ArgList &Args); }; class LLVM_LIBRARY_VISIBILITY AMDGPUToolChain : public Generic_ELF { protected: Tool *buildLinker() const override; public: AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); bool IsIntegratedAssemblerDefault() const override { return true; } }; class LLVM_LIBRARY_VISIBILITY NaClToolChain : public Generic_ELF { public: NaClToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; bool IsIntegratedAssemblerDefault() const override { return getTriple().getArch() == llvm::Triple::mipsel; } // Get the path to the file containing NaCl's ARM macros. // It lives in NaClToolChain because the ARMAssembler tool needs a // const char * that it can pass around, const char *GetNaClArmMacrosPath() const { return NaClArmMacrosPath.c_str(); } std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, types::ID InputType) const override; protected: Tool *buildLinker() const override; Tool *buildAssembler() const override; private: std::string NaClArmMacrosPath; }; /// TCEToolChain - A tool chain using the llvm bitcode tools to perform /// all subcommands. See http://tce.cs.tut.fi for our peculiar target. class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain { public: TCEToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); ~TCEToolChain() override; bool IsMathErrnoDefault() const override; bool isPICDefault() const override; bool isPIEDefault() const override; bool isPICDefaultForced() const override; }; class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain { public: MSVCToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); llvm::opt::DerivedArgList * TranslateArgs(const llvm::opt::DerivedArgList &Args, const char *BoundArch) const override; bool IsIntegratedAssemblerDefault() const override; bool IsUnwindTablesDefault() const override; bool isPICDefault() const override; bool isPIEDefault() const override; bool isPICDefaultForced() const override; void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; bool getWindowsSDKDir(std::string &path, int &major, std::string &windowsSDKIncludeVersion, std::string &windowsSDKLibVersion) const; bool getWindowsSDKLibraryPath(std::string &path) const; /// \brief Check if Universal CRT should be used if available bool useUniversalCRT(std::string &visualStudioDir) const; bool getUniversalCRTSdkDir(std::string &path, std::string &ucrtVersion) const; bool getUniversalCRTLibraryPath(std::string &path) const; bool getVisualStudioInstallDir(std::string &path) const; bool getVisualStudioBinariesFolder(const char *clangProgramPath, std::string &path) const; std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, types::ID InputType) const override; SanitizerMask getSupportedSanitizers() const override; protected: void AddSystemIncludeWithSubfolder(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, const std::string &folder, const Twine &subfolder1, const Twine &subfolder2 = "", const Twine &subfolder3 = "") const; Tool *buildLinker() const override; Tool *buildAssembler() const override; }; class LLVM_LIBRARY_VISIBILITY CrossWindowsToolChain : public Generic_GCC { public: CrossWindowsToolChain(const Driver &D, const llvm::Triple &T, const llvm::opt::ArgList &Args); bool IsIntegratedAssemblerDefault() const override { return true; } bool IsUnwindTablesDefault() const override; bool isPICDefault() const override; bool isPIEDefault() const override; bool isPICDefaultForced() const override; unsigned int GetDefaultStackProtectorLevel(bool KernelOrKext) const override { return 0; } void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; SanitizerMask getSupportedSanitizers() const override; protected: Tool *buildLinker() const override; Tool *buildAssembler() const override; }; class LLVM_LIBRARY_VISIBILITY XCoreToolChain : public ToolChain { public: XCoreToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; public: bool isPICDefault() const override; bool isPIEDefault() const override; bool isPICDefaultForced() const override; bool SupportsProfiling() const override; bool hasBlocksRuntime() const override; void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; }; /// MyriadToolChain - A tool chain using either clang or the external compiler /// installed by the Movidius SDK to perform all subcommands. class LLVM_LIBRARY_VISIBILITY MyriadToolChain : public Generic_GCC { public: MyriadToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); ~MyriadToolChain() override; void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; Tool *SelectTool(const JobAction &JA) const override; unsigned GetDefaultDwarfVersion() const override { return 2; } protected: Tool *buildLinker() const override; bool isShaveCompilation(const llvm::Triple &T) const { return T.getArch() == llvm::Triple::shave; } private: mutable std::unique_ptr Compiler; mutable std::unique_ptr Assembler; }; class LLVM_LIBRARY_VISIBILITY WebAssembly final : public ToolChain { public: WebAssembly(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); private: bool IsMathErrnoDefault() const override; bool IsObjCNonFragileABIDefault() const override; bool UseObjCMixedDispatch() const override; bool isPICDefault() const override; bool isPIEDefault() const override; bool isPICDefaultForced() const override; bool IsIntegratedAssemblerDefault() const override; bool hasBlocksRuntime() const override; bool SupportsObjCGC() const override; bool SupportsProfiling() const override; bool HasNativeLLVMSupport() const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; Tool *buildLinker() const override; }; class LLVM_LIBRARY_VISIBILITY PS4CPU : public Generic_ELF { public: PS4CPU(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); bool IsMathErrnoDefault() const override { return false; } bool IsObjCNonFragileABIDefault() const override { return true; } bool HasNativeLLVMSupport() const override; bool isPICDefault() const override; unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { return 2; // SSPStrong } llvm::DebuggerKind getDefaultDebuggerTuning() const override { return llvm::DebuggerKind::SCE; } SanitizerMask getSupportedSanitizers() const override; protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; }; } // end namespace toolchains } // end namespace driver } // end namespace clang #endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_H Index: projects/clang380-import/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp =================================================================== --- projects/clang380-import/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp (revision 295858) +++ projects/clang380-import/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp (revision 295859) @@ -1,1227 +1,1227 @@ //===--- ContinuationIndenter.cpp - Format C++ code -----------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief This file implements the continuation indenter. /// //===----------------------------------------------------------------------===// #include "BreakableToken.h" #include "ContinuationIndenter.h" #include "WhitespaceManager.h" #include "clang/Basic/OperatorPrecedence.h" #include "clang/Basic/SourceManager.h" #include "clang/Format/Format.h" #include "llvm/Support/Debug.h" #include #define DEBUG_TYPE "format-formatter" namespace clang { namespace format { // Returns the length of everything up to the first possible line break after // the ), ], } or > matching \c Tok. static unsigned getLengthToMatchingParen(const FormatToken &Tok) { if (!Tok.MatchingParen) return 0; FormatToken *End = Tok.MatchingParen; while (End->Next && !End->Next->CanBreakBefore) { End = End->Next; } return End->TotalLength - Tok.TotalLength + 1; } static unsigned getLengthToNextOperator(const FormatToken &Tok) { if (!Tok.NextOperator) return 0; return Tok.NextOperator->TotalLength - Tok.TotalLength; } // Returns \c true if \c Tok is the "." or "->" of a call and starts the next // segment of a builder type call. static bool startsSegmentOfBuilderTypeCall(const FormatToken &Tok) { return Tok.isMemberAccess() && Tok.Previous && Tok.Previous->closesScope(); } // Returns \c true if \c Current starts a new parameter. static bool startsNextParameter(const FormatToken &Current, const FormatStyle &Style) { const FormatToken &Previous = *Current.Previous; if (Current.is(TT_CtorInitializerComma) && Style.BreakConstructorInitializersBeforeComma) return true; return Previous.is(tok::comma) && !Current.isTrailingComment() && (Previous.isNot(TT_CtorInitializerComma) || !Style.BreakConstructorInitializersBeforeComma); } ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style, const AdditionalKeywords &Keywords, SourceManager &SourceMgr, WhitespaceManager &Whitespaces, encoding::Encoding Encoding, bool BinPackInconclusiveFunctions) : Style(Style), Keywords(Keywords), SourceMgr(SourceMgr), Whitespaces(Whitespaces), Encoding(Encoding), BinPackInconclusiveFunctions(BinPackInconclusiveFunctions), CommentPragmasRegex(Style.CommentPragmas) {} LineState ContinuationIndenter::getInitialState(unsigned FirstIndent, const AnnotatedLine *Line, bool DryRun) { LineState State; State.FirstIndent = FirstIndent; State.Column = FirstIndent; State.Line = Line; State.NextToken = Line->First; State.Stack.push_back(ParenState(FirstIndent, Line->Level, FirstIndent, /*AvoidBinPacking=*/false, /*NoLineBreak=*/false)); State.LineContainsContinuedForLoopSection = false; State.StartOfStringLiteral = 0; State.StartOfLineLevel = 0; State.LowestLevelOnLine = 0; State.IgnoreStackForComparison = false; // The first token has already been indented and thus consumed. moveStateToNextToken(State, DryRun, /*Newline=*/false); return State; } bool ContinuationIndenter::canBreak(const LineState &State) { const FormatToken &Current = *State.NextToken; const FormatToken &Previous = *Current.Previous; assert(&Previous == Current.Previous); if (!Current.CanBreakBefore && !(State.Stack.back().BreakBeforeClosingBrace && Current.closesBlockOrBlockTypeList(Style))) return false; // The opening "{" of a braced list has to be on the same line as the first // element if it is nested in another braced init list or function call. if (!Current.MustBreakBefore && Previous.is(tok::l_brace) && Previous.isNot(TT_DictLiteral) && Previous.BlockKind == BK_BracedInit && Previous.Previous && Previous.Previous->isOneOf(tok::l_brace, tok::l_paren, tok::comma)) return false; // This prevents breaks like: // ... // SomeParameter, OtherParameter).DoSomething( // ... // As they hide "DoSomething" and are generally bad for readability. if (Previous.opensScope() && Previous.isNot(tok::l_brace) && State.LowestLevelOnLine < State.StartOfLineLevel && State.LowestLevelOnLine < Current.NestingLevel) return false; if (Current.isMemberAccess() && State.Stack.back().ContainsUnwrappedBuilder) return false; // Don't create a 'hanging' indent if there are multiple blocks in a single // statement. if (Previous.is(tok::l_brace) && State.Stack.size() > 1 && State.Stack[State.Stack.size() - 2].NestedBlockInlined && State.Stack[State.Stack.size() - 2].HasMultipleNestedBlocks) return false; // Don't break after very short return types (e.g. "void") as that is often // unexpected. if (Current.is(TT_FunctionDeclarationName) && State.Column < 6) { if (Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None) return false; } return !State.Stack.back().NoLineBreak; } bool ContinuationIndenter::mustBreak(const LineState &State) { const FormatToken &Current = *State.NextToken; const FormatToken &Previous = *Current.Previous; if (Current.MustBreakBefore || Current.is(TT_InlineASMColon)) return true; if (State.Stack.back().BreakBeforeClosingBrace && Current.closesBlockOrBlockTypeList(Style)) return true; if (Previous.is(tok::semi) && State.LineContainsContinuedForLoopSection) return true; if ((startsNextParameter(Current, Style) || Previous.is(tok::semi) || (Previous.is(TT_TemplateCloser) && Current.is(TT_StartOfName) && // FIXME: This is a temporary workaround for the case where clang-format // sets BreakBeforeParameter to avoid bin packing and this creates a // completely unnecessary line break after a template type that isn't // line-wrapped. (Previous.NestingLevel == 1 || Style.BinPackParameters)) || (Style.BreakBeforeTernaryOperators && Current.is(TT_ConditionalExpr) && Previous.isNot(tok::question)) || (!Style.BreakBeforeTernaryOperators && Previous.is(TT_ConditionalExpr))) && State.Stack.back().BreakBeforeParameter && !Current.isTrailingComment() && !Current.isOneOf(tok::r_paren, tok::r_brace)) return true; if (((Previous.is(TT_DictLiteral) && Previous.is(tok::l_brace)) || (Previous.is(TT_ArrayInitializerLSquare) && Previous.ParameterCount > 1)) && Style.ColumnLimit > 0 && getLengthToMatchingParen(Previous) + State.Column - 1 > getColumnLimit(State)) return true; if (Current.is(TT_CtorInitializerColon) && (State.Column + State.Line->Last->TotalLength - Current.TotalLength + 2 > getColumnLimit(State) || State.Stack.back().BreakBeforeParameter) && ((Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All) || Style.BreakConstructorInitializersBeforeComma || Style.ColumnLimit != 0)) return true; if (Current.is(TT_SelectorName) && State.Stack.back().ObjCSelectorNameFound && State.Stack.back().BreakBeforeParameter) return true; unsigned NewLineColumn = getNewLineColumn(State); - if (Current.isMemberAccess() && + if (Current.isMemberAccess() && Style.ColumnLimit != 0 && State.Column + getLengthToNextOperator(Current) > Style.ColumnLimit && (State.Column > NewLineColumn || Current.NestingLevel < State.StartOfLineLevel)) return true; if (State.Column <= NewLineColumn) return false; if (Style.AlwaysBreakBeforeMultilineStrings && (NewLineColumn == State.FirstIndent + Style.ContinuationIndentWidth || Previous.is(tok::comma) || Current.NestingLevel < 2) && !Previous.isOneOf(tok::kw_return, tok::lessless, tok::at) && !Previous.isOneOf(TT_InlineASMColon, TT_ConditionalExpr) && nextIsMultilineString(State)) return true; // Using CanBreakBefore here and below takes care of the decision whether the // current style uses wrapping before or after operators for the given // operator. if (Previous.is(TT_BinaryOperator) && Current.CanBreakBefore) { // If we need to break somewhere inside the LHS of a binary expression, we // should also break after the operator. Otherwise, the formatting would // hide the operator precedence, e.g. in: // if (aaaaaaaaaaaaaa == // bbbbbbbbbbbbbb && c) {.. // For comparisons, we only apply this rule, if the LHS is a binary // expression itself as otherwise, the line breaks seem superfluous. // We need special cases for ">>" which we have split into two ">" while // lexing in order to make template parsing easier. bool IsComparison = (Previous.getPrecedence() == prec::Relational || Previous.getPrecedence() == prec::Equality) && Previous.Previous && Previous.Previous->isNot(TT_BinaryOperator); // For >>. bool LHSIsBinaryExpr = Previous.Previous && Previous.Previous->EndsBinaryExpression; if ((!IsComparison || LHSIsBinaryExpr) && !Current.isTrailingComment() && Previous.getPrecedence() != prec::Assignment && State.Stack.back().BreakBeforeParameter) return true; } else if (Current.is(TT_BinaryOperator) && Current.CanBreakBefore && State.Stack.back().BreakBeforeParameter) { return true; } // Same as above, but for the first "<<" operator. if (Current.is(tok::lessless) && Current.isNot(TT_OverloadedOperator) && State.Stack.back().BreakBeforeParameter && State.Stack.back().FirstLessLess == 0) return true; if (Current.NestingLevel == 0 && !Current.isTrailingComment()) { // Always break after "template <...>" and leading annotations. This is only // for cases where the entire line does not fit on a single line as a // different LineFormatter would be used otherwise. if (Previous.ClosesTemplateDeclaration) return true; if (Previous.is(TT_FunctionAnnotationRParen)) return true; if (Previous.is(TT_LeadingJavaAnnotation) && Current.isNot(tok::l_paren) && Current.isNot(TT_LeadingJavaAnnotation)) return true; } // If the return type spans multiple lines, wrap before the function name. if ((Current.is(TT_FunctionDeclarationName) || (Current.is(tok::kw_operator) && !Previous.is(tok::coloncolon))) && State.Stack.back().BreakBeforeParameter) return true; if (startsSegmentOfBuilderTypeCall(Current) && (State.Stack.back().CallContinuation != 0 || State.Stack.back().BreakBeforeParameter)) return true; // The following could be precomputed as they do not depend on the state. // However, as they should take effect only if the UnwrappedLine does not fit // into the ColumnLimit, they are checked here in the ContinuationIndenter. if (Style.ColumnLimit != 0 && Previous.BlockKind == BK_Block && Previous.is(tok::l_brace) && !Current.isOneOf(tok::r_brace, tok::comment)) return true; if (Current.is(tok::lessless) && ((Previous.is(tok::identifier) && Previous.TokenText == "endl") || (Previous.Tok.isLiteral() && (Previous.TokenText.endswith("\\n\"") || Previous.TokenText == "\'\\n\'")))) return true; return false; } unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline, bool DryRun, unsigned ExtraSpaces) { const FormatToken &Current = *State.NextToken; assert(!State.Stack.empty()); if ((Current.is(TT_ImplicitStringLiteral) && (Current.Previous->Tok.getIdentifierInfo() == nullptr || Current.Previous->Tok.getIdentifierInfo()->getPPKeywordID() == tok::pp_not_keyword))) { unsigned EndColumn = SourceMgr.getSpellingColumnNumber(Current.WhitespaceRange.getEnd()); if (Current.LastNewlineOffset != 0) { // If there is a newline within this token, the final column will solely // determined by the current end column. State.Column = EndColumn; } else { unsigned StartColumn = SourceMgr.getSpellingColumnNumber(Current.WhitespaceRange.getBegin()); assert(EndColumn >= StartColumn); State.Column += EndColumn - StartColumn; } moveStateToNextToken(State, DryRun, /*Newline=*/false); return 0; } unsigned Penalty = 0; if (Newline) Penalty = addTokenOnNewLine(State, DryRun); else addTokenOnCurrentLine(State, DryRun, ExtraSpaces); return moveStateToNextToken(State, DryRun, Newline) + Penalty; } void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, unsigned ExtraSpaces) { FormatToken &Current = *State.NextToken; const FormatToken &Previous = *State.NextToken->Previous; if (Current.is(tok::equal) && (State.Line->First->is(tok::kw_for) || Current.NestingLevel == 0) && State.Stack.back().VariablePos == 0) { State.Stack.back().VariablePos = State.Column; // Move over * and & if they are bound to the variable name. const FormatToken *Tok = &Previous; while (Tok && State.Stack.back().VariablePos >= Tok->ColumnWidth) { State.Stack.back().VariablePos -= Tok->ColumnWidth; if (Tok->SpacesRequiredBefore != 0) break; Tok = Tok->Previous; } if (Previous.PartOfMultiVariableDeclStmt) State.Stack.back().LastSpace = State.Stack.back().VariablePos; } unsigned Spaces = Current.SpacesRequiredBefore + ExtraSpaces; if (!DryRun) Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, /*IndentLevel=*/0, Spaces, State.Column + Spaces); if (Current.is(TT_SelectorName) && !State.Stack.back().ObjCSelectorNameFound) { unsigned MinIndent = std::max(State.FirstIndent + Style.ContinuationIndentWidth, State.Stack.back().Indent); unsigned FirstColonPos = State.Column + Spaces + Current.ColumnWidth; if (Current.LongestObjCSelectorName == 0) State.Stack.back().AlignColons = false; else if (MinIndent + Current.LongestObjCSelectorName > FirstColonPos) State.Stack.back().ColonPos = MinIndent + Current.LongestObjCSelectorName; else State.Stack.back().ColonPos = FirstColonPos; } // In "AlwaysBreak" mode, enforce wrapping directly after the parenthesis by // disallowing any further line breaks if there is no line break after the // opening parenthesis. Don't break if it doesn't conserve columns. if (Style.AlignAfterOpenBracket == FormatStyle::BAS_AlwaysBreak && Previous.is(tok::l_paren) && State.Column > getNewLineColumn(State) && (!Previous.Previous || !Previous.Previous->isOneOf(tok::kw_for, tok::kw_while, tok::kw_switch))) State.Stack.back().NoLineBreak = true; if (Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign && Previous.opensScope() && Previous.isNot(TT_ObjCMethodExpr) && (Current.isNot(TT_LineComment) || Previous.BlockKind == BK_BracedInit)) State.Stack.back().Indent = State.Column + Spaces; if (State.Stack.back().AvoidBinPacking && startsNextParameter(Current, Style)) State.Stack.back().NoLineBreak = true; if (startsSegmentOfBuilderTypeCall(Current) && State.Column > getNewLineColumn(State)) State.Stack.back().ContainsUnwrappedBuilder = true; if (Current.is(TT_LambdaArrow) && Style.Language == FormatStyle::LK_Java) State.Stack.back().NoLineBreak = true; if (Current.isMemberAccess() && Previous.is(tok::r_paren) && (Previous.MatchingParen && (Previous.TotalLength - Previous.MatchingParen->TotalLength > 10))) { // If there is a function call with long parameters, break before trailing // calls. This prevents things like: // EXPECT_CALL(SomeLongParameter).Times( // 2); // We don't want to do this for short parameters as they can just be // indexes. State.Stack.back().NoLineBreak = true; } State.Column += Spaces; if (Current.isNot(tok::comment) && Previous.is(tok::l_paren) && Previous.Previous && Previous.Previous->isOneOf(tok::kw_if, tok::kw_for)) { // Treat the condition inside an if as if it was a second function // parameter, i.e. let nested calls have a continuation indent. State.Stack.back().LastSpace = State.Column; State.Stack.back().NestedBlockIndent = State.Column; } else if (!Current.isOneOf(tok::comment, tok::caret) && ((Previous.is(tok::comma) && !Previous.is(TT_OverloadedOperator)) || (Previous.is(tok::colon) && Previous.is(TT_ObjCMethodExpr)))) { State.Stack.back().LastSpace = State.Column; } else if ((Previous.isOneOf(TT_BinaryOperator, TT_ConditionalExpr, TT_CtorInitializerColon)) && ((Previous.getPrecedence() != prec::Assignment && (Previous.isNot(tok::lessless) || Previous.OperatorIndex != 0 || Previous.NextOperator)) || Current.StartsBinaryExpression)) { // Always indent relative to the RHS of the expression unless this is a // simple assignment without binary expression on the RHS. Also indent // relative to unary operators and the colons of constructor initializers. State.Stack.back().LastSpace = State.Column; } else if (Previous.is(TT_InheritanceColon)) { State.Stack.back().Indent = State.Column; State.Stack.back().LastSpace = State.Column; } else if (Previous.opensScope()) { // If a function has a trailing call, indent all parameters from the // opening parenthesis. This avoids confusing indents like: // OuterFunction(InnerFunctionCall( // break // ParameterToInnerFunction)) // break // .SecondInnerFunctionCall(); bool HasTrailingCall = false; if (Previous.MatchingParen) { const FormatToken *Next = Previous.MatchingParen->getNextNonComment(); HasTrailingCall = Next && Next->isMemberAccess(); } if (HasTrailingCall && State.Stack.size() > 1 && State.Stack[State.Stack.size() - 2].CallContinuation == 0) State.Stack.back().LastSpace = State.Column; } } unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, bool DryRun) { FormatToken &Current = *State.NextToken; const FormatToken &Previous = *State.NextToken->Previous; // Extra penalty that needs to be added because of the way certain line // breaks are chosen. unsigned Penalty = 0; const FormatToken *PreviousNonComment = Current.getPreviousNonComment(); const FormatToken *NextNonComment = Previous.getNextNonComment(); if (!NextNonComment) NextNonComment = &Current; // The first line break on any NestingLevel causes an extra penalty in order // prefer similar line breaks. if (!State.Stack.back().ContainsLineBreak) Penalty += 15; State.Stack.back().ContainsLineBreak = true; Penalty += State.NextToken->SplitPenalty; // Breaking before the first "<<" is generally not desirable if the LHS is // short. Also always add the penalty if the LHS is split over mutliple lines // to avoid unnecessary line breaks that just work around this penalty. if (NextNonComment->is(tok::lessless) && State.Stack.back().FirstLessLess == 0 && (State.Column <= Style.ColumnLimit / 3 || State.Stack.back().BreakBeforeParameter)) Penalty += Style.PenaltyBreakFirstLessLess; State.Column = getNewLineColumn(State); // Indent nested blocks relative to this column, unless in a very specific // JavaScript special case where: // // var loooooong_name = // function() { // // code // } // // is common and should be formatted like a free-standing function. if (Style.Language != FormatStyle::LK_JavaScript || Current.NestingLevel != 0 || !PreviousNonComment->is(tok::equal) || !Current.is(Keywords.kw_function)) State.Stack.back().NestedBlockIndent = State.Column; if (NextNonComment->isMemberAccess()) { if (State.Stack.back().CallContinuation == 0) State.Stack.back().CallContinuation = State.Column; } else if (NextNonComment->is(TT_SelectorName)) { if (!State.Stack.back().ObjCSelectorNameFound) { if (NextNonComment->LongestObjCSelectorName == 0) { State.Stack.back().AlignColons = false; } else { State.Stack.back().ColonPos = (Style.IndentWrappedFunctionNames ? std::max(State.Stack.back().Indent, State.FirstIndent + Style.ContinuationIndentWidth) : State.Stack.back().Indent) + NextNonComment->LongestObjCSelectorName; } } else if (State.Stack.back().AlignColons && State.Stack.back().ColonPos <= NextNonComment->ColumnWidth) { State.Stack.back().ColonPos = State.Column + NextNonComment->ColumnWidth; } } else if (PreviousNonComment && PreviousNonComment->is(tok::colon) && PreviousNonComment->isOneOf(TT_ObjCMethodExpr, TT_DictLiteral)) { // FIXME: This is hacky, find a better way. The problem is that in an ObjC // method expression, the block should be aligned to the line starting it, // e.g.: // [aaaaaaaaaaaaaaa aaaaaaaaa: \\ break for some reason // ^(int *i) { // // ... // }]; // Thus, we set LastSpace of the next higher NestingLevel, to which we move // when we consume all of the "}"'s FakeRParens at the "{". if (State.Stack.size() > 1) State.Stack[State.Stack.size() - 2].LastSpace = std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) + Style.ContinuationIndentWidth; } if ((Previous.isOneOf(tok::comma, tok::semi) && !State.Stack.back().AvoidBinPacking) || Previous.is(TT_BinaryOperator)) State.Stack.back().BreakBeforeParameter = false; if (Previous.isOneOf(TT_TemplateCloser, TT_JavaAnnotation) && Current.NestingLevel == 0) State.Stack.back().BreakBeforeParameter = false; if (NextNonComment->is(tok::question) || (PreviousNonComment && PreviousNonComment->is(tok::question))) State.Stack.back().BreakBeforeParameter = true; if (Current.is(TT_BinaryOperator) && Current.CanBreakBefore) State.Stack.back().BreakBeforeParameter = false; if (!DryRun) { unsigned Newlines = std::max( 1u, std::min(Current.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1)); Whitespaces.replaceWhitespace(Current, Newlines, State.Stack.back().IndentLevel, State.Column, State.Column, State.Line->InPPDirective); } if (!Current.isTrailingComment()) State.Stack.back().LastSpace = State.Column; State.StartOfLineLevel = Current.NestingLevel; State.LowestLevelOnLine = Current.NestingLevel; // Any break on this level means that the parent level has been broken // and we need to avoid bin packing there. bool NestedBlockSpecialCase = Style.Language != FormatStyle::LK_Cpp && Current.is(tok::r_brace) && State.Stack.size() > 1 && State.Stack[State.Stack.size() - 2].NestedBlockInlined; if (!NestedBlockSpecialCase) for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) State.Stack[i].BreakBeforeParameter = true; if (PreviousNonComment && !PreviousNonComment->isOneOf(tok::comma, tok::semi) && (PreviousNonComment->isNot(TT_TemplateCloser) || Current.NestingLevel != 0) && !PreviousNonComment->isOneOf( TT_BinaryOperator, TT_FunctionAnnotationRParen, TT_JavaAnnotation, TT_LeadingJavaAnnotation) && Current.isNot(TT_BinaryOperator) && !PreviousNonComment->opensScope()) State.Stack.back().BreakBeforeParameter = true; // If we break after { or the [ of an array initializer, we should also break // before the corresponding } or ]. if (PreviousNonComment && (PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare))) State.Stack.back().BreakBeforeClosingBrace = true; if (State.Stack.back().AvoidBinPacking) { // If we are breaking after '(', '{', '<', this is not bin packing // unless AllowAllParametersOfDeclarationOnNextLine is false or this is a // dict/object literal. if (!Previous.isOneOf(tok::l_paren, tok::l_brace, TT_BinaryOperator) || (!Style.AllowAllParametersOfDeclarationOnNextLine && State.Line->MustBeDeclaration) || Previous.is(TT_DictLiteral)) State.Stack.back().BreakBeforeParameter = true; } return Penalty; } unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { if (!State.NextToken || !State.NextToken->Previous) return 0; FormatToken &Current = *State.NextToken; const FormatToken &Previous = *Current.Previous; // If we are continuing an expression, we want to use the continuation indent. unsigned ContinuationIndent = std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) + Style.ContinuationIndentWidth; const FormatToken *PreviousNonComment = Current.getPreviousNonComment(); const FormatToken *NextNonComment = Previous.getNextNonComment(); if (!NextNonComment) NextNonComment = &Current; // Java specific bits. if (Style.Language == FormatStyle::LK_Java && Current.isOneOf(Keywords.kw_implements, Keywords.kw_extends)) return std::max(State.Stack.back().LastSpace, State.Stack.back().Indent + Style.ContinuationIndentWidth); if (NextNonComment->is(tok::l_brace) && NextNonComment->BlockKind == BK_Block) return Current.NestingLevel == 0 ? State.FirstIndent : State.Stack.back().Indent; if (Current.isOneOf(tok::r_brace, tok::r_square) && State.Stack.size() > 1) { if (Current.closesBlockOrBlockTypeList(Style)) return State.Stack[State.Stack.size() - 2].NestedBlockIndent; if (Current.MatchingParen && Current.MatchingParen->BlockKind == BK_BracedInit) return State.Stack[State.Stack.size() - 2].LastSpace; return State.FirstIndent; } if (Current.is(tok::identifier) && Current.Next && Current.Next->is(TT_DictLiteral)) return State.Stack.back().Indent; if (NextNonComment->isStringLiteral() && State.StartOfStringLiteral != 0) return State.StartOfStringLiteral; if (NextNonComment->is(TT_ObjCStringLiteral) && State.StartOfStringLiteral != 0) return State.StartOfStringLiteral - 1; if (NextNonComment->is(tok::lessless) && State.Stack.back().FirstLessLess != 0) return State.Stack.back().FirstLessLess; if (NextNonComment->isMemberAccess()) { if (State.Stack.back().CallContinuation == 0) return ContinuationIndent; return State.Stack.back().CallContinuation; } if (State.Stack.back().QuestionColumn != 0 && ((NextNonComment->is(tok::colon) && NextNonComment->is(TT_ConditionalExpr)) || Previous.is(TT_ConditionalExpr))) return State.Stack.back().QuestionColumn; if (Previous.is(tok::comma) && State.Stack.back().VariablePos != 0) return State.Stack.back().VariablePos; if ((PreviousNonComment && (PreviousNonComment->ClosesTemplateDeclaration || PreviousNonComment->isOneOf( TT_AttributeParen, TT_FunctionAnnotationRParen, TT_JavaAnnotation, TT_LeadingJavaAnnotation))) || (!Style.IndentWrappedFunctionNames && NextNonComment->isOneOf(tok::kw_operator, TT_FunctionDeclarationName))) return std::max(State.Stack.back().LastSpace, State.Stack.back().Indent); if (NextNonComment->is(TT_SelectorName)) { if (!State.Stack.back().ObjCSelectorNameFound) { if (NextNonComment->LongestObjCSelectorName == 0) return State.Stack.back().Indent; return (Style.IndentWrappedFunctionNames ? std::max(State.Stack.back().Indent, State.FirstIndent + Style.ContinuationIndentWidth) : State.Stack.back().Indent) + NextNonComment->LongestObjCSelectorName - NextNonComment->ColumnWidth; } if (!State.Stack.back().AlignColons) return State.Stack.back().Indent; if (State.Stack.back().ColonPos > NextNonComment->ColumnWidth) return State.Stack.back().ColonPos - NextNonComment->ColumnWidth; return State.Stack.back().Indent; } if (NextNonComment->is(TT_ArraySubscriptLSquare)) { if (State.Stack.back().StartOfArraySubscripts != 0) return State.Stack.back().StartOfArraySubscripts; return ContinuationIndent; } // This ensure that we correctly format ObjC methods calls without inputs, // i.e. where the last element isn't selector like: [callee method]; if (NextNonComment->is(tok::identifier) && NextNonComment->FakeRParens == 0 && NextNonComment->Next && NextNonComment->Next->is(TT_ObjCMethodExpr)) return State.Stack.back().Indent; if (NextNonComment->isOneOf(TT_StartOfName, TT_PointerOrReference) || Previous.isOneOf(tok::coloncolon, tok::equal, TT_JsTypeColon)) return ContinuationIndent; if (PreviousNonComment && PreviousNonComment->is(tok::colon) && PreviousNonComment->isOneOf(TT_ObjCMethodExpr, TT_DictLiteral)) return ContinuationIndent; if (NextNonComment->is(TT_CtorInitializerColon)) return State.FirstIndent + Style.ConstructorInitializerIndentWidth; if (NextNonComment->is(TT_CtorInitializerComma)) return State.Stack.back().Indent; if (Previous.is(tok::r_paren) && !Current.isBinaryOperator() && !Current.isOneOf(tok::colon, tok::comment)) return ContinuationIndent; if (State.Stack.back().Indent == State.FirstIndent && PreviousNonComment && PreviousNonComment->isNot(tok::r_brace)) // Ensure that we fall back to the continuation indent width instead of // just flushing continuations left. return State.Stack.back().Indent + Style.ContinuationIndentWidth; return State.Stack.back().Indent; } unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, bool DryRun, bool Newline) { assert(State.Stack.size()); const FormatToken &Current = *State.NextToken; if (Current.is(TT_InheritanceColon)) State.Stack.back().AvoidBinPacking = true; if (Current.is(tok::lessless) && Current.isNot(TT_OverloadedOperator)) { if (State.Stack.back().FirstLessLess == 0) State.Stack.back().FirstLessLess = State.Column; else State.Stack.back().LastOperatorWrapped = Newline; } if ((Current.is(TT_BinaryOperator) && Current.isNot(tok::lessless)) || Current.is(TT_ConditionalExpr)) State.Stack.back().LastOperatorWrapped = Newline; if (Current.is(TT_ArraySubscriptLSquare) && State.Stack.back().StartOfArraySubscripts == 0) State.Stack.back().StartOfArraySubscripts = State.Column; if ((Current.is(tok::question) && Style.BreakBeforeTernaryOperators) || (Current.getPreviousNonComment() && Current.isNot(tok::colon) && Current.getPreviousNonComment()->is(tok::question) && !Style.BreakBeforeTernaryOperators)) State.Stack.back().QuestionColumn = State.Column; if (!Current.opensScope() && !Current.closesScope()) State.LowestLevelOnLine = std::min(State.LowestLevelOnLine, Current.NestingLevel); if (Current.isMemberAccess()) State.Stack.back().StartOfFunctionCall = !Current.NextOperator ? 0 : State.Column; if (Current.is(TT_SelectorName)) { State.Stack.back().ObjCSelectorNameFound = true; if (Style.IndentWrappedFunctionNames) { State.Stack.back().Indent = State.FirstIndent + Style.ContinuationIndentWidth; } } if (Current.is(TT_CtorInitializerColon)) { // Indent 2 from the column, so: // SomeClass::SomeClass() // : First(...), ... // Next(...) // ^ line up here. State.Stack.back().Indent = State.Column + (Style.BreakConstructorInitializersBeforeComma ? 0 : 2); State.Stack.back().NestedBlockIndent = State.Stack.back().Indent; if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine) State.Stack.back().AvoidBinPacking = true; State.Stack.back().BreakBeforeParameter = false; } if (Current.isOneOf(TT_BinaryOperator, TT_ConditionalExpr) && Newline) State.Stack.back().NestedBlockIndent = State.Column + Current.ColumnWidth + 1; // Insert scopes created by fake parenthesis. const FormatToken *Previous = Current.getPreviousNonComment(); // Add special behavior to support a format commonly used for JavaScript // closures: // SomeFunction(function() { // foo(); // bar(); // }, a, b, c); if (Current.isNot(tok::comment) && Previous && Previous->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) && !Previous->is(TT_DictLiteral) && State.Stack.size() > 1) { if (State.Stack[State.Stack.size() - 2].NestedBlockInlined && Newline) for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) State.Stack[i].NoLineBreak = true; State.Stack[State.Stack.size() - 2].NestedBlockInlined = false; } if (Previous && (Previous->isOneOf(tok::l_paren, tok::comma, tok::colon) || Previous->isOneOf(TT_BinaryOperator, TT_ConditionalExpr)) && !Previous->isOneOf(TT_DictLiteral, TT_ObjCMethodExpr)) { State.Stack.back().NestedBlockInlined = !Newline && (Previous->isNot(tok::l_paren) || Previous->ParameterCount > 1); } moveStatePastFakeLParens(State, Newline); moveStatePastScopeOpener(State, Newline); moveStatePastScopeCloser(State); moveStatePastFakeRParens(State); if (Current.isStringLiteral() && State.StartOfStringLiteral == 0) State.StartOfStringLiteral = State.Column; if (Current.is(TT_ObjCStringLiteral) && State.StartOfStringLiteral == 0) State.StartOfStringLiteral = State.Column + 1; else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash) && !Current.isStringLiteral()) State.StartOfStringLiteral = 0; State.Column += Current.ColumnWidth; State.NextToken = State.NextToken->Next; unsigned Penalty = breakProtrudingToken(Current, State, DryRun); if (State.Column > getColumnLimit(State)) { unsigned ExcessCharacters = State.Column - getColumnLimit(State); Penalty += Style.PenaltyExcessCharacter * ExcessCharacters; } if (Current.Role) Current.Role->formatFromToken(State, this, DryRun); // If the previous has a special role, let it consume tokens as appropriate. // It is necessary to start at the previous token for the only implemented // role (comma separated list). That way, the decision whether or not to break // after the "{" is already done and both options are tried and evaluated. // FIXME: This is ugly, find a better way. if (Previous && Previous->Role) Penalty += Previous->Role->formatAfterToken(State, this, DryRun); return Penalty; } void ContinuationIndenter::moveStatePastFakeLParens(LineState &State, bool Newline) { const FormatToken &Current = *State.NextToken; const FormatToken *Previous = Current.getPreviousNonComment(); // Don't add extra indentation for the first fake parenthesis after // 'return', assignments or opening <({[. The indentation for these cases // is special cased. bool SkipFirstExtraIndent = (Previous && (Previous->opensScope() || Previous->isOneOf(tok::semi, tok::kw_return) || (Previous->getPrecedence() == prec::Assignment && Style.AlignOperands) || Previous->is(TT_ObjCMethodExpr))); for (SmallVectorImpl::const_reverse_iterator I = Current.FakeLParens.rbegin(), E = Current.FakeLParens.rend(); I != E; ++I) { ParenState NewParenState = State.Stack.back(); NewParenState.ContainsLineBreak = false; // Indent from 'LastSpace' unless these are fake parentheses encapsulating // a builder type call after 'return' or, if the alignment after opening // brackets is disabled. if (!Current.isTrailingComment() && (Style.AlignOperands || *I < prec::Assignment) && (!Previous || Previous->isNot(tok::kw_return) || (Style.Language != FormatStyle::LK_Java && *I > 0)) && (Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign || *I != prec::Comma || Current.NestingLevel == 0)) NewParenState.Indent = std::max(std::max(State.Column, NewParenState.Indent), State.Stack.back().LastSpace); // Don't allow the RHS of an operator to be split over multiple lines unless // there is a line-break right after the operator. // Exclude relational operators, as there, it is always more desirable to // have the LHS 'left' of the RHS. if (Previous && Previous->getPrecedence() > prec::Assignment && Previous->isOneOf(TT_BinaryOperator, TT_ConditionalExpr) && Previous->getPrecedence() != prec::Relational) { bool BreakBeforeOperator = Previous->is(tok::lessless) || (Previous->is(TT_BinaryOperator) && Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None) || (Previous->is(TT_ConditionalExpr) && Style.BreakBeforeTernaryOperators); if ((!Newline && !BreakBeforeOperator) || (!State.Stack.back().LastOperatorWrapped && BreakBeforeOperator)) NewParenState.NoLineBreak = true; } // Do not indent relative to the fake parentheses inserted for "." or "->". // This is a special case to make the following to statements consistent: // OuterFunction(InnerFunctionCall( // break // ParameterToInnerFunction)); // OuterFunction(SomeObject.InnerFunctionCall( // break // ParameterToInnerFunction)); if (*I > prec::Unknown) NewParenState.LastSpace = std::max(NewParenState.LastSpace, State.Column); if (*I != prec::Conditional && !Current.is(TT_UnaryOperator)) NewParenState.StartOfFunctionCall = State.Column; // Always indent conditional expressions. Never indent expression where // the 'operator' is ',', ';' or an assignment (i.e. *I <= // prec::Assignment) as those have different indentation rules. Indent // other expression, unless the indentation needs to be skipped. if (*I == prec::Conditional || (!SkipFirstExtraIndent && *I > prec::Assignment && !Current.isTrailingComment())) NewParenState.Indent += Style.ContinuationIndentWidth; if ((Previous && !Previous->opensScope()) || *I != prec::Comma) NewParenState.BreakBeforeParameter = false; State.Stack.push_back(NewParenState); SkipFirstExtraIndent = false; } } void ContinuationIndenter::moveStatePastFakeRParens(LineState &State) { for (unsigned i = 0, e = State.NextToken->FakeRParens; i != e; ++i) { unsigned VariablePos = State.Stack.back().VariablePos; if (State.Stack.size() == 1) { // Do not pop the last element. break; } State.Stack.pop_back(); State.Stack.back().VariablePos = VariablePos; } } void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, bool Newline) { const FormatToken &Current = *State.NextToken; if (!Current.opensScope()) return; if (Current.MatchingParen && Current.BlockKind == BK_Block) { moveStateToNewBlock(State); return; } unsigned NewIndent; unsigned NewIndentLevel = State.Stack.back().IndentLevel; unsigned LastSpace = State.Stack.back().LastSpace; bool AvoidBinPacking; bool BreakBeforeParameter = false; unsigned NestedBlockIndent = std::max(State.Stack.back().StartOfFunctionCall, State.Stack.back().NestedBlockIndent); if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)) { if (Current.opensBlockOrBlockTypeList(Style)) { NewIndent = State.Stack.back().NestedBlockIndent + Style.IndentWidth; NewIndent = std::min(State.Column + 2, NewIndent); ++NewIndentLevel; } else { NewIndent = State.Stack.back().LastSpace + Style.ContinuationIndentWidth; } const FormatToken *NextNoComment = Current.getNextNonComment(); bool EndsInComma = Current.MatchingParen && Current.MatchingParen->Previous && Current.MatchingParen->Previous->is(tok::comma); AvoidBinPacking = (Current.is(TT_ArrayInitializerLSquare) && EndsInComma) || Current.is(TT_DictLiteral) || Style.Language == FormatStyle::LK_Proto || !Style.BinPackArguments || (NextNoComment && NextNoComment->is(TT_DesignatedInitializerPeriod)); if (Current.ParameterCount > 1) NestedBlockIndent = std::max(NestedBlockIndent, State.Column + 1); } else { NewIndent = Style.ContinuationIndentWidth + std::max(State.Stack.back().LastSpace, State.Stack.back().StartOfFunctionCall); // Ensure that different different brackets force relative alignment, e.g.: // void SomeFunction(vector< // break // int> v); // FIXME: We likely want to do this for more combinations of brackets. // Verify that it is wanted for ObjC, too. if (Current.Tok.getKind() == tok::less && Current.ParentBracket == tok::l_paren) { NewIndent = std::max(NewIndent, State.Stack.back().Indent); LastSpace = std::max(LastSpace, State.Stack.back().Indent); } AvoidBinPacking = (State.Line->MustBeDeclaration && !Style.BinPackParameters) || (!State.Line->MustBeDeclaration && !Style.BinPackArguments) || (Style.ExperimentalAutoDetectBinPacking && (Current.PackingKind == PPK_OnePerLine || (!BinPackInconclusiveFunctions && Current.PackingKind == PPK_Inconclusive))); if (Current.is(TT_ObjCMethodExpr) && Current.MatchingParen) { if (Style.ColumnLimit) { // If this '[' opens an ObjC call, determine whether all parameters fit // into one line and put one per line if they don't. if (getLengthToMatchingParen(Current) + State.Column > getColumnLimit(State)) BreakBeforeParameter = true; } else { // For ColumnLimit = 0, we have to figure out whether there is or has to // be a line break within this call. for (const FormatToken *Tok = &Current; Tok && Tok != Current.MatchingParen; Tok = Tok->Next) { if (Tok->MustBreakBefore || (Tok->CanBreakBefore && Tok->NewlinesBefore > 0)) { BreakBeforeParameter = true; break; } } } } } // Generally inherit NoLineBreak from the current scope to nested scope. // However, don't do this for non-empty nested blocks, dict literals and // array literals as these follow different indentation rules. bool NoLineBreak = Current.Children.empty() && !Current.isOneOf(TT_DictLiteral, TT_ArrayInitializerLSquare) && (State.Stack.back().NoLineBreak || (Current.is(TT_TemplateOpener) && State.Stack.back().ContainsUnwrappedBuilder)); State.Stack.push_back(ParenState(NewIndent, NewIndentLevel, LastSpace, AvoidBinPacking, NoLineBreak)); State.Stack.back().NestedBlockIndent = NestedBlockIndent; State.Stack.back().BreakBeforeParameter = BreakBeforeParameter; State.Stack.back().HasMultipleNestedBlocks = Current.BlockParameterCount > 1; } void ContinuationIndenter::moveStatePastScopeCloser(LineState &State) { const FormatToken &Current = *State.NextToken; if (!Current.closesScope()) return; // If we encounter a closing ), ], } or >, we can remove a level from our // stacks. if (State.Stack.size() > 1 && (Current.isOneOf(tok::r_paren, tok::r_square) || (Current.is(tok::r_brace) && State.NextToken != State.Line->First) || State.NextToken->is(TT_TemplateCloser))) State.Stack.pop_back(); if (Current.is(tok::r_square)) { // If this ends the array subscript expr, reset the corresponding value. const FormatToken *NextNonComment = Current.getNextNonComment(); if (NextNonComment && NextNonComment->isNot(tok::l_square)) State.Stack.back().StartOfArraySubscripts = 0; } } void ContinuationIndenter::moveStateToNewBlock(LineState &State) { unsigned NestedBlockIndent = State.Stack.back().NestedBlockIndent; // ObjC block sometimes follow special indentation rules. unsigned NewIndent = NestedBlockIndent + (State.NextToken->is(TT_ObjCBlockLBrace) ? Style.ObjCBlockIndentWidth : Style.IndentWidth); State.Stack.push_back(ParenState( NewIndent, /*NewIndentLevel=*/State.Stack.back().IndentLevel + 1, State.Stack.back().LastSpace, /*AvoidBinPacking=*/true, /*NoLineBreak=*/false)); State.Stack.back().NestedBlockIndent = NestedBlockIndent; State.Stack.back().BreakBeforeParameter = true; } unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current, LineState &State) { // Break before further function parameters on all levels. for (unsigned i = 0, e = State.Stack.size(); i != e; ++i) State.Stack[i].BreakBeforeParameter = true; unsigned ColumnsUsed = State.Column; // We can only affect layout of the first and the last line, so the penalty // for all other lines is constant, and we ignore it. State.Column = Current.LastLineColumnWidth; if (ColumnsUsed > getColumnLimit(State)) return Style.PenaltyExcessCharacter * (ColumnsUsed - getColumnLimit(State)); return 0; } unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current, LineState &State, bool DryRun) { // Don't break multi-line tokens other than block comments. Instead, just // update the state. if (Current.isNot(TT_BlockComment) && Current.IsMultiline) return addMultilineToken(Current, State); // Don't break implicit string literals or import statements. if (Current.is(TT_ImplicitStringLiteral) || State.Line->Type == LT_ImportStatement) return 0; if (!Current.isStringLiteral() && !Current.is(tok::comment)) return 0; std::unique_ptr Token; unsigned StartColumn = State.Column - Current.ColumnWidth; unsigned ColumnLimit = getColumnLimit(State); if (Current.isStringLiteral()) { // FIXME: String literal breaking is currently disabled for Java and JS, as // it requires strings to be merged using "+" which we don't support. if (Style.Language == FormatStyle::LK_Java || Style.Language == FormatStyle::LK_JavaScript) return 0; // Don't break string literals inside preprocessor directives (except for // #define directives, as their contents are stored in separate lines and // are not affected by this check). // This way we avoid breaking code with line directives and unknown // preprocessor directives that contain long string literals. if (State.Line->Type == LT_PreprocessorDirective) return 0; // Exempts unterminated string literals from line breaking. The user will // likely want to terminate the string before any line breaking is done. if (Current.IsUnterminatedLiteral) return 0; StringRef Text = Current.TokenText; StringRef Prefix; StringRef Postfix; bool IsNSStringLiteral = false; // FIXME: Handle whitespace between '_T', '(', '"..."', and ')'. // FIXME: Store Prefix and Suffix (or PrefixLength and SuffixLength to // reduce the overhead) for each FormatToken, which is a string, so that we // don't run multiple checks here on the hot path. if (Text.startswith("\"") && Current.Previous && Current.Previous->is(tok::at)) { IsNSStringLiteral = true; Prefix = "@\""; } if ((Text.endswith(Postfix = "\"") && (IsNSStringLiteral || Text.startswith(Prefix = "\"") || Text.startswith(Prefix = "u\"") || Text.startswith(Prefix = "U\"") || Text.startswith(Prefix = "u8\"") || Text.startswith(Prefix = "L\""))) || (Text.startswith(Prefix = "_T(\"") && Text.endswith(Postfix = "\")"))) { Token.reset(new BreakableStringLiteral( Current, State.Line->Level, StartColumn, Prefix, Postfix, State.Line->InPPDirective, Encoding, Style)); } else { return 0; } } else if (Current.is(TT_BlockComment) && Current.isTrailingComment()) { if (!Style.ReflowComments || CommentPragmasRegex.match(Current.TokenText.substr(2))) return 0; Token.reset(new BreakableBlockComment( Current, State.Line->Level, StartColumn, Current.OriginalColumn, !Current.Previous, State.Line->InPPDirective, Encoding, Style)); } else if (Current.is(TT_LineComment) && (Current.Previous == nullptr || Current.Previous->isNot(TT_ImplicitStringLiteral))) { if (!Style.ReflowComments || CommentPragmasRegex.match(Current.TokenText.substr(2))) return 0; Token.reset(new BreakableLineComment(Current, State.Line->Level, StartColumn, /*InPPDirective=*/false, Encoding, Style)); // We don't insert backslashes when breaking line comments. ColumnLimit = Style.ColumnLimit; } else { return 0; } if (Current.UnbreakableTailLength >= ColumnLimit) return 0; unsigned RemainingSpace = ColumnLimit - Current.UnbreakableTailLength; bool BreakInserted = false; unsigned Penalty = 0; unsigned RemainingTokenColumns = 0; for (unsigned LineIndex = 0, EndIndex = Token->getLineCount(); LineIndex != EndIndex; ++LineIndex) { if (!DryRun) Token->replaceWhitespaceBefore(LineIndex, Whitespaces); unsigned TailOffset = 0; RemainingTokenColumns = Token->getLineLengthAfterSplit(LineIndex, TailOffset, StringRef::npos); while (RemainingTokenColumns > RemainingSpace) { BreakableToken::Split Split = Token->getSplit(LineIndex, TailOffset, ColumnLimit); if (Split.first == StringRef::npos) { // The last line's penalty is handled in addNextStateToQueue(). if (LineIndex < EndIndex - 1) Penalty += Style.PenaltyExcessCharacter * (RemainingTokenColumns - RemainingSpace); break; } assert(Split.first != 0); unsigned NewRemainingTokenColumns = Token->getLineLengthAfterSplit( LineIndex, TailOffset + Split.first + Split.second, StringRef::npos); // We can remove extra whitespace instead of breaking the line. if (RemainingTokenColumns + 1 - Split.second <= RemainingSpace) { RemainingTokenColumns = 0; if (!DryRun) Token->replaceWhitespace(LineIndex, TailOffset, Split, Whitespaces); break; } // When breaking before a tab character, it may be moved by a few columns, // but will still be expanded to the next tab stop, so we don't save any // columns. if (NewRemainingTokenColumns == RemainingTokenColumns) break; assert(NewRemainingTokenColumns < RemainingTokenColumns); if (!DryRun) Token->insertBreak(LineIndex, TailOffset, Split, Whitespaces); Penalty += Current.SplitPenalty; unsigned ColumnsUsed = Token->getLineLengthAfterSplit(LineIndex, TailOffset, Split.first); if (ColumnsUsed > ColumnLimit) { Penalty += Style.PenaltyExcessCharacter * (ColumnsUsed - ColumnLimit); } TailOffset += Split.first + Split.second; RemainingTokenColumns = NewRemainingTokenColumns; BreakInserted = true; } } State.Column = RemainingTokenColumns; if (BreakInserted) { // If we break the token inside a parameter list, we need to break before // the next parameter on all levels, so that the next parameter is clearly // visible. Line comments already introduce a break. if (Current.isNot(TT_LineComment)) { for (unsigned i = 0, e = State.Stack.size(); i != e; ++i) State.Stack[i].BreakBeforeParameter = true; } Penalty += Current.isStringLiteral() ? Style.PenaltyBreakString : Style.PenaltyBreakComment; State.Stack.back().LastSpace = StartColumn; } return Penalty; } unsigned ContinuationIndenter::getColumnLimit(const LineState &State) const { // In preprocessor directives reserve two chars for trailing " \" return Style.ColumnLimit - (State.Line->InPPDirective ? 2 : 0); } bool ContinuationIndenter::nextIsMultilineString(const LineState &State) { const FormatToken &Current = *State.NextToken; if (!Current.isStringLiteral() || Current.is(TT_ImplicitStringLiteral)) return false; // We never consider raw string literals "multiline" for the purpose of // AlwaysBreakBeforeMultilineStrings implementation as they are special-cased // (see TokenAnnotator::mustBreakBefore(). if (Current.TokenText.startswith("R\"")) return false; if (Current.IsMultiline) return true; if (Current.getNextNonComment() && Current.getNextNonComment()->isStringLiteral()) return true; // Implicit concatenation. if (Style.ColumnLimit != 0 && State.Column + Current.ColumnWidth + Current.UnbreakableTailLength > Style.ColumnLimit) return true; // String will be split. return false; } } // namespace format } // namespace clang Index: projects/clang380-import/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp =================================================================== --- projects/clang380-import/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp (revision 295858) +++ projects/clang380-import/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp (revision 295859) @@ -1,8544 +1,8580 @@ //===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP constructs ---------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// \file /// \brief This file implements semantic analysis for OpenMP directives and /// clauses. /// //===----------------------------------------------------------------------===// #include "TreeTransform.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclOpenMP.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtOpenMP.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" using namespace clang; //===----------------------------------------------------------------------===// // Stack of data-sharing attributes for variables //===----------------------------------------------------------------------===// namespace { /// \brief Default data sharing attributes, which can be applied to directive. enum DefaultDataSharingAttributes { DSA_unspecified = 0, /// \brief Data sharing attribute not specified. DSA_none = 1 << 0, /// \brief Default data sharing attribute 'none'. DSA_shared = 1 << 1 /// \brief Default data sharing attribute 'shared'. }; template struct MatchesAny { explicit MatchesAny(ArrayRef Arr) : Arr(std::move(Arr)) {} bool operator()(T Kind) { for (auto KindEl : Arr) if (KindEl == Kind) return true; return false; } private: ArrayRef Arr; }; struct MatchesAlways { MatchesAlways() {} template bool operator()(T) { return true; } }; typedef MatchesAny MatchesAnyClause; typedef MatchesAny MatchesAnyDirective; /// \brief Stack for tracking declarations used in OpenMP directives and /// clauses and their data-sharing attributes. class DSAStackTy { public: struct DSAVarData { OpenMPDirectiveKind DKind; OpenMPClauseKind CKind; DeclRefExpr *RefExpr; SourceLocation ImplicitDSALoc; DSAVarData() : DKind(OMPD_unknown), CKind(OMPC_unknown), RefExpr(nullptr), ImplicitDSALoc() {} }; public: struct MapInfo { Expr *RefExpr; }; private: struct DSAInfo { OpenMPClauseKind Attributes; DeclRefExpr *RefExpr; }; typedef llvm::SmallDenseMap DeclSAMapTy; typedef llvm::SmallDenseMap AlignedMapTy; typedef llvm::DenseMap LoopControlVariablesMapTy; typedef llvm::SmallDenseMap MappedDeclsTy; typedef llvm::StringMap> CriticalsWithHintsTy; struct SharingMapTy { DeclSAMapTy SharingMap; AlignedMapTy AlignedMap; MappedDeclsTy MappedDecls; LoopControlVariablesMapTy LCVMap; DefaultDataSharingAttributes DefaultAttr; SourceLocation DefaultAttrLoc; OpenMPDirectiveKind Directive; DeclarationNameInfo DirectiveName; Scope *CurScope; SourceLocation ConstructLoc; /// \brief first argument (Expr *) contains optional argument of the /// 'ordered' clause, the second one is true if the regions has 'ordered' /// clause, false otherwise. llvm::PointerIntPair OrderedRegion; bool NowaitRegion; bool CancelRegion; unsigned AssociatedLoops; SourceLocation InnerTeamsRegionLoc; SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name, Scope *CurScope, SourceLocation Loc) : SharingMap(), AlignedMap(), LCVMap(), DefaultAttr(DSA_unspecified), Directive(DKind), DirectiveName(std::move(Name)), CurScope(CurScope), ConstructLoc(Loc), OrderedRegion(), NowaitRegion(false), CancelRegion(false), AssociatedLoops(1), InnerTeamsRegionLoc() {} SharingMapTy() : SharingMap(), AlignedMap(), LCVMap(), DefaultAttr(DSA_unspecified), Directive(OMPD_unknown), DirectiveName(), CurScope(nullptr), ConstructLoc(), OrderedRegion(), NowaitRegion(false), CancelRegion(false), AssociatedLoops(1), InnerTeamsRegionLoc() {} }; typedef SmallVector StackTy; /// \brief Stack of used declaration and their data-sharing attributes. StackTy Stack; /// \brief true, if check for DSA must be from parent directive, false, if /// from current directive. OpenMPClauseKind ClauseKindMode; Sema &SemaRef; bool ForceCapturing; CriticalsWithHintsTy Criticals; typedef SmallVector::reverse_iterator reverse_iterator; DSAVarData getDSA(StackTy::reverse_iterator Iter, VarDecl *D); /// \brief Checks if the variable is a local for OpenMP region. bool isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter); public: explicit DSAStackTy(Sema &S) : Stack(1), ClauseKindMode(OMPC_unknown), SemaRef(S), ForceCapturing(false) {} bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; } void setClauseParsingMode(OpenMPClauseKind K) { ClauseKindMode = K; } bool isForceVarCapturing() const { return ForceCapturing; } void setForceVarCapturing(bool V) { ForceCapturing = V; } void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName, Scope *CurScope, SourceLocation Loc) { Stack.push_back(SharingMapTy(DKind, DirName, CurScope, Loc)); Stack.back().DefaultAttrLoc = Loc; } void pop() { assert(Stack.size() > 1 && "Data-sharing attributes stack is empty!"); Stack.pop_back(); } void addCriticalWithHint(OMPCriticalDirective *D, llvm::APSInt Hint) { Criticals[D->getDirectiveName().getAsString()] = std::make_pair(D, Hint); } const std::pair getCriticalWithHint(const DeclarationNameInfo &Name) const { auto I = Criticals.find(Name.getAsString()); if (I != Criticals.end()) return I->second; return std::make_pair(nullptr, llvm::APSInt()); } /// \brief If 'aligned' declaration for given variable \a D was not seen yet, /// add it and return NULL; otherwise return previous occurrence's expression /// for diagnostics. DeclRefExpr *addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE); /// \brief Register specified variable as loop control variable. void addLoopControlVariable(VarDecl *D); /// \brief Check if the specified variable is a loop control variable for /// current region. /// \return The index of the loop control variable in the list of associated /// for-loops (from outer to inner). unsigned isLoopControlVariable(VarDecl *D); /// \brief Check if the specified variable is a loop control variable for /// parent region. /// \return The index of the loop control variable in the list of associated /// for-loops (from outer to inner). unsigned isParentLoopControlVariable(VarDecl *D); /// \brief Get the loop control variable for the I-th loop (or nullptr) in /// parent directive. VarDecl *getParentLoopControlVariable(unsigned I); /// \brief Adds explicit data sharing attribute to the specified declaration. void addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A); /// \brief Returns data sharing attributes from top of the stack for the /// specified declaration. DSAVarData getTopDSA(VarDecl *D, bool FromParent); /// \brief Returns data-sharing attributes for the specified declaration. DSAVarData getImplicitDSA(VarDecl *D, bool FromParent); /// \brief Checks if the specified variables has data-sharing attributes which /// match specified \a CPred predicate in any directive which matches \a DPred /// predicate. template DSAVarData hasDSA(VarDecl *D, ClausesPredicate CPred, DirectivesPredicate DPred, bool FromParent); /// \brief Checks if the specified variables has data-sharing attributes which /// match specified \a CPred predicate in any innermost directive which /// matches \a DPred predicate. template DSAVarData hasInnermostDSA(VarDecl *D, ClausesPredicate CPred, DirectivesPredicate DPred, bool FromParent); /// \brief Checks if the specified variables has explicit data-sharing /// attributes which match specified \a CPred predicate at the specified /// OpenMP region. bool hasExplicitDSA(VarDecl *D, const llvm::function_ref &CPred, unsigned Level); /// \brief Returns true if the directive at level \Level matches in the /// specified \a DPred predicate. bool hasExplicitDirective( const llvm::function_ref &DPred, unsigned Level); /// \brief Finds a directive which matches specified \a DPred predicate. template bool hasDirective(NamedDirectivesPredicate DPred, bool FromParent); /// \brief Returns currently analyzed directive. OpenMPDirectiveKind getCurrentDirective() const { return Stack.back().Directive; } /// \brief Returns parent directive. OpenMPDirectiveKind getParentDirective() const { if (Stack.size() > 2) return Stack[Stack.size() - 2].Directive; return OMPD_unknown; } /// \brief Return the directive associated with the provided scope. OpenMPDirectiveKind getDirectiveForScope(const Scope *S) const; /// \brief Set default data sharing attribute to none. void setDefaultDSANone(SourceLocation Loc) { Stack.back().DefaultAttr = DSA_none; Stack.back().DefaultAttrLoc = Loc; } /// \brief Set default data sharing attribute to shared. void setDefaultDSAShared(SourceLocation Loc) { Stack.back().DefaultAttr = DSA_shared; Stack.back().DefaultAttrLoc = Loc; } DefaultDataSharingAttributes getDefaultDSA() const { return Stack.back().DefaultAttr; } SourceLocation getDefaultDSALocation() const { return Stack.back().DefaultAttrLoc; } /// \brief Checks if the specified variable is a threadprivate. bool isThreadPrivate(VarDecl *D) { DSAVarData DVar = getTopDSA(D, false); return isOpenMPThreadPrivate(DVar.CKind); } /// \brief Marks current region as ordered (it has an 'ordered' clause). void setOrderedRegion(bool IsOrdered, Expr *Param) { Stack.back().OrderedRegion.setInt(IsOrdered); Stack.back().OrderedRegion.setPointer(Param); } /// \brief Returns true, if parent region is ordered (has associated /// 'ordered' clause), false - otherwise. bool isParentOrderedRegion() const { if (Stack.size() > 2) return Stack[Stack.size() - 2].OrderedRegion.getInt(); return false; } /// \brief Returns optional parameter for the ordered region. Expr *getParentOrderedRegionParam() const { if (Stack.size() > 2) return Stack[Stack.size() - 2].OrderedRegion.getPointer(); return nullptr; } /// \brief Marks current region as nowait (it has a 'nowait' clause). void setNowaitRegion(bool IsNowait = true) { Stack.back().NowaitRegion = IsNowait; } /// \brief Returns true, if parent region is nowait (has associated /// 'nowait' clause), false - otherwise. bool isParentNowaitRegion() const { if (Stack.size() > 2) return Stack[Stack.size() - 2].NowaitRegion; return false; } /// \brief Marks parent region as cancel region. void setParentCancelRegion(bool Cancel = true) { if (Stack.size() > 2) Stack[Stack.size() - 2].CancelRegion = Stack[Stack.size() - 2].CancelRegion || Cancel; } /// \brief Return true if current region has inner cancel construct. bool isCancelRegion() const { return Stack.back().CancelRegion; } /// \brief Set collapse value for the region. void setAssociatedLoops(unsigned Val) { Stack.back().AssociatedLoops = Val; } /// \brief Return collapse value for region. unsigned getAssociatedLoops() const { return Stack.back().AssociatedLoops; } /// \brief Marks current target region as one with closely nested teams /// region. void setParentTeamsRegionLoc(SourceLocation TeamsRegionLoc) { if (Stack.size() > 2) Stack[Stack.size() - 2].InnerTeamsRegionLoc = TeamsRegionLoc; } /// \brief Returns true, if current region has closely nested teams region. bool hasInnerTeamsRegion() const { return getInnerTeamsRegionLoc().isValid(); } /// \brief Returns location of the nested teams region (if any). SourceLocation getInnerTeamsRegionLoc() const { if (Stack.size() > 1) return Stack.back().InnerTeamsRegionLoc; return SourceLocation(); } Scope *getCurScope() const { return Stack.back().CurScope; } Scope *getCurScope() { return Stack.back().CurScope; } SourceLocation getConstructLoc() { return Stack.back().ConstructLoc; } MapInfo getMapInfoForVar(VarDecl *VD) { MapInfo VarMI = {0}; for (auto Cnt = Stack.size() - 1; Cnt > 0; --Cnt) { if (Stack[Cnt].MappedDecls.count(VD)) { VarMI = Stack[Cnt].MappedDecls[VD]; break; } } return VarMI; } void addMapInfoForVar(VarDecl *VD, MapInfo MI) { if (Stack.size() > 1) { Stack.back().MappedDecls[VD] = MI; } } MapInfo IsMappedInCurrentRegion(VarDecl *VD) { assert(Stack.size() > 1 && "Target level is 0"); MapInfo VarMI = {0}; if (Stack.size() > 1 && Stack.back().MappedDecls.count(VD)) { VarMI = Stack.back().MappedDecls[VD]; } return VarMI; } }; bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) { return isOpenMPParallelDirective(DKind) || DKind == OMPD_task || isOpenMPTeamsDirective(DKind) || DKind == OMPD_unknown || isOpenMPTaskLoopDirective(DKind); } } // namespace DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, VarDecl *D) { D = D->getCanonicalDecl(); DSAVarData DVar; if (Iter == std::prev(Stack.rend())) { // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a region but not in construct] // File-scope or namespace-scope variables referenced in called routines // in the region are shared unless they appear in a threadprivate // directive. if (!D->isFunctionOrMethodVarDecl() && !isa(D)) DVar.CKind = OMPC_shared; // OpenMP [2.9.1.2, Data-sharing Attribute Rules for Variables Referenced // in a region but not in construct] // Variables with static storage duration that are declared in called // routines in the region are shared. if (D->hasGlobalStorage()) DVar.CKind = OMPC_shared; return DVar; } DVar.DKind = Iter->Directive; // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.1] // Variables with automatic storage duration that are declared in a scope // inside the construct are private. if (isOpenMPLocal(D, Iter) && D->isLocalVarDecl() && (D->getStorageClass() == SC_Auto || D->getStorageClass() == SC_None)) { DVar.CKind = OMPC_private; return DVar; } // Explicitly specified attributes and local variables with predetermined // attributes. if (Iter->SharingMap.count(D)) { DVar.RefExpr = Iter->SharingMap[D].RefExpr; DVar.CKind = Iter->SharingMap[D].Attributes; DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; return DVar; } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, implicitly determined, p.1] // In a parallel or task construct, the data-sharing attributes of these // variables are determined by the default clause, if present. switch (Iter->DefaultAttr) { case DSA_shared: DVar.CKind = OMPC_shared; DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; return DVar; case DSA_none: return DVar; case DSA_unspecified: // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, implicitly determined, p.2] // In a parallel construct, if no default clause is present, these // variables are shared. DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; if (isOpenMPParallelDirective(DVar.DKind) || isOpenMPTeamsDirective(DVar.DKind)) { DVar.CKind = OMPC_shared; return DVar; } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, implicitly determined, p.4] // In a task construct, if no default clause is present, a variable that in // the enclosing context is determined to be shared by all implicit tasks // bound to the current team is shared. if (DVar.DKind == OMPD_task) { DSAVarData DVarTemp; for (StackTy::reverse_iterator I = std::next(Iter), EE = Stack.rend(); I != EE; ++I) { // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables // Referenced // in a Construct, implicitly determined, p.6] // In a task construct, if no default clause is present, a variable // whose data-sharing attribute is not determined by the rules above is // firstprivate. DVarTemp = getDSA(I, D); if (DVarTemp.CKind != OMPC_shared) { DVar.RefExpr = nullptr; DVar.DKind = OMPD_task; DVar.CKind = OMPC_firstprivate; return DVar; } if (isParallelOrTaskRegion(I->Directive)) break; } DVar.DKind = OMPD_task; DVar.CKind = (DVarTemp.CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared; return DVar; } } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, implicitly determined, p.3] // For constructs other than task, if no default clause is present, these // variables inherit their data-sharing attributes from the enclosing // context. return getDSA(std::next(Iter), D); } DeclRefExpr *DSAStackTy::addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE) { assert(Stack.size() > 1 && "Data sharing attributes stack is empty"); D = D->getCanonicalDecl(); auto It = Stack.back().AlignedMap.find(D); if (It == Stack.back().AlignedMap.end()) { assert(NewDE && "Unexpected nullptr expr to be added into aligned map"); Stack.back().AlignedMap[D] = NewDE; return nullptr; } else { assert(It->second && "Unexpected nullptr expr in the aligned map"); return It->second; } return nullptr; } void DSAStackTy::addLoopControlVariable(VarDecl *D) { assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); D = D->getCanonicalDecl(); Stack.back().LCVMap.insert(std::make_pair(D, Stack.back().LCVMap.size() + 1)); } unsigned DSAStackTy::isLoopControlVariable(VarDecl *D) { assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); D = D->getCanonicalDecl(); return Stack.back().LCVMap.count(D) > 0 ? Stack.back().LCVMap[D] : 0; } unsigned DSAStackTy::isParentLoopControlVariable(VarDecl *D) { assert(Stack.size() > 2 && "Data-sharing attributes stack is empty"); D = D->getCanonicalDecl(); return Stack[Stack.size() - 2].LCVMap.count(D) > 0 ? Stack[Stack.size() - 2].LCVMap[D] : 0; } VarDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) { assert(Stack.size() > 2 && "Data-sharing attributes stack is empty"); if (Stack[Stack.size() - 2].LCVMap.size() < I) return nullptr; for (auto &Pair : Stack[Stack.size() - 2].LCVMap) { if (Pair.second == I) return Pair.first; } return nullptr; } void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) { D = D->getCanonicalDecl(); if (A == OMPC_threadprivate) { Stack[0].SharingMap[D].Attributes = A; Stack[0].SharingMap[D].RefExpr = E; } else { assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); Stack.back().SharingMap[D].Attributes = A; Stack.back().SharingMap[D].RefExpr = E; } } bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) { D = D->getCanonicalDecl(); if (Stack.size() > 2) { reverse_iterator I = Iter, E = std::prev(Stack.rend()); Scope *TopScope = nullptr; while (I != E && !isParallelOrTaskRegion(I->Directive)) { ++I; } if (I == E) return false; TopScope = I->CurScope ? I->CurScope->getParent() : nullptr; Scope *CurScope = getCurScope(); while (CurScope != TopScope && !CurScope->isDeclScope(D)) { CurScope = CurScope->getParent(); } return CurScope != TopScope; } return false; } /// \brief Build a variable declaration for OpenMP loop iteration variable. static VarDecl *buildVarDecl(Sema &SemaRef, SourceLocation Loc, QualType Type, StringRef Name, const AttrVec *Attrs = nullptr) { DeclContext *DC = SemaRef.CurContext; IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name); TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc); VarDecl *Decl = VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type, TInfo, SC_None); if (Attrs) { for (specific_attr_iterator I(Attrs->begin()), E(Attrs->end()); I != E; ++I) Decl->addAttr(*I); } Decl->setImplicit(); return Decl; } static DeclRefExpr *buildDeclRefExpr(Sema &S, VarDecl *D, QualType Ty, SourceLocation Loc, bool RefersToCapture = false) { D->setReferenced(); D->markUsed(S.Context); return DeclRefExpr::Create(S.getASTContext(), NestedNameSpecifierLoc(), SourceLocation(), D, RefersToCapture, Loc, Ty, VK_LValue); } DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { D = D->getCanonicalDecl(); DSAVarData DVar; // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.1] // Variables appearing in threadprivate directives are threadprivate. if ((D->getTLSKind() != VarDecl::TLS_None && !(D->hasAttr() && SemaRef.getLangOpts().OpenMPUseTLS && SemaRef.getASTContext().getTargetInfo().isTLSSupported())) || (D->getStorageClass() == SC_Register && D->hasAttr() && !D->isLocalVarDecl())) { addDSA(D, buildDeclRefExpr(SemaRef, D, D->getType().getNonReferenceType(), D->getLocation()), OMPC_threadprivate); } if (Stack[0].SharingMap.count(D)) { DVar.RefExpr = Stack[0].SharingMap[D].RefExpr; DVar.CKind = OMPC_threadprivate; return DVar; } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.4] // Static data members are shared. // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.7] // Variables with static storage duration that are declared in a scope // inside the construct are shared. if (D->isStaticDataMember()) { DSAVarData DVarTemp = hasDSA(D, isOpenMPPrivate, MatchesAlways(), FromParent); if (DVarTemp.CKind != OMPC_unknown && DVarTemp.RefExpr) return DVar; DVar.CKind = OMPC_shared; return DVar; } QualType Type = D->getType().getNonReferenceType().getCanonicalType(); bool IsConstant = Type.isConstant(SemaRef.getASTContext()); Type = SemaRef.getASTContext().getBaseElementType(Type); // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.6] // Variables with const qualified type having no mutable member are // shared. CXXRecordDecl *RD = SemaRef.getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr; if (auto *CTSD = dyn_cast_or_null(RD)) if (auto *CTD = CTSD->getSpecializedTemplate()) RD = CTD->getTemplatedDecl(); if (IsConstant && - !(SemaRef.getLangOpts().CPlusPlus && RD && RD->hasMutableFields())) { + !(SemaRef.getLangOpts().CPlusPlus && RD && RD->hasDefinition() && + RD->hasMutableFields())) { // Variables with const-qualified type having no mutable member may be // listed in a firstprivate clause, even if they are static data members. DSAVarData DVarTemp = hasDSA(D, MatchesAnyClause(OMPC_firstprivate), MatchesAlways(), FromParent); if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr) return DVar; DVar.CKind = OMPC_shared; return DVar; } // Explicitly specified attributes and local variables with predetermined // attributes. auto StartI = std::next(Stack.rbegin()); auto EndI = std::prev(Stack.rend()); if (FromParent && StartI != EndI) { StartI = std::next(StartI); } auto I = std::prev(StartI); if (I->SharingMap.count(D)) { DVar.RefExpr = I->SharingMap[D].RefExpr; DVar.CKind = I->SharingMap[D].Attributes; DVar.ImplicitDSALoc = I->DefaultAttrLoc; } return DVar; } DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(VarDecl *D, bool FromParent) { D = D->getCanonicalDecl(); auto StartI = Stack.rbegin(); auto EndI = std::prev(Stack.rend()); if (FromParent && StartI != EndI) { StartI = std::next(StartI); } return getDSA(StartI, D); } template DSAStackTy::DSAVarData DSAStackTy::hasDSA(VarDecl *D, ClausesPredicate CPred, DirectivesPredicate DPred, bool FromParent) { D = D->getCanonicalDecl(); auto StartI = std::next(Stack.rbegin()); auto EndI = std::prev(Stack.rend()); if (FromParent && StartI != EndI) { StartI = std::next(StartI); } for (auto I = StartI, EE = EndI; I != EE; ++I) { if (!DPred(I->Directive) && !isParallelOrTaskRegion(I->Directive)) continue; DSAVarData DVar = getDSA(I, D); if (CPred(DVar.CKind)) return DVar; } return DSAVarData(); } template DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA(VarDecl *D, ClausesPredicate CPred, DirectivesPredicate DPred, bool FromParent) { D = D->getCanonicalDecl(); auto StartI = std::next(Stack.rbegin()); auto EndI = std::prev(Stack.rend()); if (FromParent && StartI != EndI) { StartI = std::next(StartI); } for (auto I = StartI, EE = EndI; I != EE; ++I) { if (!DPred(I->Directive)) break; DSAVarData DVar = getDSA(I, D); if (CPred(DVar.CKind)) return DVar; return DSAVarData(); } return DSAVarData(); } bool DSAStackTy::hasExplicitDSA( VarDecl *D, const llvm::function_ref &CPred, unsigned Level) { if (CPred(ClauseKindMode)) return true; if (isClauseParsingMode()) ++Level; D = D->getCanonicalDecl(); auto StartI = Stack.rbegin(); auto EndI = std::prev(Stack.rend()); if (std::distance(StartI, EndI) <= (int)Level) return false; std::advance(StartI, Level); return (StartI->SharingMap.count(D) > 0) && StartI->SharingMap[D].RefExpr && CPred(StartI->SharingMap[D].Attributes); } bool DSAStackTy::hasExplicitDirective( const llvm::function_ref &DPred, unsigned Level) { if (isClauseParsingMode()) ++Level; auto StartI = Stack.rbegin(); auto EndI = std::prev(Stack.rend()); if (std::distance(StartI, EndI) <= (int)Level) return false; std::advance(StartI, Level); return DPred(StartI->Directive); } template bool DSAStackTy::hasDirective(NamedDirectivesPredicate DPred, bool FromParent) { auto StartI = std::next(Stack.rbegin()); auto EndI = std::prev(Stack.rend()); if (FromParent && StartI != EndI) { StartI = std::next(StartI); } for (auto I = StartI, EE = EndI; I != EE; ++I) { if (DPred(I->Directive, I->DirectiveName, I->ConstructLoc)) return true; } return false; } OpenMPDirectiveKind DSAStackTy::getDirectiveForScope(const Scope *S) const { for (auto I = Stack.rbegin(), EE = Stack.rend(); I != EE; ++I) if (I->CurScope == S) return I->Directive; return OMPD_unknown; } void Sema::InitDataSharingAttributesStack() { VarDataSharingAttributesStack = new DSAStackTy(*this); } #define DSAStack static_cast(VarDataSharingAttributesStack) bool Sema::IsOpenMPCapturedByRef(VarDecl *VD, const CapturedRegionScopeInfo *RSI) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); auto &Ctx = getASTContext(); bool IsByRef = true; // Find the directive that is associated with the provided scope. auto DKind = DSAStack->getDirectiveForScope(RSI->TheScope); auto Ty = VD->getType(); if (isOpenMPTargetDirective(DKind)) { // This table summarizes how a given variable should be passed to the device // given its type and the clauses where it appears. This table is based on // the description in OpenMP 4.5 [2.10.4, target Construct] and // OpenMP 4.5 [2.15.5, Data-mapping Attribute Rules and Clauses]. // // ========================================================================= // | type | defaultmap | pvt | first | is_device_ptr | map | res. | // | |(tofrom:scalar)| | pvt | | | | // ========================================================================= // | scl | | | | - | | bycopy| // | scl | | - | x | - | - | bycopy| // | scl | | x | - | - | - | null | // | scl | x | | | - | | byref | // | scl | x | - | x | - | - | bycopy| // | scl | x | x | - | - | - | null | // | scl | | - | - | - | x | byref | // | scl | x | - | - | - | x | byref | // // | agg | n.a. | | | - | | byref | // | agg | n.a. | - | x | - | - | byref | // | agg | n.a. | x | - | - | - | null | // | agg | n.a. | - | - | - | x | byref | // | agg | n.a. | - | - | - | x[] | byref | // // | ptr | n.a. | | | - | | bycopy| // | ptr | n.a. | - | x | - | - | bycopy| // | ptr | n.a. | x | - | - | - | null | // | ptr | n.a. | - | - | - | x | byref | // | ptr | n.a. | - | - | - | x[] | bycopy| // | ptr | n.a. | - | - | x | | bycopy| // | ptr | n.a. | - | - | x | x | bycopy| // | ptr | n.a. | - | - | x | x[] | bycopy| // ========================================================================= // Legend: // scl - scalar // ptr - pointer // agg - aggregate // x - applies // - - invalid in this combination // [] - mapped with an array section // byref - should be mapped by reference // byval - should be mapped by value // null - initialize a local variable to null on the device // // Observations: // - All scalar declarations that show up in a map clause have to be passed // by reference, because they may have been mapped in the enclosing data // environment. // - If the scalar value does not fit the size of uintptr, it has to be // passed by reference, regardless the result in the table above. // - For pointers mapped by value that have either an implicit map or an // array section, the runtime library may pass the NULL value to the // device instead of the value passed to it by the compiler. // FIXME: Right now, only implicit maps are implemented. Properly mapping // values requires having the map, private, and firstprivate clauses SEMA // and parsing in place, which we don't yet. if (Ty->isReferenceType()) Ty = Ty->castAs()->getPointeeType(); IsByRef = !Ty->isScalarType(); } // When passing data by value, we need to make sure it fits the uintptr size // and alignment, because the runtime library only deals with uintptr types. // If it does not fit the uintptr size, we need to pass the data by reference // instead. if (!IsByRef && (Ctx.getTypeSizeInChars(Ty) > Ctx.getTypeSizeInChars(Ctx.getUIntPtrType()) || Ctx.getDeclAlign(VD) > Ctx.getTypeAlignInChars(Ctx.getUIntPtrType()))) IsByRef = true; return IsByRef; } bool Sema::IsOpenMPCapturedVar(VarDecl *VD) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); VD = VD->getCanonicalDecl(); // If we are attempting to capture a global variable in a directive with // 'target' we return true so that this global is also mapped to the device. // // FIXME: If the declaration is enclosed in a 'declare target' directive, // then it should not be captured. Therefore, an extra check has to be // inserted here once support for 'declare target' is added. // if (!VD->hasLocalStorage()) { if (DSAStack->getCurrentDirective() == OMPD_target && !DSAStack->isClauseParsingMode()) { return true; } if (DSAStack->getCurScope() && DSAStack->hasDirective( [](OpenMPDirectiveKind K, const DeclarationNameInfo &DNI, SourceLocation Loc) -> bool { return isOpenMPTargetDirective(K); }, false)) { return true; } } if (DSAStack->getCurrentDirective() != OMPD_unknown && (!DSAStack->isClauseParsingMode() || DSAStack->getParentDirective() != OMPD_unknown)) { if (DSAStack->isLoopControlVariable(VD) || (VD->hasLocalStorage() && isParallelOrTaskRegion(DSAStack->getCurrentDirective())) || DSAStack->isForceVarCapturing()) return true; auto DVarPrivate = DSAStack->getTopDSA(VD, DSAStack->isClauseParsingMode()); if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind)) return true; DVarPrivate = DSAStack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(), DSAStack->isClauseParsingMode()); return DVarPrivate.CKind != OMPC_unknown; } return false; } bool Sema::isOpenMPPrivateVar(VarDecl *VD, unsigned Level) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); return DSAStack->hasExplicitDSA( VD, [](OpenMPClauseKind K) -> bool { return K == OMPC_private; }, Level); } bool Sema::isOpenMPTargetCapturedVar(VarDecl *VD, unsigned Level) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); // Return true if the current level is no longer enclosed in a target region. return !VD->hasLocalStorage() && DSAStack->hasExplicitDirective(isOpenMPTargetDirective, Level); } void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; } void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName, Scope *CurScope, SourceLocation Loc) { DSAStack->push(DKind, DirName, CurScope, Loc); PushExpressionEvaluationContext(PotentiallyEvaluated); } void Sema::StartOpenMPClause(OpenMPClauseKind K) { DSAStack->setClauseParsingMode(K); } void Sema::EndOpenMPClause() { DSAStack->setClauseParsingMode(/*K=*/OMPC_unknown); } void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { // OpenMP [2.14.3.5, Restrictions, C/C++, p.1] // A variable of class type (or array thereof) that appears in a lastprivate // clause requires an accessible, unambiguous default constructor for the // class type, unless the list item is also specified in a firstprivate // clause. if (auto D = dyn_cast_or_null(CurDirective)) { for (auto *C : D->clauses()) { if (auto *Clause = dyn_cast(C)) { SmallVector PrivateCopies; for (auto *DE : Clause->varlists()) { if (DE->isValueDependent() || DE->isTypeDependent()) { PrivateCopies.push_back(nullptr); continue; } auto *VD = cast(cast(DE)->getDecl()); QualType Type = VD->getType().getNonReferenceType(); auto DVar = DSAStack->getTopDSA(VD, false); if (DVar.CKind == OMPC_lastprivate) { // Generate helper private variable and initialize it with the // default value. The address of the original variable is replaced // by the address of the new private variable in CodeGen. This new // variable is not added to IdResolver, so the code in the OpenMP // region uses original variable for proper diagnostics. auto *VDPrivate = buildVarDecl( *this, DE->getExprLoc(), Type.getUnqualifiedType(), VD->getName(), VD->hasAttrs() ? &VD->getAttrs() : nullptr); ActOnUninitializedDecl(VDPrivate, /*TypeMayContainAuto=*/false); if (VDPrivate->isInvalidDecl()) continue; PrivateCopies.push_back(buildDeclRefExpr( *this, VDPrivate, DE->getType(), DE->getExprLoc())); } else { // The variable is also a firstprivate, so initialization sequence // for private copy is generated already. PrivateCopies.push_back(nullptr); } } // Set initializers to private copies if no errors were found. if (PrivateCopies.size() == Clause->varlist_size()) { Clause->setPrivateCopies(PrivateCopies); } } } } DSAStack->pop(); DiscardCleanupsInEvaluationContext(); PopExpressionEvaluationContext(); } static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, Expr *NumIterations, Sema &SemaRef, Scope *S); namespace { class VarDeclFilterCCC : public CorrectionCandidateCallback { private: Sema &SemaRef; public: explicit VarDeclFilterCCC(Sema &S) : SemaRef(S) {} bool ValidateCandidate(const TypoCorrection &Candidate) override { NamedDecl *ND = Candidate.getCorrectionDecl(); if (VarDecl *VD = dyn_cast_or_null(ND)) { return VD->hasGlobalStorage() && SemaRef.isDeclInScope(ND, SemaRef.getCurLexicalContext(), SemaRef.getCurScope()); } return false; } }; } // namespace ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, CXXScopeSpec &ScopeSpec, const DeclarationNameInfo &Id) { LookupResult Lookup(*this, Id, LookupOrdinaryName); LookupParsedName(Lookup, CurScope, &ScopeSpec, true); if (Lookup.isAmbiguous()) return ExprError(); VarDecl *VD; if (!Lookup.isSingleResult()) { if (TypoCorrection Corrected = CorrectTypo( Id, LookupOrdinaryName, CurScope, nullptr, llvm::make_unique(*this), CTK_ErrorRecovery)) { diagnoseTypo(Corrected, PDiag(Lookup.empty() ? diag::err_undeclared_var_use_suggest : diag::err_omp_expected_var_arg_suggest) << Id.getName()); VD = Corrected.getCorrectionDeclAs(); } else { Diag(Id.getLoc(), Lookup.empty() ? diag::err_undeclared_var_use : diag::err_omp_expected_var_arg) << Id.getName(); return ExprError(); } } else { if (!(VD = Lookup.getAsSingle())) { Diag(Id.getLoc(), diag::err_omp_expected_var_arg) << Id.getName(); Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at); return ExprError(); } } Lookup.suppressDiagnostics(); // OpenMP [2.9.2, Syntax, C/C++] // Variables must be file-scope, namespace-scope, or static block-scope. if (!VD->hasGlobalStorage()) { Diag(Id.getLoc(), diag::err_omp_global_var_arg) << getOpenMPDirectiveName(OMPD_threadprivate) << !VD->isStaticLocal(); bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; return ExprError(); } VarDecl *CanonicalVD = VD->getCanonicalDecl(); NamedDecl *ND = cast(CanonicalVD); // OpenMP [2.9.2, Restrictions, C/C++, p.2] // A threadprivate directive for file-scope variables must appear outside // any definition or declaration. if (CanonicalVD->getDeclContext()->isTranslationUnit() && !getCurLexicalContext()->isTranslationUnit()) { Diag(Id.getLoc(), diag::err_omp_var_scope) << getOpenMPDirectiveName(OMPD_threadprivate) << VD; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; return ExprError(); } // OpenMP [2.9.2, Restrictions, C/C++, p.3] // A threadprivate directive for static class member variables must appear // in the class definition, in the same scope in which the member // variables are declared. if (CanonicalVD->isStaticDataMember() && !CanonicalVD->getDeclContext()->Equals(getCurLexicalContext())) { Diag(Id.getLoc(), diag::err_omp_var_scope) << getOpenMPDirectiveName(OMPD_threadprivate) << VD; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; return ExprError(); } // OpenMP [2.9.2, Restrictions, C/C++, p.4] // A threadprivate directive for namespace-scope variables must appear // outside any definition or declaration other than the namespace // definition itself. if (CanonicalVD->getDeclContext()->isNamespace() && (!getCurLexicalContext()->isFileContext() || !getCurLexicalContext()->Encloses(CanonicalVD->getDeclContext()))) { Diag(Id.getLoc(), diag::err_omp_var_scope) << getOpenMPDirectiveName(OMPD_threadprivate) << VD; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; return ExprError(); } // OpenMP [2.9.2, Restrictions, C/C++, p.6] // A threadprivate directive for static block-scope variables must appear // in the scope of the variable and not in a nested scope. if (CanonicalVD->isStaticLocal() && CurScope && !isDeclInScope(ND, getCurLexicalContext(), CurScope)) { Diag(Id.getLoc(), diag::err_omp_var_scope) << getOpenMPDirectiveName(OMPD_threadprivate) << VD; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; return ExprError(); } // OpenMP [2.9.2, Restrictions, C/C++, p.2-6] // A threadprivate directive must lexically precede all references to any // of the variables in its list. if (VD->isUsed() && !DSAStack->isThreadPrivate(VD)) { Diag(Id.getLoc(), diag::err_omp_var_used) << getOpenMPDirectiveName(OMPD_threadprivate) << VD; return ExprError(); } QualType ExprType = VD->getType().getNonReferenceType(); ExprResult DE = buildDeclRefExpr(*this, VD, ExprType, Id.getLoc()); return DE; } Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective(SourceLocation Loc, ArrayRef VarList) { if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, VarList)) { CurContext->addDecl(D); return DeclGroupPtrTy::make(DeclGroupRef(D)); } return DeclGroupPtrTy(); } namespace { class LocalVarRefChecker : public ConstStmtVisitor { Sema &SemaRef; public: bool VisitDeclRefExpr(const DeclRefExpr *E) { if (auto VD = dyn_cast(E->getDecl())) { if (VD->hasLocalStorage()) { SemaRef.Diag(E->getLocStart(), diag::err_omp_local_var_in_threadprivate_init) << E->getSourceRange(); SemaRef.Diag(VD->getLocation(), diag::note_defined_here) << VD << VD->getSourceRange(); return true; } } return false; } bool VisitStmt(const Stmt *S) { for (auto Child : S->children()) { if (Child && Visit(Child)) return true; } return false; } explicit LocalVarRefChecker(Sema &SemaRef) : SemaRef(SemaRef) {} }; } // namespace OMPThreadPrivateDecl * Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef VarList) { SmallVector Vars; for (auto &RefExpr : VarList) { DeclRefExpr *DE = cast(RefExpr); VarDecl *VD = cast(DE->getDecl()); SourceLocation ILoc = DE->getExprLoc(); QualType QType = VD->getType(); if (QType->isDependentType() || QType->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); continue; } // OpenMP [2.9.2, Restrictions, C/C++, p.10] // A threadprivate variable must not have an incomplete type. if (RequireCompleteType(ILoc, VD->getType(), diag::err_omp_threadprivate_incomplete_type)) { continue; } // OpenMP [2.9.2, Restrictions, C/C++, p.10] // A threadprivate variable must not have a reference type. if (VD->getType()->isReferenceType()) { Diag(ILoc, diag::err_omp_ref_type_arg) << getOpenMPDirectiveName(OMPD_threadprivate) << VD->getType(); bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; continue; } // Check if this is a TLS variable. If TLS is not being supported, produce // the corresponding diagnostic. if ((VD->getTLSKind() != VarDecl::TLS_None && !(VD->hasAttr() && getLangOpts().OpenMPUseTLS && getASTContext().getTargetInfo().isTLSSupported())) || (VD->getStorageClass() == SC_Register && VD->hasAttr() && !VD->isLocalVarDecl())) { Diag(ILoc, diag::err_omp_var_thread_local) << VD << ((VD->getTLSKind() != VarDecl::TLS_None) ? 0 : 1); bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; continue; } // Check if initial value of threadprivate variable reference variable with // local storage (it is not supported by runtime). if (auto Init = VD->getAnyInitializer()) { LocalVarRefChecker Checker(*this); if (Checker.Visit(Init)) continue; } Vars.push_back(RefExpr); DSAStack->addDSA(VD, DE, OMPC_threadprivate); VD->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit( Context, SourceRange(Loc, Loc))); if (auto *ML = Context.getASTMutationListener()) ML->DeclarationMarkedOpenMPThreadPrivate(VD); } OMPThreadPrivateDecl *D = nullptr; if (!Vars.empty()) { D = OMPThreadPrivateDecl::Create(Context, getCurLexicalContext(), Loc, Vars); D->setAccess(AS_public); } return D; } static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack, const VarDecl *VD, DSAStackTy::DSAVarData DVar, bool IsLoopIterVar = false) { if (DVar.RefExpr) { SemaRef.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) << getOpenMPClauseName(DVar.CKind); return; } enum { PDSA_StaticMemberShared, PDSA_StaticLocalVarShared, PDSA_LoopIterVarPrivate, PDSA_LoopIterVarLinear, PDSA_LoopIterVarLastprivate, PDSA_ConstVarShared, PDSA_GlobalVarShared, PDSA_TaskVarFirstprivate, PDSA_LocalVarPrivate, PDSA_Implicit } Reason = PDSA_Implicit; bool ReportHint = false; auto ReportLoc = VD->getLocation(); if (IsLoopIterVar) { if (DVar.CKind == OMPC_private) Reason = PDSA_LoopIterVarPrivate; else if (DVar.CKind == OMPC_lastprivate) Reason = PDSA_LoopIterVarLastprivate; else Reason = PDSA_LoopIterVarLinear; } else if (DVar.DKind == OMPD_task && DVar.CKind == OMPC_firstprivate) { Reason = PDSA_TaskVarFirstprivate; ReportLoc = DVar.ImplicitDSALoc; } else if (VD->isStaticLocal()) Reason = PDSA_StaticLocalVarShared; else if (VD->isStaticDataMember()) Reason = PDSA_StaticMemberShared; else if (VD->isFileVarDecl()) Reason = PDSA_GlobalVarShared; else if (VD->getType().isConstant(SemaRef.getASTContext())) Reason = PDSA_ConstVarShared; else if (VD->isLocalVarDecl() && DVar.CKind == OMPC_private) { ReportHint = true; Reason = PDSA_LocalVarPrivate; } if (Reason != PDSA_Implicit) { SemaRef.Diag(ReportLoc, diag::note_omp_predetermined_dsa) << Reason << ReportHint << getOpenMPDirectiveName(Stack->getCurrentDirective()); } else if (DVar.ImplicitDSALoc.isValid()) { SemaRef.Diag(DVar.ImplicitDSALoc, diag::note_omp_implicit_dsa) << getOpenMPClauseName(DVar.CKind); } } namespace { class DSAAttrChecker : public StmtVisitor { DSAStackTy *Stack; Sema &SemaRef; bool ErrorFound; CapturedStmt *CS; llvm::SmallVector ImplicitFirstprivate; llvm::DenseMap VarsWithInheritedDSA; public: void VisitDeclRefExpr(DeclRefExpr *E) { if (auto *VD = dyn_cast(E->getDecl())) { // Skip internally declared variables. if (VD->isLocalVarDecl() && !CS->capturesVariable(VD)) return; auto DVar = Stack->getTopDSA(VD, false); // Check if the variable has explicit DSA set and stop analysis if it so. if (DVar.RefExpr) return; auto ELoc = E->getExprLoc(); auto DKind = Stack->getCurrentDirective(); // The default(none) clause requires that each variable that is referenced // in the construct, and does not have a predetermined data-sharing // attribute, must have its data-sharing attribute explicitly determined // by being listed in a data-sharing attribute clause. if (DVar.CKind == OMPC_unknown && Stack->getDefaultDSA() == DSA_none && isParallelOrTaskRegion(DKind) && VarsWithInheritedDSA.count(VD) == 0) { VarsWithInheritedDSA[VD] = E; return; } // OpenMP [2.9.3.6, Restrictions, p.2] // A list item that appears in a reduction clause of the innermost // enclosing worksharing or parallel construct may not be accessed in an // explicit task. DVar = Stack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction), [](OpenMPDirectiveKind K) -> bool { return isOpenMPParallelDirective(K) || isOpenMPWorksharingDirective(K) || isOpenMPTeamsDirective(K); }, false); if (DKind == OMPD_task && DVar.CKind == OMPC_reduction) { ErrorFound = true; SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task); ReportOriginalDSA(SemaRef, Stack, VD, DVar); return; } // Define implicit data-sharing attributes for task. DVar = Stack->getImplicitDSA(VD, false); if (DKind == OMPD_task && DVar.CKind != OMPC_shared) ImplicitFirstprivate.push_back(E); } } void VisitOMPExecutableDirective(OMPExecutableDirective *S) { for (auto *C : S->clauses()) { // Skip analysis of arguments of implicitly defined firstprivate clause // for task directives. if (C && (!isa(C) || C->getLocStart().isValid())) for (auto *CC : C->children()) { if (CC) Visit(CC); } } } void VisitStmt(Stmt *S) { for (auto *C : S->children()) { if (C && !isa(C)) Visit(C); } } bool isErrorFound() { return ErrorFound; } ArrayRef getImplicitFirstprivate() { return ImplicitFirstprivate; } llvm::DenseMap &getVarsWithInheritedDSA() { return VarsWithInheritedDSA; } DSAAttrChecker(DSAStackTy *S, Sema &SemaRef, CapturedStmt *CS) : Stack(S), SemaRef(SemaRef), ErrorFound(false), CS(CS) {} }; } // namespace void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { switch (DKind) { case OMPD_parallel: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); Sema::CapturedParamNameType Params[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), std::make_pair(".bound_tid.", KmpInt32PtrTy), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_simd: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_for: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_for_simd: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_sections: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_section: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_single: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_master: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_critical: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_parallel_for: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); Sema::CapturedParamNameType Params[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), std::make_pair(".bound_tid.", KmpInt32PtrTy), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_parallel_for_simd: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); Sema::CapturedParamNameType Params[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), std::make_pair(".bound_tid.", KmpInt32PtrTy), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_parallel_sections: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); Sema::CapturedParamNameType Params[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), std::make_pair(".bound_tid.", KmpInt32PtrTy), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_task: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); QualType Args[] = {Context.VoidPtrTy.withConst().withRestrict()}; FunctionProtoType::ExtProtoInfo EPI; EPI.Variadic = true; QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI); Sema::CapturedParamNameType Params[] = { std::make_pair(".global_tid.", KmpInt32Ty), std::make_pair(".part_id.", KmpInt32Ty), std::make_pair(".privates.", Context.VoidPtrTy.withConst().withRestrict()), std::make_pair( ".copy_fn.", Context.getPointerType(CopyFnType).withConst().withRestrict()), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); // Mark this captured region as inlined, because we don't use outlined // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( Context, AlwaysInlineAttr::Keyword_forceinline, SourceRange())); break; } case OMPD_ordered: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_atomic: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_target_data: case OMPD_target: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_teams: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); Sema::CapturedParamNameType Params[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), std::make_pair(".bound_tid.", KmpInt32PtrTy), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_taskgroup: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_taskloop: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_taskloop_simd: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_distribute: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } case OMPD_threadprivate: case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_cancel: case OMPD_flush: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); } } StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, ArrayRef Clauses) { if (!S.isUsable()) { ActOnCapturedRegionError(); return StmtError(); } OMPOrderedClause *OC = nullptr; OMPScheduleClause *SC = nullptr; SmallVector LCs; // This is required for proper codegen. for (auto *Clause : Clauses) { if (isOpenMPPrivate(Clause->getClauseKind()) || Clause->getClauseKind() == OMPC_copyprivate || (getLangOpts().OpenMPUseTLS && getASTContext().getTargetInfo().isTLSSupported() && Clause->getClauseKind() == OMPC_copyin)) { DSAStack->setForceVarCapturing(Clause->getClauseKind() == OMPC_copyin); // Mark all variables in private list clauses as used in inner region. for (auto *VarRef : Clause->children()) { if (auto *E = cast_or_null(VarRef)) { MarkDeclarationsReferencedInExpr(E); } } DSAStack->setForceVarCapturing(/*V=*/false); } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective()) && Clause->getClauseKind() == OMPC_schedule) { // Mark all variables in private list clauses as used in inner region. // Required for proper codegen of combined directives. // TODO: add processing for other clauses. if (auto *E = cast_or_null( cast(Clause)->getHelperChunkSize())) MarkDeclarationsReferencedInExpr(E); } if (Clause->getClauseKind() == OMPC_schedule) SC = cast(Clause); else if (Clause->getClauseKind() == OMPC_ordered) OC = cast(Clause); else if (Clause->getClauseKind() == OMPC_linear) LCs.push_back(cast(Clause)); } bool ErrorFound = false; // OpenMP, 2.7.1 Loop Construct, Restrictions // The nonmonotonic modifier cannot be specified if an ordered clause is // specified. if (SC && (SC->getFirstScheduleModifier() == OMPC_SCHEDULE_MODIFIER_nonmonotonic || SC->getSecondScheduleModifier() == OMPC_SCHEDULE_MODIFIER_nonmonotonic) && OC) { Diag(SC->getFirstScheduleModifier() == OMPC_SCHEDULE_MODIFIER_nonmonotonic ? SC->getFirstScheduleModifierLoc() : SC->getSecondScheduleModifierLoc(), diag::err_omp_schedule_nonmonotonic_ordered) << SourceRange(OC->getLocStart(), OC->getLocEnd()); ErrorFound = true; } if (!LCs.empty() && OC && OC->getNumForLoops()) { for (auto *C : LCs) { Diag(C->getLocStart(), diag::err_omp_linear_ordered) << SourceRange(OC->getLocStart(), OC->getLocEnd()); } ErrorFound = true; } if (isOpenMPWorksharingDirective(DSAStack->getCurrentDirective()) && isOpenMPSimdDirective(DSAStack->getCurrentDirective()) && OC && OC->getNumForLoops()) { Diag(OC->getLocStart(), diag::err_omp_ordered_simd) << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); ErrorFound = true; } if (ErrorFound) { ActOnCapturedRegionError(); return StmtError(); } return ActOnCapturedRegionEnd(S.get()); } static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, OpenMPDirectiveKind CurrentRegion, const DeclarationNameInfo &CurrentName, OpenMPDirectiveKind CancelRegion, SourceLocation StartLoc) { // Allowed nesting of constructs // +------------------+-----------------+------------------------------------+ // | Parent directive | Child directive | Closely (!), No-Closely(+), Both(*)| // +------------------+-----------------+------------------------------------+ // | parallel | parallel | * | // | parallel | for | * | // | parallel | for simd | * | // | parallel | master | * | // | parallel | critical | * | // | parallel | simd | * | // | parallel | sections | * | // | parallel | section | + | // | parallel | single | * | // | parallel | parallel for | * | // | parallel |parallel for simd| * | // | parallel |parallel sections| * | // | parallel | task | * | // | parallel | taskyield | * | // | parallel | barrier | * | // | parallel | taskwait | * | // | parallel | taskgroup | * | // | parallel | flush | * | // | parallel | ordered | + | // | parallel | atomic | * | // | parallel | target | * | // | parallel | teams | + | // | parallel | cancellation | | // | | point | ! | // | parallel | cancel | ! | // | parallel | taskloop | * | // | parallel | taskloop simd | * | // | parallel | distribute | | // +------------------+-----------------+------------------------------------+ // | for | parallel | * | // | for | for | + | // | for | for simd | + | // | for | master | + | // | for | critical | * | // | for | simd | * | // | for | sections | + | // | for | section | + | // | for | single | + | // | for | parallel for | * | // | for |parallel for simd| * | // | for |parallel sections| * | // | for | task | * | // | for | taskyield | * | // | for | barrier | + | // | for | taskwait | * | // | for | taskgroup | * | // | for | flush | * | // | for | ordered | * (if construct is ordered) | // | for | atomic | * | // | for | target | * | // | for | teams | + | // | for | cancellation | | // | | point | ! | // | for | cancel | ! | // | for | taskloop | * | // | for | taskloop simd | * | // | for | distribute | | // +------------------+-----------------+------------------------------------+ // | master | parallel | * | // | master | for | + | // | master | for simd | + | // | master | master | * | // | master | critical | * | // | master | simd | * | // | master | sections | + | // | master | section | + | // | master | single | + | // | master | parallel for | * | // | master |parallel for simd| * | // | master |parallel sections| * | // | master | task | * | // | master | taskyield | * | // | master | barrier | + | // | master | taskwait | * | // | master | taskgroup | * | // | master | flush | * | // | master | ordered | + | // | master | atomic | * | // | master | target | * | // | master | teams | + | // | master | cancellation | | // | | point | | // | master | cancel | | // | master | taskloop | * | // | master | taskloop simd | * | // | master | distribute | | // +------------------+-----------------+------------------------------------+ // | critical | parallel | * | // | critical | for | + | // | critical | for simd | + | // | critical | master | * | // | critical | critical | * (should have different names) | // | critical | simd | * | // | critical | sections | + | // | critical | section | + | // | critical | single | + | // | critical | parallel for | * | // | critical |parallel for simd| * | // | critical |parallel sections| * | // | critical | task | * | // | critical | taskyield | * | // | critical | barrier | + | // | critical | taskwait | * | // | critical | taskgroup | * | // | critical | ordered | + | // | critical | atomic | * | // | critical | target | * | // | critical | teams | + | // | critical | cancellation | | // | | point | | // | critical | cancel | | // | critical | taskloop | * | // | critical | taskloop simd | * | // | critical | distribute | | // +------------------+-----------------+------------------------------------+ // | simd | parallel | | // | simd | for | | // | simd | for simd | | // | simd | master | | // | simd | critical | | // | simd | simd | | // | simd | sections | | // | simd | section | | // | simd | single | | // | simd | parallel for | | // | simd |parallel for simd| | // | simd |parallel sections| | // | simd | task | | // | simd | taskyield | | // | simd | barrier | | // | simd | taskwait | | // | simd | taskgroup | | // | simd | flush | | // | simd | ordered | + (with simd clause) | // | simd | atomic | | // | simd | target | | // | simd | teams | | // | simd | cancellation | | // | | point | | // | simd | cancel | | // | simd | taskloop | | // | simd | taskloop simd | | // | simd | distribute | | // +------------------+-----------------+------------------------------------+ // | for simd | parallel | | // | for simd | for | | // | for simd | for simd | | // | for simd | master | | // | for simd | critical | | // | for simd | simd | | // | for simd | sections | | // | for simd | section | | // | for simd | single | | // | for simd | parallel for | | // | for simd |parallel for simd| | // | for simd |parallel sections| | // | for simd | task | | // | for simd | taskyield | | // | for simd | barrier | | // | for simd | taskwait | | // | for simd | taskgroup | | // | for simd | flush | | // | for simd | ordered | + (with simd clause) | // | for simd | atomic | | // | for simd | target | | // | for simd | teams | | // | for simd | cancellation | | // | | point | | // | for simd | cancel | | // | for simd | taskloop | | // | for simd | taskloop simd | | // | for simd | distribute | | // +------------------+-----------------+------------------------------------+ // | parallel for simd| parallel | | // | parallel for simd| for | | // | parallel for simd| for simd | | // | parallel for simd| master | | // | parallel for simd| critical | | // | parallel for simd| simd | | // | parallel for simd| sections | | // | parallel for simd| section | | // | parallel for simd| single | | // | parallel for simd| parallel for | | // | parallel for simd|parallel for simd| | // | parallel for simd|parallel sections| | // | parallel for simd| task | | // | parallel for simd| taskyield | | // | parallel for simd| barrier | | // | parallel for simd| taskwait | | // | parallel for simd| taskgroup | | // | parallel for simd| flush | | // | parallel for simd| ordered | + (with simd clause) | // | parallel for simd| atomic | | // | parallel for simd| target | | // | parallel for simd| teams | | // | parallel for simd| cancellation | | // | | point | | // | parallel for simd| cancel | | // | parallel for simd| taskloop | | // | parallel for simd| taskloop simd | | // | parallel for simd| distribute | | // +------------------+-----------------+------------------------------------+ // | sections | parallel | * | // | sections | for | + | // | sections | for simd | + | // | sections | master | + | // | sections | critical | * | // | sections | simd | * | // | sections | sections | + | // | sections | section | * | // | sections | single | + | // | sections | parallel for | * | // | sections |parallel for simd| * | // | sections |parallel sections| * | // | sections | task | * | // | sections | taskyield | * | // | sections | barrier | + | // | sections | taskwait | * | // | sections | taskgroup | * | // | sections | flush | * | // | sections | ordered | + | // | sections | atomic | * | // | sections | target | * | // | sections | teams | + | // | sections | cancellation | | // | | point | ! | // | sections | cancel | ! | // | sections | taskloop | * | // | sections | taskloop simd | * | // | sections | distribute | | // +------------------+-----------------+------------------------------------+ // | section | parallel | * | // | section | for | + | // | section | for simd | + | // | section | master | + | // | section | critical | * | // | section | simd | * | // | section | sections | + | // | section | section | + | // | section | single | + | // | section | parallel for | * | // | section |parallel for simd| * | // | section |parallel sections| * | // | section | task | * | // | section | taskyield | * | // | section | barrier | + | // | section | taskwait | * | // | section | taskgroup | * | // | section | flush | * | // | section | ordered | + | // | section | atomic | * | // | section | target | * | // | section | teams | + | // | section | cancellation | | // | | point | ! | // | section | cancel | ! | // | section | taskloop | * | // | section | taskloop simd | * | // | section | distribute | | // +------------------+-----------------+------------------------------------+ // | single | parallel | * | // | single | for | + | // | single | for simd | + | // | single | master | + | // | single | critical | * | // | single | simd | * | // | single | sections | + | // | single | section | + | // | single | single | + | // | single | parallel for | * | // | single |parallel for simd| * | // | single |parallel sections| * | // | single | task | * | // | single | taskyield | * | // | single | barrier | + | // | single | taskwait | * | // | single | taskgroup | * | // | single | flush | * | // | single | ordered | + | // | single | atomic | * | // | single | target | * | // | single | teams | + | // | single | cancellation | | // | | point | | // | single | cancel | | // | single | taskloop | * | // | single | taskloop simd | * | // | single | distribute | | // +------------------+-----------------+------------------------------------+ // | parallel for | parallel | * | // | parallel for | for | + | // | parallel for | for simd | + | // | parallel for | master | + | // | parallel for | critical | * | // | parallel for | simd | * | // | parallel for | sections | + | // | parallel for | section | + | // | parallel for | single | + | // | parallel for | parallel for | * | // | parallel for |parallel for simd| * | // | parallel for |parallel sections| * | // | parallel for | task | * | // | parallel for | taskyield | * | // | parallel for | barrier | + | // | parallel for | taskwait | * | // | parallel for | taskgroup | * | // | parallel for | flush | * | // | parallel for | ordered | * (if construct is ordered) | // | parallel for | atomic | * | // | parallel for | target | * | // | parallel for | teams | + | // | parallel for | cancellation | | // | | point | ! | // | parallel for | cancel | ! | // | parallel for | taskloop | * | // | parallel for | taskloop simd | * | // | parallel for | distribute | | // +------------------+-----------------+------------------------------------+ // | parallel sections| parallel | * | // | parallel sections| for | + | // | parallel sections| for simd | + | // | parallel sections| master | + | // | parallel sections| critical | + | // | parallel sections| simd | * | // | parallel sections| sections | + | // | parallel sections| section | * | // | parallel sections| single | + | // | parallel sections| parallel for | * | // | parallel sections|parallel for simd| * | // | parallel sections|parallel sections| * | // | parallel sections| task | * | // | parallel sections| taskyield | * | // | parallel sections| barrier | + | // | parallel sections| taskwait | * | // | parallel sections| taskgroup | * | // | parallel sections| flush | * | // | parallel sections| ordered | + | // | parallel sections| atomic | * | // | parallel sections| target | * | // | parallel sections| teams | + | // | parallel sections| cancellation | | // | | point | ! | // | parallel sections| cancel | ! | // | parallel sections| taskloop | * | // | parallel sections| taskloop simd | * | // | parallel sections| distribute | | // +------------------+-----------------+------------------------------------+ // | task | parallel | * | // | task | for | + | // | task | for simd | + | // | task | master | + | // | task | critical | * | // | task | simd | * | // | task | sections | + | // | task | section | + | // | task | single | + | // | task | parallel for | * | // | task |parallel for simd| * | // | task |parallel sections| * | // | task | task | * | // | task | taskyield | * | // | task | barrier | + | // | task | taskwait | * | // | task | taskgroup | * | // | task | flush | * | // | task | ordered | + | // | task | atomic | * | // | task | target | * | // | task | teams | + | // | task | cancellation | | // | | point | ! | // | task | cancel | ! | // | task | taskloop | * | // | task | taskloop simd | * | // | task | distribute | | // +------------------+-----------------+------------------------------------+ // | ordered | parallel | * | // | ordered | for | + | // | ordered | for simd | + | // | ordered | master | * | // | ordered | critical | * | // | ordered | simd | * | // | ordered | sections | + | // | ordered | section | + | // | ordered | single | + | // | ordered | parallel for | * | // | ordered |parallel for simd| * | // | ordered |parallel sections| * | // | ordered | task | * | // | ordered | taskyield | * | // | ordered | barrier | + | // | ordered | taskwait | * | // | ordered | taskgroup | * | // | ordered | flush | * | // | ordered | ordered | + | // | ordered | atomic | * | // | ordered | target | * | // | ordered | teams | + | // | ordered | cancellation | | // | | point | | // | ordered | cancel | | // | ordered | taskloop | * | // | ordered | taskloop simd | * | // | ordered | distribute | | // +------------------+-----------------+------------------------------------+ // | atomic | parallel | | // | atomic | for | | // | atomic | for simd | | // | atomic | master | | // | atomic | critical | | // | atomic | simd | | // | atomic | sections | | // | atomic | section | | // | atomic | single | | // | atomic | parallel for | | // | atomic |parallel for simd| | // | atomic |parallel sections| | // | atomic | task | | // | atomic | taskyield | | // | atomic | barrier | | // | atomic | taskwait | | // | atomic | taskgroup | | // | atomic | flush | | // | atomic | ordered | | // | atomic | atomic | | // | atomic | target | | // | atomic | teams | | // | atomic | cancellation | | // | | point | | // | atomic | cancel | | // | atomic | taskloop | | // | atomic | taskloop simd | | // | atomic | distribute | | // +------------------+-----------------+------------------------------------+ // | target | parallel | * | // | target | for | * | // | target | for simd | * | // | target | master | * | // | target | critical | * | // | target | simd | * | // | target | sections | * | // | target | section | * | // | target | single | * | // | target | parallel for | * | // | target |parallel for simd| * | // | target |parallel sections| * | // | target | task | * | // | target | taskyield | * | // | target | barrier | * | // | target | taskwait | * | // | target | taskgroup | * | // | target | flush | * | // | target | ordered | * | // | target | atomic | * | // | target | target | * | // | target | teams | * | // | target | cancellation | | // | | point | | // | target | cancel | | // | target | taskloop | * | // | target | taskloop simd | * | // | target | distribute | | // +------------------+-----------------+------------------------------------+ // | teams | parallel | * | // | teams | for | + | // | teams | for simd | + | // | teams | master | + | // | teams | critical | + | // | teams | simd | + | // | teams | sections | + | // | teams | section | + | // | teams | single | + | // | teams | parallel for | * | // | teams |parallel for simd| * | // | teams |parallel sections| * | // | teams | task | + | // | teams | taskyield | + | // | teams | barrier | + | // | teams | taskwait | + | // | teams | taskgroup | + | // | teams | flush | + | // | teams | ordered | + | // | teams | atomic | + | // | teams | target | + | // | teams | teams | + | // | teams | cancellation | | // | | point | | // | teams | cancel | | // | teams | taskloop | + | // | teams | taskloop simd | + | // | teams | distribute | ! | // +------------------+-----------------+------------------------------------+ // | taskloop | parallel | * | // | taskloop | for | + | // | taskloop | for simd | + | // | taskloop | master | + | // | taskloop | critical | * | // | taskloop | simd | * | // | taskloop | sections | + | // | taskloop | section | + | // | taskloop | single | + | // | taskloop | parallel for | * | // | taskloop |parallel for simd| * | // | taskloop |parallel sections| * | // | taskloop | task | * | // | taskloop | taskyield | * | // | taskloop | barrier | + | // | taskloop | taskwait | * | // | taskloop | taskgroup | * | // | taskloop | flush | * | // | taskloop | ordered | + | // | taskloop | atomic | * | // | taskloop | target | * | // | taskloop | teams | + | // | taskloop | cancellation | | // | | point | | // | taskloop | cancel | | // | taskloop | taskloop | * | // | taskloop | distribute | | // +------------------+-----------------+------------------------------------+ // | taskloop simd | parallel | | // | taskloop simd | for | | // | taskloop simd | for simd | | // | taskloop simd | master | | // | taskloop simd | critical | | // | taskloop simd | simd | | // | taskloop simd | sections | | // | taskloop simd | section | | // | taskloop simd | single | | // | taskloop simd | parallel for | | // | taskloop simd |parallel for simd| | // | taskloop simd |parallel sections| | // | taskloop simd | task | | // | taskloop simd | taskyield | | // | taskloop simd | barrier | | // | taskloop simd | taskwait | | // | taskloop simd | taskgroup | | // | taskloop simd | flush | | // | taskloop simd | ordered | + (with simd clause) | // | taskloop simd | atomic | | // | taskloop simd | target | | // | taskloop simd | teams | | // | taskloop simd | cancellation | | // | | point | | // | taskloop simd | cancel | | // | taskloop simd | taskloop | | // | taskloop simd | taskloop simd | | // | taskloop simd | distribute | | // +------------------+-----------------+------------------------------------+ // | distribute | parallel | * | // | distribute | for | * | // | distribute | for simd | * | // | distribute | master | * | // | distribute | critical | * | // | distribute | simd | * | // | distribute | sections | * | // | distribute | section | * | // | distribute | single | * | // | distribute | parallel for | * | // | distribute |parallel for simd| * | // | distribute |parallel sections| * | // | distribute | task | * | // | distribute | taskyield | * | // | distribute | barrier | * | // | distribute | taskwait | * | // | distribute | taskgroup | * | // | distribute | flush | * | // | distribute | ordered | + | // | distribute | atomic | * | // | distribute | target | | // | distribute | teams | | // | distribute | cancellation | + | // | | point | | // | distribute | cancel | + | // | distribute | taskloop | * | // | distribute | taskloop simd | * | // | distribute | distribute | | // +------------------+-----------------+------------------------------------+ if (Stack->getCurScope()) { auto ParentRegion = Stack->getParentDirective(); bool NestingProhibited = false; bool CloseNesting = true; enum { NoRecommend, ShouldBeInParallelRegion, ShouldBeInOrderedRegion, ShouldBeInTargetRegion, ShouldBeInTeamsRegion } Recommend = NoRecommend; if (isOpenMPSimdDirective(ParentRegion) && CurrentRegion != OMPD_ordered) { // OpenMP [2.16, Nesting of Regions] // OpenMP constructs may not be nested inside a simd region. // OpenMP [2.8.1,simd Construct, Restrictions] // An ordered construct with the simd clause is the only OpenMP construct // that can appear in the simd region. SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_simd); return true; } if (ParentRegion == OMPD_atomic) { // OpenMP [2.16, Nesting of Regions] // OpenMP constructs may not be nested inside an atomic region. SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_atomic); return true; } if (CurrentRegion == OMPD_section) { // OpenMP [2.7.2, sections Construct, Restrictions] // Orphaned section directives are prohibited. That is, the section // directives must appear within the sections construct and must not be // encountered elsewhere in the sections region. if (ParentRegion != OMPD_sections && ParentRegion != OMPD_parallel_sections) { SemaRef.Diag(StartLoc, diag::err_omp_orphaned_section_directive) << (ParentRegion != OMPD_unknown) << getOpenMPDirectiveName(ParentRegion); return true; } return false; } // Allow some constructs to be orphaned (they could be used in functions, // called from OpenMP regions with the required preconditions). if (ParentRegion == OMPD_unknown) return false; if (CurrentRegion == OMPD_cancellation_point || CurrentRegion == OMPD_cancel) { // OpenMP [2.16, Nesting of Regions] // A cancellation point construct for which construct-type-clause is // taskgroup must be nested inside a task construct. A cancellation // point construct for which construct-type-clause is not taskgroup must // be closely nested inside an OpenMP construct that matches the type // specified in construct-type-clause. // A cancel construct for which construct-type-clause is taskgroup must be // nested inside a task construct. A cancel construct for which // construct-type-clause is not taskgroup must be closely nested inside an // OpenMP construct that matches the type specified in // construct-type-clause. NestingProhibited = !((CancelRegion == OMPD_parallel && ParentRegion == OMPD_parallel) || (CancelRegion == OMPD_for && (ParentRegion == OMPD_for || ParentRegion == OMPD_parallel_for)) || (CancelRegion == OMPD_taskgroup && ParentRegion == OMPD_task) || (CancelRegion == OMPD_sections && (ParentRegion == OMPD_section || ParentRegion == OMPD_sections || ParentRegion == OMPD_parallel_sections))); } else if (CurrentRegion == OMPD_master) { // OpenMP [2.16, Nesting of Regions] // A master region may not be closely nested inside a worksharing, // atomic, or explicit task region. NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || ParentRegion == OMPD_task || isOpenMPTaskLoopDirective(ParentRegion); } else if (CurrentRegion == OMPD_critical && CurrentName.getName()) { // OpenMP [2.16, Nesting of Regions] // A critical region may not be nested (closely or otherwise) inside a // critical region with the same name. Note that this restriction is not // sufficient to prevent deadlock. SourceLocation PreviousCriticalLoc; bool DeadLock = Stack->hasDirective([CurrentName, &PreviousCriticalLoc]( OpenMPDirectiveKind K, const DeclarationNameInfo &DNI, SourceLocation Loc) ->bool { if (K == OMPD_critical && DNI.getName() == CurrentName.getName()) { PreviousCriticalLoc = Loc; return true; } else return false; }, false /* skip top directive */); if (DeadLock) { SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_critical_same_name) << CurrentName.getName(); if (PreviousCriticalLoc.isValid()) SemaRef.Diag(PreviousCriticalLoc, diag::note_omp_previous_critical_region); return true; } } else if (CurrentRegion == OMPD_barrier) { // OpenMP [2.16, Nesting of Regions] // A barrier region may not be closely nested inside a worksharing, // explicit task, critical, ordered, atomic, or master region. NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || ParentRegion == OMPD_task || ParentRegion == OMPD_master || ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered || isOpenMPTaskLoopDirective(ParentRegion); } else if (isOpenMPWorksharingDirective(CurrentRegion) && !isOpenMPParallelDirective(CurrentRegion)) { // OpenMP [2.16, Nesting of Regions] // A worksharing region may not be closely nested inside a worksharing, // explicit task, critical, ordered, atomic, or master region. NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || ParentRegion == OMPD_task || ParentRegion == OMPD_master || ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered || isOpenMPTaskLoopDirective(ParentRegion); Recommend = ShouldBeInParallelRegion; } else if (CurrentRegion == OMPD_ordered) { // OpenMP [2.16, Nesting of Regions] // An ordered region may not be closely nested inside a critical, // atomic, or explicit task region. // An ordered region must be closely nested inside a loop region (or // parallel loop region) with an ordered clause. // OpenMP [2.8.1,simd Construct, Restrictions] // An ordered construct with the simd clause is the only OpenMP construct // that can appear in the simd region. NestingProhibited = ParentRegion == OMPD_critical || ParentRegion == OMPD_task || isOpenMPTaskLoopDirective(ParentRegion) || !(isOpenMPSimdDirective(ParentRegion) || Stack->isParentOrderedRegion()); Recommend = ShouldBeInOrderedRegion; } else if (isOpenMPTeamsDirective(CurrentRegion)) { // OpenMP [2.16, Nesting of Regions] // If specified, a teams construct must be contained within a target // construct. NestingProhibited = ParentRegion != OMPD_target; Recommend = ShouldBeInTargetRegion; Stack->setParentTeamsRegionLoc(Stack->getConstructLoc()); } if (!NestingProhibited && isOpenMPTeamsDirective(ParentRegion)) { // OpenMP [2.16, Nesting of Regions] // distribute, parallel, parallel sections, parallel workshare, and the // parallel loop and parallel loop SIMD constructs are the only OpenMP // constructs that can be closely nested in the teams region. NestingProhibited = !isOpenMPParallelDirective(CurrentRegion) && !isOpenMPDistributeDirective(CurrentRegion); Recommend = ShouldBeInParallelRegion; } if (!NestingProhibited && isOpenMPDistributeDirective(CurrentRegion)) { // OpenMP 4.5 [2.17 Nesting of Regions] // The region associated with the distribute construct must be strictly // nested inside a teams region NestingProhibited = !isOpenMPTeamsDirective(ParentRegion); Recommend = ShouldBeInTeamsRegion; } if (NestingProhibited) { SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region) << CloseNesting << getOpenMPDirectiveName(ParentRegion) << Recommend << getOpenMPDirectiveName(CurrentRegion); return true; } } return false; } static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind, ArrayRef Clauses, ArrayRef AllowedNameModifiers) { bool ErrorFound = false; unsigned NamedModifiersNumber = 0; SmallVector FoundNameModifiers( OMPD_unknown + 1); SmallVector NameModifierLoc; for (const auto *C : Clauses) { if (const auto *IC = dyn_cast_or_null(C)) { // At most one if clause without a directive-name-modifier can appear on // the directive. OpenMPDirectiveKind CurNM = IC->getNameModifier(); if (FoundNameModifiers[CurNM]) { S.Diag(C->getLocStart(), diag::err_omp_more_one_clause) << getOpenMPDirectiveName(Kind) << getOpenMPClauseName(OMPC_if) << (CurNM != OMPD_unknown) << getOpenMPDirectiveName(CurNM); ErrorFound = true; } else if (CurNM != OMPD_unknown) { NameModifierLoc.push_back(IC->getNameModifierLoc()); ++NamedModifiersNumber; } FoundNameModifiers[CurNM] = IC; if (CurNM == OMPD_unknown) continue; // Check if the specified name modifier is allowed for the current // directive. // At most one if clause with the particular directive-name-modifier can // appear on the directive. bool MatchFound = false; for (auto NM : AllowedNameModifiers) { if (CurNM == NM) { MatchFound = true; break; } } if (!MatchFound) { S.Diag(IC->getNameModifierLoc(), diag::err_omp_wrong_if_directive_name_modifier) << getOpenMPDirectiveName(CurNM) << getOpenMPDirectiveName(Kind); ErrorFound = true; } } } // If any if clause on the directive includes a directive-name-modifier then // all if clauses on the directive must include a directive-name-modifier. if (FoundNameModifiers[OMPD_unknown] && NamedModifiersNumber > 0) { if (NamedModifiersNumber == AllowedNameModifiers.size()) { S.Diag(FoundNameModifiers[OMPD_unknown]->getLocStart(), diag::err_omp_no_more_if_clause); } else { std::string Values; std::string Sep(", "); unsigned AllowedCnt = 0; unsigned TotalAllowedNum = AllowedNameModifiers.size() - NamedModifiersNumber; for (unsigned Cnt = 0, End = AllowedNameModifiers.size(); Cnt < End; ++Cnt) { OpenMPDirectiveKind NM = AllowedNameModifiers[Cnt]; if (!FoundNameModifiers[NM]) { Values += "'"; Values += getOpenMPDirectiveName(NM); Values += "'"; if (AllowedCnt + 2 == TotalAllowedNum) Values += " or "; else if (AllowedCnt + 1 != TotalAllowedNum) Values += Sep; ++AllowedCnt; } } S.Diag(FoundNameModifiers[OMPD_unknown]->getCondition()->getLocStart(), diag::err_omp_unnamed_if_clause) << (TotalAllowedNum > 1) << Values; } for (auto Loc : NameModifierLoc) { S.Diag(Loc, diag::note_omp_previous_named_if_clause); } ErrorFound = true; } return ErrorFound; } StmtResult Sema::ActOnOpenMPExecutableDirective( OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName, OpenMPDirectiveKind CancelRegion, ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { StmtResult Res = StmtError(); if (CheckNestingOfRegions(*this, DSAStack, Kind, DirName, CancelRegion, StartLoc)) return StmtError(); llvm::SmallVector ClausesWithImplicit; llvm::DenseMap VarsWithInheritedDSA; bool ErrorFound = false; ClausesWithImplicit.append(Clauses.begin(), Clauses.end()); if (AStmt) { assert(isa(AStmt) && "Captured statement expected"); // Check default data sharing attributes for referenced variables. DSAAttrChecker DSAChecker(DSAStack, *this, cast(AStmt)); DSAChecker.Visit(cast(AStmt)->getCapturedStmt()); if (DSAChecker.isErrorFound()) return StmtError(); // Generate list of implicitly defined firstprivate variables. VarsWithInheritedDSA = DSAChecker.getVarsWithInheritedDSA(); if (!DSAChecker.getImplicitFirstprivate().empty()) { if (OMPClause *Implicit = ActOnOpenMPFirstprivateClause( DSAChecker.getImplicitFirstprivate(), SourceLocation(), SourceLocation(), SourceLocation())) { ClausesWithImplicit.push_back(Implicit); ErrorFound = cast(Implicit)->varlist_size() != DSAChecker.getImplicitFirstprivate().size(); } else ErrorFound = true; } } llvm::SmallVector AllowedNameModifiers; switch (Kind) { case OMPD_parallel: Res = ActOnOpenMPParallelDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_simd: Res = ActOnOpenMPSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); break; case OMPD_for: Res = ActOnOpenMPForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); break; case OMPD_for_simd: Res = ActOnOpenMPForSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); break; case OMPD_sections: Res = ActOnOpenMPSectionsDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); break; case OMPD_section: assert(ClausesWithImplicit.empty() && "No clauses are allowed for 'omp section' directive"); Res = ActOnOpenMPSectionDirective(AStmt, StartLoc, EndLoc); break; case OMPD_single: Res = ActOnOpenMPSingleDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); break; case OMPD_master: assert(ClausesWithImplicit.empty() && "No clauses are allowed for 'omp master' directive"); Res = ActOnOpenMPMasterDirective(AStmt, StartLoc, EndLoc); break; case OMPD_critical: Res = ActOnOpenMPCriticalDirective(DirName, ClausesWithImplicit, AStmt, StartLoc, EndLoc); break; case OMPD_parallel_for: Res = ActOnOpenMPParallelForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_parallel_for_simd: Res = ActOnOpenMPParallelForSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_parallel_sections: Res = ActOnOpenMPParallelSectionsDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_task: Res = ActOnOpenMPTaskDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); AllowedNameModifiers.push_back(OMPD_task); break; case OMPD_taskyield: assert(ClausesWithImplicit.empty() && "No clauses are allowed for 'omp taskyield' directive"); assert(AStmt == nullptr && "No associated statement allowed for 'omp taskyield' directive"); Res = ActOnOpenMPTaskyieldDirective(StartLoc, EndLoc); break; case OMPD_barrier: assert(ClausesWithImplicit.empty() && "No clauses are allowed for 'omp barrier' directive"); assert(AStmt == nullptr && "No associated statement allowed for 'omp barrier' directive"); Res = ActOnOpenMPBarrierDirective(StartLoc, EndLoc); break; case OMPD_taskwait: assert(ClausesWithImplicit.empty() && "No clauses are allowed for 'omp taskwait' directive"); assert(AStmt == nullptr && "No associated statement allowed for 'omp taskwait' directive"); Res = ActOnOpenMPTaskwaitDirective(StartLoc, EndLoc); break; case OMPD_taskgroup: assert(ClausesWithImplicit.empty() && "No clauses are allowed for 'omp taskgroup' directive"); Res = ActOnOpenMPTaskgroupDirective(AStmt, StartLoc, EndLoc); break; case OMPD_flush: assert(AStmt == nullptr && "No associated statement allowed for 'omp flush' directive"); Res = ActOnOpenMPFlushDirective(ClausesWithImplicit, StartLoc, EndLoc); break; case OMPD_ordered: Res = ActOnOpenMPOrderedDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); break; case OMPD_atomic: Res = ActOnOpenMPAtomicDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); break; case OMPD_teams: Res = ActOnOpenMPTeamsDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); break; case OMPD_target: Res = ActOnOpenMPTargetDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); AllowedNameModifiers.push_back(OMPD_target); break; case OMPD_cancellation_point: assert(ClausesWithImplicit.empty() && "No clauses are allowed for 'omp cancellation point' directive"); assert(AStmt == nullptr && "No associated statement allowed for 'omp " "cancellation point' directive"); Res = ActOnOpenMPCancellationPointDirective(StartLoc, EndLoc, CancelRegion); break; case OMPD_cancel: assert(AStmt == nullptr && "No associated statement allowed for 'omp cancel' directive"); Res = ActOnOpenMPCancelDirective(ClausesWithImplicit, StartLoc, EndLoc, CancelRegion); AllowedNameModifiers.push_back(OMPD_cancel); break; case OMPD_target_data: Res = ActOnOpenMPTargetDataDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); AllowedNameModifiers.push_back(OMPD_target_data); break; case OMPD_taskloop: Res = ActOnOpenMPTaskLoopDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); AllowedNameModifiers.push_back(OMPD_taskloop); break; case OMPD_taskloop_simd: Res = ActOnOpenMPTaskLoopSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); AllowedNameModifiers.push_back(OMPD_taskloop); break; case OMPD_distribute: Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); break; case OMPD_threadprivate: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); } for (auto P : VarsWithInheritedDSA) { Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable) << P.first << P.second->getSourceRange(); } ErrorFound = !VarsWithInheritedDSA.empty() || ErrorFound; if (!AllowedNameModifiers.empty()) ErrorFound = checkIfClauses(*this, Kind, Clauses, AllowedNameModifiers) || ErrorFound; if (ErrorFound) return StmtError(); return Res; } StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { if (!AStmt) return StmtError(); CapturedStmt *CS = cast(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the // top and a single exit at the bottom. // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); getCurFunction()->setHasBranchProtectedScope(); return OMPParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, DSAStack->isCancelRegion()); } namespace { /// \brief Helper class for checking canonical form of the OpenMP loops and /// extracting iteration space of each loop in the loop nest, that will be used /// for IR generation. class OpenMPIterationSpaceChecker { /// \brief Reference to Sema. Sema &SemaRef; /// \brief A location for diagnostics (when there is no some better location). SourceLocation DefaultLoc; /// \brief A location for diagnostics (when increment is not compatible). SourceLocation ConditionLoc; /// \brief A source location for referring to loop init later. SourceRange InitSrcRange; /// \brief A source location for referring to condition later. SourceRange ConditionSrcRange; /// \brief A source location for referring to increment later. SourceRange IncrementSrcRange; /// \brief Loop variable. VarDecl *Var; /// \brief Reference to loop variable. DeclRefExpr *VarRef; /// \brief Lower bound (initializer for the var). Expr *LB; /// \brief Upper bound. Expr *UB; /// \brief Loop step (increment). Expr *Step; /// \brief This flag is true when condition is one of: /// Var < UB /// Var <= UB /// UB > Var /// UB >= Var bool TestIsLessOp; /// \brief This flag is true when condition is strict ( < or > ). bool TestIsStrictOp; /// \brief This flag is true when step is subtracted on each iteration. bool SubtractStep; public: OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc) : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc), InitSrcRange(SourceRange()), ConditionSrcRange(SourceRange()), IncrementSrcRange(SourceRange()), Var(nullptr), VarRef(nullptr), LB(nullptr), UB(nullptr), Step(nullptr), TestIsLessOp(false), TestIsStrictOp(false), SubtractStep(false) {} /// \brief Check init-expr for canonical loop form and save loop counter /// variable - #Var and its initialization value - #LB. bool CheckInit(Stmt *S, bool EmitDiags = true); /// \brief Check test-expr for canonical form, save upper-bound (#UB), flags /// for less/greater and for strict/non-strict comparison. bool CheckCond(Expr *S); /// \brief Check incr-expr for canonical loop form and return true if it /// does not conform, otherwise save loop step (#Step). bool CheckInc(Expr *S); /// \brief Return the loop counter variable. VarDecl *GetLoopVar() const { return Var; } /// \brief Return the reference expression to loop counter variable. DeclRefExpr *GetLoopVarRefExpr() const { return VarRef; } /// \brief Source range of the loop init. SourceRange GetInitSrcRange() const { return InitSrcRange; } /// \brief Source range of the loop condition. SourceRange GetConditionSrcRange() const { return ConditionSrcRange; } /// \brief Source range of the loop increment. SourceRange GetIncrementSrcRange() const { return IncrementSrcRange; } /// \brief True if the step should be subtracted. bool ShouldSubtractStep() const { return SubtractStep; } /// \brief Build the expression to calculate the number of iterations. Expr *BuildNumIterations(Scope *S, const bool LimitedType) const; /// \brief Build the precondition expression for the loops. Expr *BuildPreCond(Scope *S, Expr *Cond) const; /// \brief Build reference expression to the counter be used for codegen. Expr *BuildCounterVar() const; /// \brief Build reference expression to the private counter be used for /// codegen. Expr *BuildPrivateCounterVar() const; /// \brief Build initization of the counter be used for codegen. Expr *BuildCounterInit() const; /// \brief Build step of the counter be used for codegen. Expr *BuildCounterStep() const; /// \brief Return true if any expression is dependent. bool Dependent() const; private: /// \brief Check the right-hand side of an assignment in the increment /// expression. bool CheckIncRHS(Expr *RHS); /// \brief Helper to set loop counter variable and its initializer. bool SetVarAndLB(VarDecl *NewVar, DeclRefExpr *NewVarRefExpr, Expr *NewLB); /// \brief Helper to set upper bound. bool SetUB(Expr *NewUB, bool LessOp, bool StrictOp, SourceRange SR, SourceLocation SL); /// \brief Helper to set loop increment. bool SetStep(Expr *NewStep, bool Subtract); }; bool OpenMPIterationSpaceChecker::Dependent() const { if (!Var) { assert(!LB && !UB && !Step); return false; } return Var->getType()->isDependentType() || (LB && LB->isValueDependent()) || (UB && UB->isValueDependent()) || (Step && Step->isValueDependent()); } template static T *getExprAsWritten(T *E) { if (auto *ExprTemp = dyn_cast(E)) E = ExprTemp->getSubExpr(); if (auto *MTE = dyn_cast(E)) E = MTE->GetTemporaryExpr(); while (auto *Binder = dyn_cast(E)) E = Binder->getSubExpr(); if (auto *ICE = dyn_cast(E)) E = ICE->getSubExprAsWritten(); return E->IgnoreParens(); } bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar, DeclRefExpr *NewVarRefExpr, Expr *NewLB) { // State consistency checking to ensure correct usage. assert(Var == nullptr && LB == nullptr && VarRef == nullptr && UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp); if (!NewVar || !NewLB) return true; Var = NewVar; VarRef = NewVarRefExpr; if (auto *CE = dyn_cast_or_null(NewLB)) if (const CXXConstructorDecl *Ctor = CE->getConstructor()) if ((Ctor->isCopyOrMoveConstructor() || Ctor->isConvertingConstructor(/*AllowExplicit=*/false)) && CE->getNumArgs() > 0 && CE->getArg(0) != nullptr) NewLB = CE->getArg(0)->IgnoreParenImpCasts(); LB = NewLB; return false; } bool OpenMPIterationSpaceChecker::SetUB(Expr *NewUB, bool LessOp, bool StrictOp, SourceRange SR, SourceLocation SL) { // State consistency checking to ensure correct usage. assert(Var != nullptr && LB != nullptr && UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp); if (!NewUB) return true; UB = NewUB; TestIsLessOp = LessOp; TestIsStrictOp = StrictOp; ConditionSrcRange = SR; ConditionLoc = SL; return false; } bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) { // State consistency checking to ensure correct usage. assert(Var != nullptr && LB != nullptr && Step == nullptr); if (!NewStep) return true; if (!NewStep->isValueDependent()) { // Check that the step is integer expression. SourceLocation StepLoc = NewStep->getLocStart(); ExprResult Val = SemaRef.PerformOpenMPImplicitIntegerConversion(StepLoc, NewStep); if (Val.isInvalid()) return true; NewStep = Val.get(); // OpenMP [2.6, Canonical Loop Form, Restrictions] // If test-expr is of form var relational-op b and relational-op is < or // <= then incr-expr must cause var to increase on each iteration of the // loop. If test-expr is of form var relational-op b and relational-op is // > or >= then incr-expr must cause var to decrease on each iteration of // the loop. // If test-expr is of form b relational-op var and relational-op is < or // <= then incr-expr must cause var to decrease on each iteration of the // loop. If test-expr is of form b relational-op var and relational-op is // > or >= then incr-expr must cause var to increase on each iteration of // the loop. llvm::APSInt Result; bool IsConstant = NewStep->isIntegerConstantExpr(Result, SemaRef.Context); bool IsUnsigned = !NewStep->getType()->hasSignedIntegerRepresentation(); bool IsConstNeg = IsConstant && Result.isSigned() && (Subtract != Result.isNegative()); bool IsConstPos = IsConstant && Result.isSigned() && (Subtract == Result.isNegative()); bool IsConstZero = IsConstant && !Result.getBoolValue(); if (UB && (IsConstZero || (TestIsLessOp ? (IsConstNeg || (IsUnsigned && Subtract)) : (IsConstPos || (IsUnsigned && !Subtract))))) { SemaRef.Diag(NewStep->getExprLoc(), diag::err_omp_loop_incr_not_compatible) << Var << TestIsLessOp << NewStep->getSourceRange(); SemaRef.Diag(ConditionLoc, diag::note_omp_loop_cond_requres_compatible_incr) << TestIsLessOp << ConditionSrcRange; return true; } if (TestIsLessOp == Subtract) { NewStep = SemaRef.CreateBuiltinUnaryOp(NewStep->getExprLoc(), UO_Minus, NewStep).get(); Subtract = !Subtract; } } Step = NewStep; SubtractStep = Subtract; return false; } bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { // Check init-expr for canonical loop form and save loop counter // variable - #Var and its initialization value - #LB. // OpenMP [2.6] Canonical loop form. init-expr may be one of the following: // var = lb // integer-type var = lb // random-access-iterator-type var = lb // pointer-type var = lb // if (!S) { if (EmitDiags) { SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_init); } return true; } InitSrcRange = S->getSourceRange(); if (Expr *E = dyn_cast(S)) S = E->IgnoreParens(); if (auto BO = dyn_cast(S)) { if (BO->getOpcode() == BO_Assign) if (auto DRE = dyn_cast(BO->getLHS()->IgnoreParens())) return SetVarAndLB(dyn_cast(DRE->getDecl()), DRE, BO->getRHS()); } else if (auto DS = dyn_cast(S)) { if (DS->isSingleDecl()) { if (auto Var = dyn_cast_or_null(DS->getSingleDecl())) { if (Var->hasInit() && !Var->getType()->isReferenceType()) { // Accept non-canonical init form here but emit ext. warning. if (Var->getInitStyle() != VarDecl::CInit && EmitDiags) SemaRef.Diag(S->getLocStart(), diag::ext_omp_loop_not_canonical_init) << S->getSourceRange(); return SetVarAndLB(Var, nullptr, Var->getInit()); } } } } else if (auto CE = dyn_cast(S)) if (CE->getOperator() == OO_Equal) if (auto DRE = dyn_cast(CE->getArg(0))) return SetVarAndLB(dyn_cast(DRE->getDecl()), DRE, CE->getArg(1)); if (EmitDiags) { SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_init) << S->getSourceRange(); } return true; } /// \brief Ignore parenthesizes, implicit casts, copy constructor and return the /// variable (which may be the loop variable) if possible. static const VarDecl *GetInitVarDecl(const Expr *E) { if (!E) return nullptr; E = getExprAsWritten(E); if (auto *CE = dyn_cast_or_null(E)) if (const CXXConstructorDecl *Ctor = CE->getConstructor()) if ((Ctor->isCopyOrMoveConstructor() || Ctor->isConvertingConstructor(/*AllowExplicit=*/false)) && CE->getNumArgs() > 0 && CE->getArg(0) != nullptr) E = CE->getArg(0)->IgnoreParenImpCasts(); auto DRE = dyn_cast_or_null(E); if (!DRE) return nullptr; return dyn_cast(DRE->getDecl()); } bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { // Check test-expr for canonical form, save upper-bound UB, flags for // less/greater and for strict/non-strict comparison. // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following: // var relational-op b // b relational-op var // if (!S) { SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << Var; return true; } S = getExprAsWritten(S); SourceLocation CondLoc = S->getLocStart(); if (auto BO = dyn_cast(S)) { if (BO->isRelationalOp()) { if (GetInitVarDecl(BO->getLHS()) == Var) return SetUB(BO->getRHS(), (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_LE), (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), BO->getSourceRange(), BO->getOperatorLoc()); if (GetInitVarDecl(BO->getRHS()) == Var) return SetUB(BO->getLHS(), (BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE), (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), BO->getSourceRange(), BO->getOperatorLoc()); } } else if (auto CE = dyn_cast(S)) { if (CE->getNumArgs() == 2) { auto Op = CE->getOperator(); switch (Op) { case OO_Greater: case OO_GreaterEqual: case OO_Less: case OO_LessEqual: if (GetInitVarDecl(CE->getArg(0)) == Var) return SetUB(CE->getArg(1), Op == OO_Less || Op == OO_LessEqual, Op == OO_Less || Op == OO_Greater, CE->getSourceRange(), CE->getOperatorLoc()); if (GetInitVarDecl(CE->getArg(1)) == Var) return SetUB(CE->getArg(0), Op == OO_Greater || Op == OO_GreaterEqual, Op == OO_Less || Op == OO_Greater, CE->getSourceRange(), CE->getOperatorLoc()); break; default: break; } } } SemaRef.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond) << S->getSourceRange() << Var; return true; } bool OpenMPIterationSpaceChecker::CheckIncRHS(Expr *RHS) { // RHS of canonical loop form increment can be: // var + incr // incr + var // var - incr // RHS = RHS->IgnoreParenImpCasts(); if (auto BO = dyn_cast(RHS)) { if (BO->isAdditiveOp()) { bool IsAdd = BO->getOpcode() == BO_Add; if (GetInitVarDecl(BO->getLHS()) == Var) return SetStep(BO->getRHS(), !IsAdd); if (IsAdd && GetInitVarDecl(BO->getRHS()) == Var) return SetStep(BO->getLHS(), false); } } else if (auto CE = dyn_cast(RHS)) { bool IsAdd = CE->getOperator() == OO_Plus; if ((IsAdd || CE->getOperator() == OO_Minus) && CE->getNumArgs() == 2) { if (GetInitVarDecl(CE->getArg(0)) == Var) return SetStep(CE->getArg(1), !IsAdd); if (IsAdd && GetInitVarDecl(CE->getArg(1)) == Var) return SetStep(CE->getArg(0), false); } } SemaRef.Diag(RHS->getLocStart(), diag::err_omp_loop_not_canonical_incr) << RHS->getSourceRange() << Var; return true; } bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { // Check incr-expr for canonical loop form and return true if it // does not conform. // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following: // ++var // var++ // --var // var-- // var += incr // var -= incr // var = var + incr // var = incr + var // var = var - incr // if (!S) { SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr) << Var; return true; } IncrementSrcRange = S->getSourceRange(); S = S->IgnoreParens(); if (auto UO = dyn_cast(S)) { if (UO->isIncrementDecrementOp() && GetInitVarDecl(UO->getSubExpr()) == Var) return SetStep( SemaRef.ActOnIntegerConstant(UO->getLocStart(), (UO->isDecrementOp() ? -1 : 1)).get(), false); } else if (auto BO = dyn_cast(S)) { switch (BO->getOpcode()) { case BO_AddAssign: case BO_SubAssign: if (GetInitVarDecl(BO->getLHS()) == Var) return SetStep(BO->getRHS(), BO->getOpcode() == BO_SubAssign); break; case BO_Assign: if (GetInitVarDecl(BO->getLHS()) == Var) return CheckIncRHS(BO->getRHS()); break; default: break; } } else if (auto CE = dyn_cast(S)) { switch (CE->getOperator()) { case OO_PlusPlus: case OO_MinusMinus: if (GetInitVarDecl(CE->getArg(0)) == Var) return SetStep( SemaRef.ActOnIntegerConstant( CE->getLocStart(), ((CE->getOperator() == OO_MinusMinus) ? -1 : 1)).get(), false); break; case OO_PlusEqual: case OO_MinusEqual: if (GetInitVarDecl(CE->getArg(0)) == Var) return SetStep(CE->getArg(1), CE->getOperator() == OO_MinusEqual); break; case OO_Equal: if (GetInitVarDecl(CE->getArg(0)) == Var) return CheckIncRHS(CE->getArg(1)); break; default: break; } } SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_incr) << S->getSourceRange() << Var; return true; } namespace { // Transform variables declared in GNU statement expressions to new ones to // avoid crash on codegen. class TransformToNewDefs : public TreeTransform { typedef TreeTransform BaseTransform; public: TransformToNewDefs(Sema &SemaRef) : BaseTransform(SemaRef) {} Decl *TransformDefinition(SourceLocation Loc, Decl *D) { if (auto *VD = cast(D)) if (!isa(D) && !isa(D) && !isa(D)) { auto *NewVD = VarDecl::Create( SemaRef.Context, VD->getDeclContext(), VD->getLocStart(), VD->getLocation(), VD->getIdentifier(), VD->getType(), VD->getTypeSourceInfo(), VD->getStorageClass()); NewVD->setTSCSpec(VD->getTSCSpec()); NewVD->setInit(VD->getInit()); NewVD->setInitStyle(VD->getInitStyle()); NewVD->setExceptionVariable(VD->isExceptionVariable()); NewVD->setNRVOVariable(VD->isNRVOVariable()); - NewVD->setCXXForRangeDecl(VD->isInExternCXXContext()); + NewVD->setCXXForRangeDecl(VD->isCXXForRangeDecl()); NewVD->setConstexpr(VD->isConstexpr()); NewVD->setInitCapture(VD->isInitCapture()); NewVD->setPreviousDeclInSameBlockScope( VD->isPreviousDeclInSameBlockScope()); VD->getDeclContext()->addHiddenDecl(NewVD); if (VD->hasAttrs()) NewVD->setAttrs(VD->getAttrs()); transformedLocalDecl(VD, NewVD); return NewVD; } return BaseTransform::TransformDefinition(Loc, D); } ExprResult TransformDeclRefExpr(DeclRefExpr *E) { if (auto *NewD = TransformDecl(E->getExprLoc(), E->getDecl())) if (E->getDecl() != NewD) { NewD->setReferenced(); NewD->markUsed(SemaRef.Context); return DeclRefExpr::Create( SemaRef.Context, E->getQualifierLoc(), E->getTemplateKeywordLoc(), cast(NewD), E->refersToEnclosingVariableOrCapture(), E->getNameInfo(), E->getType(), E->getValueKind()); } return BaseTransform::TransformDeclRefExpr(E); } }; } /// \brief Build the expression to calculate the number of iterations. Expr * OpenMPIterationSpaceChecker::BuildNumIterations(Scope *S, const bool LimitedType) const { TransformToNewDefs Transform(SemaRef); ExprResult Diff; auto VarType = Var->getType().getNonReferenceType(); if (VarType->isIntegerType() || VarType->isPointerType() || SemaRef.getLangOpts().CPlusPlus) { // Upper - Lower auto *UBExpr = TestIsLessOp ? UB : LB; auto *LBExpr = TestIsLessOp ? LB : UB; Expr *Upper = Transform.TransformExpr(UBExpr).get(); Expr *Lower = Transform.TransformExpr(LBExpr).get(); if (!Upper || !Lower) return nullptr; - Upper = SemaRef.PerformImplicitConversion(Upper, UBExpr->getType(), - Sema::AA_Converting, - /*AllowExplicit=*/true) - .get(); - Lower = SemaRef.PerformImplicitConversion(Lower, LBExpr->getType(), - Sema::AA_Converting, - /*AllowExplicit=*/true) - .get(); + if (!SemaRef.Context.hasSameType(Upper->getType(), UBExpr->getType())) { + Upper = SemaRef + .PerformImplicitConversion(Upper, UBExpr->getType(), + Sema::AA_Converting, + /*AllowExplicit=*/true) + .get(); + } + if (!SemaRef.Context.hasSameType(Lower->getType(), LBExpr->getType())) { + Lower = SemaRef + .PerformImplicitConversion(Lower, LBExpr->getType(), + Sema::AA_Converting, + /*AllowExplicit=*/true) + .get(); + } if (!Upper || !Lower) return nullptr; Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower); if (!Diff.isUsable() && VarType->getAsCXXRecordDecl()) { // BuildBinOp already emitted error, this one is to point user to upper // and lower bound, and to tell what is passed to 'operator-'. SemaRef.Diag(Upper->getLocStart(), diag::err_omp_loop_diff_cxx) << Upper->getSourceRange() << Lower->getSourceRange(); return nullptr; } } if (!Diff.isUsable()) return nullptr; // Upper - Lower [- 1] if (TestIsStrictOp) Diff = SemaRef.BuildBinOp( S, DefaultLoc, BO_Sub, Diff.get(), SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); if (!Diff.isUsable()) return nullptr; // Upper - Lower [- 1] + Step - auto NewStep = Transform.TransformExpr(Step->IgnoreImplicit()); + auto *StepNoImp = Step->IgnoreImplicit(); + auto NewStep = Transform.TransformExpr(StepNoImp); if (NewStep.isInvalid()) return nullptr; - NewStep = SemaRef.PerformImplicitConversion( - NewStep.get(), Step->IgnoreImplicit()->getType(), Sema::AA_Converting, - /*AllowExplicit=*/true); - if (NewStep.isInvalid()) - return nullptr; + if (!SemaRef.Context.hasSameType(NewStep.get()->getType(), + StepNoImp->getType())) { + NewStep = SemaRef.PerformImplicitConversion( + NewStep.get(), StepNoImp->getType(), Sema::AA_Converting, + /*AllowExplicit=*/true); + if (NewStep.isInvalid()) + return nullptr; + } Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Diff.get(), NewStep.get()); if (!Diff.isUsable()) return nullptr; // Parentheses (for dumping/debugging purposes only). Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); if (!Diff.isUsable()) return nullptr; // (Upper - Lower [- 1] + Step) / Step - NewStep = Transform.TransformExpr(Step->IgnoreImplicit()); + NewStep = Transform.TransformExpr(StepNoImp); if (NewStep.isInvalid()) return nullptr; - NewStep = SemaRef.PerformImplicitConversion( - NewStep.get(), Step->IgnoreImplicit()->getType(), Sema::AA_Converting, - /*AllowExplicit=*/true); - if (NewStep.isInvalid()) - return nullptr; + if (!SemaRef.Context.hasSameType(NewStep.get()->getType(), + StepNoImp->getType())) { + NewStep = SemaRef.PerformImplicitConversion( + NewStep.get(), StepNoImp->getType(), Sema::AA_Converting, + /*AllowExplicit=*/true); + if (NewStep.isInvalid()) + return nullptr; + } Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get()); if (!Diff.isUsable()) return nullptr; // OpenMP runtime requires 32-bit or 64-bit loop variables. QualType Type = Diff.get()->getType(); auto &C = SemaRef.Context; bool UseVarType = VarType->hasIntegerRepresentation() && C.getTypeSize(Type) > C.getTypeSize(VarType); if (!Type->isIntegerType() || UseVarType) { unsigned NewSize = UseVarType ? C.getTypeSize(VarType) : C.getTypeSize(Type); bool IsSigned = UseVarType ? VarType->hasSignedIntegerRepresentation() : Type->hasSignedIntegerRepresentation(); Type = C.getIntTypeForBitwidth(NewSize, IsSigned); - Diff = SemaRef.PerformImplicitConversion( - Diff.get(), Type, Sema::AA_Converting, /*AllowExplicit=*/true); - if (!Diff.isUsable()) - return nullptr; + if (!SemaRef.Context.hasSameType(Diff.get()->getType(), Type)) { + Diff = SemaRef.PerformImplicitConversion( + Diff.get(), Type, Sema::AA_Converting, /*AllowExplicit=*/true); + if (!Diff.isUsable()) + return nullptr; + } } if (LimitedType) { unsigned NewSize = (C.getTypeSize(Type) > 32) ? 64 : 32; if (NewSize != C.getTypeSize(Type)) { if (NewSize < C.getTypeSize(Type)) { assert(NewSize == 64 && "incorrect loop var size"); SemaRef.Diag(DefaultLoc, diag::warn_omp_loop_64_bit_var) << InitSrcRange << ConditionSrcRange; } QualType NewType = C.getIntTypeForBitwidth( NewSize, Type->hasSignedIntegerRepresentation() || C.getTypeSize(Type) < NewSize); - Diff = SemaRef.PerformImplicitConversion(Diff.get(), NewType, - Sema::AA_Converting, true); - if (!Diff.isUsable()) - return nullptr; + if (!SemaRef.Context.hasSameType(Diff.get()->getType(), NewType)) { + Diff = SemaRef.PerformImplicitConversion(Diff.get(), NewType, + Sema::AA_Converting, true); + if (!Diff.isUsable()) + return nullptr; + } } } return Diff.get(); } Expr *OpenMPIterationSpaceChecker::BuildPreCond(Scope *S, Expr *Cond) const { // Try to build LB UB, where is <, >, <=, or >=. bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics(); SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true); TransformToNewDefs Transform(SemaRef); auto NewLB = Transform.TransformExpr(LB); auto NewUB = Transform.TransformExpr(UB); if (NewLB.isInvalid() || NewUB.isInvalid()) return Cond; - NewLB = SemaRef.PerformImplicitConversion(NewLB.get(), LB->getType(), - Sema::AA_Converting, - /*AllowExplicit=*/true); - NewUB = SemaRef.PerformImplicitConversion(NewUB.get(), UB->getType(), - Sema::AA_Converting, - /*AllowExplicit=*/true); + if (!SemaRef.Context.hasSameType(NewLB.get()->getType(), LB->getType())) { + NewLB = SemaRef.PerformImplicitConversion(NewLB.get(), LB->getType(), + Sema::AA_Converting, + /*AllowExplicit=*/true); + } + if (!SemaRef.Context.hasSameType(NewUB.get()->getType(), UB->getType())) { + NewUB = SemaRef.PerformImplicitConversion(NewUB.get(), UB->getType(), + Sema::AA_Converting, + /*AllowExplicit=*/true); + } if (NewLB.isInvalid() || NewUB.isInvalid()) return Cond; auto CondExpr = SemaRef.BuildBinOp( S, DefaultLoc, TestIsLessOp ? (TestIsStrictOp ? BO_LT : BO_LE) : (TestIsStrictOp ? BO_GT : BO_GE), NewLB.get(), NewUB.get()); if (CondExpr.isUsable()) { - CondExpr = SemaRef.PerformImplicitConversion( - CondExpr.get(), SemaRef.Context.BoolTy, /*Action=*/Sema::AA_Casting, - /*AllowExplicit=*/true); + if (!SemaRef.Context.hasSameType(CondExpr.get()->getType(), + SemaRef.Context.BoolTy)) + CondExpr = SemaRef.PerformImplicitConversion( + CondExpr.get(), SemaRef.Context.BoolTy, /*Action=*/Sema::AA_Casting, + /*AllowExplicit=*/true); } SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress); // Otherwise use original loop conditon and evaluate it in runtime. return CondExpr.isUsable() ? CondExpr.get() : Cond; } /// \brief Build reference expression to the counter be used for codegen. Expr *OpenMPIterationSpaceChecker::BuildCounterVar() const { return buildDeclRefExpr(SemaRef, Var, Var->getType().getNonReferenceType(), DefaultLoc); } Expr *OpenMPIterationSpaceChecker::BuildPrivateCounterVar() const { if (Var && !Var->isInvalidDecl()) { auto Type = Var->getType().getNonReferenceType(); auto *PrivateVar = buildVarDecl(SemaRef, DefaultLoc, Type, Var->getName(), Var->hasAttrs() ? &Var->getAttrs() : nullptr); if (PrivateVar->isInvalidDecl()) return nullptr; return buildDeclRefExpr(SemaRef, PrivateVar, Type, DefaultLoc); } return nullptr; } /// \brief Build initization of the counter be used for codegen. Expr *OpenMPIterationSpaceChecker::BuildCounterInit() const { return LB; } /// \brief Build step of the counter be used for codegen. Expr *OpenMPIterationSpaceChecker::BuildCounterStep() const { return Step; } /// \brief Iteration space of a single for loop. struct LoopIterationSpace { /// \brief Condition of the loop. Expr *PreCond; /// \brief This expression calculates the number of iterations in the loop. /// It is always possible to calculate it before starting the loop. Expr *NumIterations; /// \brief The loop counter variable. Expr *CounterVar; /// \brief Private loop counter variable. Expr *PrivateCounterVar; /// \brief This is initializer for the initial value of #CounterVar. Expr *CounterInit; /// \brief This is step for the #CounterVar used to generate its update: /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration. Expr *CounterStep; /// \brief Should step be subtracted? bool Subtract; /// \brief Source range of the loop init. SourceRange InitSrcRange; /// \brief Source range of the loop condition. SourceRange CondSrcRange; /// \brief Source range of the loop increment. SourceRange IncSrcRange; }; } // namespace void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { assert(getLangOpts().OpenMP && "OpenMP is not active."); assert(Init && "Expected loop in canonical form."); unsigned AssociatedLoops = DSAStack->getAssociatedLoops(); if (AssociatedLoops > 0 && isOpenMPLoopDirective(DSAStack->getCurrentDirective())) { OpenMPIterationSpaceChecker ISC(*this, ForLoc); if (!ISC.CheckInit(Init, /*EmitDiags=*/false)) DSAStack->addLoopControlVariable(ISC.GetLoopVar()); DSAStack->setAssociatedLoops(AssociatedLoops - 1); } } /// \brief Called on a for stmt to check and extract its iteration space /// for further processing (such as collapsing). static bool CheckOpenMPIterationSpace( OpenMPDirectiveKind DKind, Stmt *S, Sema &SemaRef, DSAStackTy &DSA, unsigned CurrentNestedLoopCount, unsigned NestedLoopCount, Expr *CollapseLoopCountExpr, Expr *OrderedLoopCountExpr, llvm::DenseMap &VarsWithImplicitDSA, LoopIterationSpace &ResultIterSpace) { // OpenMP [2.6, Canonical Loop Form] // for (init-expr; test-expr; incr-expr) structured-block auto For = dyn_cast_or_null(S); if (!For) { SemaRef.Diag(S->getLocStart(), diag::err_omp_not_for) << (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr) << getOpenMPDirectiveName(DKind) << NestedLoopCount << (CurrentNestedLoopCount > 0) << CurrentNestedLoopCount; if (NestedLoopCount > 1) { if (CollapseLoopCountExpr && OrderedLoopCountExpr) SemaRef.Diag(DSA.getConstructLoc(), diag::note_omp_collapse_ordered_expr) << 2 << CollapseLoopCountExpr->getSourceRange() << OrderedLoopCountExpr->getSourceRange(); else if (CollapseLoopCountExpr) SemaRef.Diag(CollapseLoopCountExpr->getExprLoc(), diag::note_omp_collapse_ordered_expr) << 0 << CollapseLoopCountExpr->getSourceRange(); else SemaRef.Diag(OrderedLoopCountExpr->getExprLoc(), diag::note_omp_collapse_ordered_expr) << 1 << OrderedLoopCountExpr->getSourceRange(); } return true; } assert(For->getBody()); OpenMPIterationSpaceChecker ISC(SemaRef, For->getForLoc()); // Check init. auto Init = For->getInit(); if (ISC.CheckInit(Init)) { return true; } bool HasErrors = false; // Check loop variable's type. auto Var = ISC.GetLoopVar(); // OpenMP [2.6, Canonical Loop Form] // Var is one of the following: // A variable of signed or unsigned integer type. // For C++, a variable of a random access iterator type. // For C, a variable of a pointer type. auto VarType = Var->getType().getNonReferenceType(); if (!VarType->isDependentType() && !VarType->isIntegerType() && !VarType->isPointerType() && !(SemaRef.getLangOpts().CPlusPlus && VarType->isOverloadableType())) { SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_variable_type) << SemaRef.getLangOpts().CPlusPlus; HasErrors = true; } // OpenMP, 2.14.1.1 Data-sharing Attribute Rules for Variables Referenced in a // Construct // The loop iteration variable(s) in the associated for-loop(s) of a for or // parallel for construct is (are) private. // The loop iteration variable in the associated for-loop of a simd construct // with just one associated for-loop is linear with a constant-linear-step // that is the increment of the associated for-loop. // Exclude loop var from the list of variables with implicitly defined data // sharing attributes. VarsWithImplicitDSA.erase(Var); // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced in // a Construct, C/C++]. // The loop iteration variable in the associated for-loop of a simd construct // with just one associated for-loop may be listed in a linear clause with a // constant-linear-step that is the increment of the associated for-loop. // The loop iteration variable(s) in the associated for-loop(s) of a for or // parallel for construct may be listed in a private or lastprivate clause. DSAStackTy::DSAVarData DVar = DSA.getTopDSA(Var, false); auto LoopVarRefExpr = ISC.GetLoopVarRefExpr(); // If LoopVarRefExpr is nullptr it means the corresponding loop variable is // declared in the loop and it is predetermined as a private. auto PredeterminedCKind = isOpenMPSimdDirective(DKind) ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate) : OMPC_private; if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && DVar.CKind != PredeterminedCKind) || ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop || isOpenMPDistributeDirective(DKind)) && !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) && (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) { SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(PredeterminedCKind); if (DVar.RefExpr == nullptr) DVar.CKind = PredeterminedCKind; ReportOriginalDSA(SemaRef, &DSA, Var, DVar, /*IsLoopIterVar=*/true); HasErrors = true; } else if (LoopVarRefExpr != nullptr) { // Make the loop iteration variable private (for worksharing constructs), // linear (for simd directives with the only one associated loop) or // lastprivate (for simd directives with several collapsed or ordered // loops). if (DVar.CKind == OMPC_unknown) DVar = DSA.hasDSA(Var, isOpenMPPrivate, MatchesAlways(), /*FromParent=*/false); DSA.addDSA(Var, LoopVarRefExpr, PredeterminedCKind); } assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars"); // Check test-expr. HasErrors |= ISC.CheckCond(For->getCond()); // Check incr-expr. HasErrors |= ISC.CheckInc(For->getInc()); if (ISC.Dependent() || SemaRef.CurContext->isDependentContext() || HasErrors) return HasErrors; // Build the loop's iteration space representation. ResultIterSpace.PreCond = ISC.BuildPreCond(DSA.getCurScope(), For->getCond()); ResultIterSpace.NumIterations = ISC.BuildNumIterations( DSA.getCurScope(), (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind))); ResultIterSpace.CounterVar = ISC.BuildCounterVar(); ResultIterSpace.PrivateCounterVar = ISC.BuildPrivateCounterVar(); ResultIterSpace.CounterInit = ISC.BuildCounterInit(); ResultIterSpace.CounterStep = ISC.BuildCounterStep(); ResultIterSpace.InitSrcRange = ISC.GetInitSrcRange(); ResultIterSpace.CondSrcRange = ISC.GetConditionSrcRange(); ResultIterSpace.IncSrcRange = ISC.GetIncrementSrcRange(); ResultIterSpace.Subtract = ISC.ShouldSubtractStep(); HasErrors |= (ResultIterSpace.PreCond == nullptr || ResultIterSpace.NumIterations == nullptr || ResultIterSpace.CounterVar == nullptr || ResultIterSpace.PrivateCounterVar == nullptr || ResultIterSpace.CounterInit == nullptr || ResultIterSpace.CounterStep == nullptr); return HasErrors; } /// \brief Build 'VarRef = Start. static ExprResult BuildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, ExprResult Start) { TransformToNewDefs Transform(SemaRef); // Build 'VarRef = Start. - auto NewStart = Transform.TransformExpr(Start.get()->IgnoreImplicit()); + auto *StartNoImp = Start.get()->IgnoreImplicit(); + auto NewStart = Transform.TransformExpr(StartNoImp); if (NewStart.isInvalid()) return ExprError(); - NewStart = SemaRef.PerformImplicitConversion( - NewStart.get(), Start.get()->IgnoreImplicit()->getType(), - Sema::AA_Converting, - /*AllowExplicit=*/true); - if (NewStart.isInvalid()) - return ExprError(); - NewStart = SemaRef.PerformImplicitConversion( - NewStart.get(), VarRef.get()->getType(), Sema::AA_Converting, - /*AllowExplicit=*/true); - if (!NewStart.isUsable()) - return ExprError(); + if (!SemaRef.Context.hasSameType(NewStart.get()->getType(), + StartNoImp->getType())) { + NewStart = SemaRef.PerformImplicitConversion( + NewStart.get(), StartNoImp->getType(), Sema::AA_Converting, + /*AllowExplicit=*/true); + if (NewStart.isInvalid()) + return ExprError(); + } + if (!SemaRef.Context.hasSameType(NewStart.get()->getType(), + VarRef.get()->getType())) { + NewStart = SemaRef.PerformImplicitConversion( + NewStart.get(), VarRef.get()->getType(), Sema::AA_Converting, + /*AllowExplicit=*/true); + if (!NewStart.isUsable()) + return ExprError(); + } auto Init = SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), NewStart.get()); return Init; } /// \brief Build 'VarRef = Start + Iter * Step'. static ExprResult BuildCounterUpdate(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, ExprResult Start, ExprResult Iter, ExprResult Step, bool Subtract) { // Add parentheses (for debugging purposes only). Iter = SemaRef.ActOnParenExpr(Loc, Loc, Iter.get()); if (!VarRef.isUsable() || !Start.isUsable() || !Iter.isUsable() || !Step.isUsable()) return ExprError(); + auto *StepNoImp = Step.get()->IgnoreImplicit(); TransformToNewDefs Transform(SemaRef); - auto NewStep = Transform.TransformExpr(Step.get()->IgnoreImplicit()); + auto NewStep = Transform.TransformExpr(StepNoImp); if (NewStep.isInvalid()) return ExprError(); - NewStep = SemaRef.PerformImplicitConversion( - NewStep.get(), Step.get()->IgnoreImplicit()->getType(), - Sema::AA_Converting, - /*AllowExplicit=*/true); - if (NewStep.isInvalid()) - return ExprError(); + if (!SemaRef.Context.hasSameType(NewStep.get()->getType(), + StepNoImp->getType())) { + NewStep = SemaRef.PerformImplicitConversion( + NewStep.get(), StepNoImp->getType(), Sema::AA_Converting, + /*AllowExplicit=*/true); + if (NewStep.isInvalid()) + return ExprError(); + } ExprResult Update = SemaRef.BuildBinOp(S, Loc, BO_Mul, Iter.get(), NewStep.get()); if (!Update.isUsable()) return ExprError(); // Build 'VarRef = Start + Iter * Step'. - auto NewStart = Transform.TransformExpr(Start.get()->IgnoreImplicit()); + auto *StartNoImp = Start.get()->IgnoreImplicit(); + auto NewStart = Transform.TransformExpr(StartNoImp); if (NewStart.isInvalid()) return ExprError(); - NewStart = SemaRef.PerformImplicitConversion( - NewStart.get(), Start.get()->IgnoreImplicit()->getType(), - Sema::AA_Converting, - /*AllowExplicit=*/true); - if (NewStart.isInvalid()) - return ExprError(); + if (!SemaRef.Context.hasSameType(NewStart.get()->getType(), + StartNoImp->getType())) { + NewStart = SemaRef.PerformImplicitConversion( + NewStart.get(), StartNoImp->getType(), Sema::AA_Converting, + /*AllowExplicit=*/true); + if (NewStart.isInvalid()) + return ExprError(); + } Update = SemaRef.BuildBinOp(S, Loc, (Subtract ? BO_Sub : BO_Add), NewStart.get(), Update.get()); if (!Update.isUsable()) return ExprError(); Update = SemaRef.PerformImplicitConversion( Update.get(), VarRef.get()->getType(), Sema::AA_Converting, true); if (!Update.isUsable()) return ExprError(); Update = SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), Update.get()); return Update; } /// \brief Convert integer expression \a E to make it have at least \a Bits /// bits. static ExprResult WidenIterationCount(unsigned Bits, Expr *E, Sema &SemaRef) { if (E == nullptr) return ExprError(); auto &C = SemaRef.Context; QualType OldType = E->getType(); unsigned HasBits = C.getTypeSize(OldType); if (HasBits >= Bits) return ExprResult(E); // OK to convert to signed, because new type has more bits than old. QualType NewType = C.getIntTypeForBitwidth(Bits, /* Signed */ true); return SemaRef.PerformImplicitConversion(E, NewType, Sema::AA_Converting, true); } /// \brief Check if the given expression \a E is a constant integer that fits /// into \a Bits bits. static bool FitsInto(unsigned Bits, bool Signed, Expr *E, Sema &SemaRef) { if (E == nullptr) return false; llvm::APSInt Result; if (E->isIntegerConstantExpr(Result, SemaRef.Context)) return Signed ? Result.isSignedIntN(Bits) : Result.isIntN(Bits); return false; } /// \brief Called on a for stmt to check itself and nested loops (if any). /// \return Returns 0 if one of the collapsed stmts is not canonical for loop, /// number of collapsed loops otherwise. static unsigned CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Expr *OrderedLoopCountExpr, Stmt *AStmt, Sema &SemaRef, DSAStackTy &DSA, llvm::DenseMap &VarsWithImplicitDSA, OMPLoopDirective::HelperExprs &Built) { unsigned NestedLoopCount = 1; if (CollapseLoopCountExpr) { // Found 'collapse' clause - calculate collapse number. llvm::APSInt Result; if (CollapseLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext())) NestedLoopCount = Result.getLimitedValue(); } if (OrderedLoopCountExpr) { // Found 'ordered' clause - calculate collapse number. llvm::APSInt Result; if (OrderedLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext())) { if (Result.getLimitedValue() < NestedLoopCount) { SemaRef.Diag(OrderedLoopCountExpr->getExprLoc(), diag::err_omp_wrong_ordered_loop_count) << OrderedLoopCountExpr->getSourceRange(); SemaRef.Diag(CollapseLoopCountExpr->getExprLoc(), diag::note_collapse_loop_count) << CollapseLoopCountExpr->getSourceRange(); } NestedLoopCount = Result.getLimitedValue(); } } // This is helper routine for loop directives (e.g., 'for', 'simd', // 'for simd', etc.). SmallVector IterSpaces; IterSpaces.resize(NestedLoopCount); Stmt *CurStmt = AStmt->IgnoreContainers(/* IgnoreCaptured */ true); for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) { if (CheckOpenMPIterationSpace(DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount, CollapseLoopCountExpr, OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces[Cnt])) return 0; // Move on to the next nested for loop, or to the loop body. // OpenMP [2.8.1, simd construct, Restrictions] // All loops associated with the construct must be perfectly nested; that // is, there must be no intervening code nor any OpenMP directive between // any two loops. CurStmt = cast(CurStmt)->getBody()->IgnoreContainers(); } Built.clear(/* size */ NestedLoopCount); if (SemaRef.CurContext->isDependentContext()) return NestedLoopCount; // An example of what is generated for the following code: // // #pragma omp simd collapse(2) ordered(2) // for (i = 0; i < NI; ++i) // for (k = 0; k < NK; ++k) // for (j = J0; j < NJ; j+=2) { // // } // // We generate the code below. // Note: the loop body may be outlined in CodeGen. // Note: some counters may be C++ classes, operator- is used to find number of // iterations and operator+= to calculate counter value. // Note: decltype(NumIterations) must be integer type (in 'omp for', only i32 // or i64 is currently supported). // // #define NumIterations (NI * ((NJ - J0 - 1 + 2) / 2)) // for (int[32|64]_t IV = 0; IV < NumIterations; ++IV ) { // .local.i = IV / ((NJ - J0 - 1 + 2) / 2); // .local.j = J0 + (IV % ((NJ - J0 - 1 + 2) / 2)) * 2; // // similar updates for vars in clauses (e.g. 'linear') // // } // i = NI; // assign final values of counters // j = NJ; // // Last iteration number is (I1 * I2 * ... In) - 1, where I1, I2 ... In are // the iteration counts of the collapsed for loops. // Precondition tests if there is at least one iteration (all conditions are // true). auto PreCond = ExprResult(IterSpaces[0].PreCond); auto N0 = IterSpaces[0].NumIterations; ExprResult LastIteration32 = WidenIterationCount( 32 /* Bits */, SemaRef.PerformImplicitConversion( N0->IgnoreImpCasts(), N0->getType(), Sema::AA_Converting, /*AllowExplicit=*/true) .get(), SemaRef); ExprResult LastIteration64 = WidenIterationCount( 64 /* Bits */, SemaRef.PerformImplicitConversion( N0->IgnoreImpCasts(), N0->getType(), Sema::AA_Converting, /*AllowExplicit=*/true) .get(), SemaRef); if (!LastIteration32.isUsable() || !LastIteration64.isUsable()) return NestedLoopCount; auto &C = SemaRef.Context; bool AllCountsNeedLessThan32Bits = C.getTypeSize(N0->getType()) < 32; Scope *CurScope = DSA.getCurScope(); for (unsigned Cnt = 1; Cnt < NestedLoopCount; ++Cnt) { if (PreCond.isUsable()) { PreCond = SemaRef.BuildBinOp(CurScope, SourceLocation(), BO_LAnd, PreCond.get(), IterSpaces[Cnt].PreCond); } auto N = IterSpaces[Cnt].NumIterations; AllCountsNeedLessThan32Bits &= C.getTypeSize(N->getType()) < 32; if (LastIteration32.isUsable()) LastIteration32 = SemaRef.BuildBinOp( CurScope, SourceLocation(), BO_Mul, LastIteration32.get(), SemaRef.PerformImplicitConversion(N->IgnoreImpCasts(), N->getType(), Sema::AA_Converting, /*AllowExplicit=*/true) .get()); if (LastIteration64.isUsable()) LastIteration64 = SemaRef.BuildBinOp( CurScope, SourceLocation(), BO_Mul, LastIteration64.get(), SemaRef.PerformImplicitConversion(N->IgnoreImpCasts(), N->getType(), Sema::AA_Converting, /*AllowExplicit=*/true) .get()); } // Choose either the 32-bit or 64-bit version. ExprResult LastIteration = LastIteration64; if (LastIteration32.isUsable() && C.getTypeSize(LastIteration32.get()->getType()) == 32 && (AllCountsNeedLessThan32Bits || NestedLoopCount == 1 || FitsInto( 32 /* Bits */, LastIteration32.get()->getType()->hasSignedIntegerRepresentation(), LastIteration64.get(), SemaRef))) LastIteration = LastIteration32; if (!LastIteration.isUsable()) return 0; // Save the number of iterations. ExprResult NumIterations = LastIteration; { LastIteration = SemaRef.BuildBinOp( CurScope, SourceLocation(), BO_Sub, LastIteration.get(), SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); if (!LastIteration.isUsable()) return 0; } // Calculate the last iteration number beforehand instead of doing this on // each iteration. Do not do this if the number of iterations may be kfold-ed. llvm::APSInt Result; bool IsConstant = LastIteration.get()->isIntegerConstantExpr(Result, SemaRef.Context); ExprResult CalcLastIteration; if (!IsConstant) { SourceLocation SaveLoc; VarDecl *SaveVar = buildVarDecl(SemaRef, SaveLoc, LastIteration.get()->getType(), ".omp.last.iteration"); ExprResult SaveRef = buildDeclRefExpr( SemaRef, SaveVar, LastIteration.get()->getType(), SaveLoc); CalcLastIteration = SemaRef.BuildBinOp(CurScope, SaveLoc, BO_Assign, SaveRef.get(), LastIteration.get()); LastIteration = SaveRef; // Prepare SaveRef + 1. NumIterations = SemaRef.BuildBinOp( CurScope, SaveLoc, BO_Add, SaveRef.get(), SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); if (!NumIterations.isUsable()) return 0; } SourceLocation InitLoc = IterSpaces[0].InitSrcRange.getBegin(); QualType VType = LastIteration.get()->getType(); // Build variables passed into runtime, nesessary for worksharing directives. ExprResult LB, UB, IL, ST, EUB; if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) { // Lower bound variable, initialized with zero. VarDecl *LBDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.lb"); LB = buildDeclRefExpr(SemaRef, LBDecl, VType, InitLoc); SemaRef.AddInitializerToDecl( LBDecl, SemaRef.ActOnIntegerConstant(InitLoc, 0).get(), /*DirectInit*/ false, /*TypeMayContainAuto*/ false); // Upper bound variable, initialized with last iteration number. VarDecl *UBDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.ub"); UB = buildDeclRefExpr(SemaRef, UBDecl, VType, InitLoc); SemaRef.AddInitializerToDecl(UBDecl, LastIteration.get(), /*DirectInit*/ false, /*TypeMayContainAuto*/ false); // A 32-bit variable-flag where runtime returns 1 for the last iteration. // This will be used to implement clause 'lastprivate'. QualType Int32Ty = SemaRef.Context.getIntTypeForBitwidth(32, true); VarDecl *ILDecl = buildVarDecl(SemaRef, InitLoc, Int32Ty, ".omp.is_last"); IL = buildDeclRefExpr(SemaRef, ILDecl, Int32Ty, InitLoc); SemaRef.AddInitializerToDecl( ILDecl, SemaRef.ActOnIntegerConstant(InitLoc, 0).get(), /*DirectInit*/ false, /*TypeMayContainAuto*/ false); // Stride variable returned by runtime (we initialize it to 1 by default). VarDecl *STDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.stride"); ST = buildDeclRefExpr(SemaRef, STDecl, VType, InitLoc); SemaRef.AddInitializerToDecl( STDecl, SemaRef.ActOnIntegerConstant(InitLoc, 1).get(), /*DirectInit*/ false, /*TypeMayContainAuto*/ false); // Build expression: UB = min(UB, LastIteration) // It is nesessary for CodeGen of directives with static scheduling. ExprResult IsUBGreater = SemaRef.BuildBinOp(CurScope, InitLoc, BO_GT, UB.get(), LastIteration.get()); ExprResult CondOp = SemaRef.ActOnConditionalOp( InitLoc, InitLoc, IsUBGreater.get(), LastIteration.get(), UB.get()); EUB = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, UB.get(), CondOp.get()); EUB = SemaRef.ActOnFinishFullExpr(EUB.get()); } // Build the iteration variable and its initialization before loop. ExprResult IV; ExprResult Init; { VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.iv"); IV = buildDeclRefExpr(SemaRef, IVDecl, VType, InitLoc); Expr *RHS = (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) ? LB.get() : SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get(); Init = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), RHS); Init = SemaRef.ActOnFinishFullExpr(Init.get()); } // Loop condition (IV < NumIterations) or (IV <= UB) for worksharing loops. SourceLocation CondLoc; ExprResult Cond = (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) ? SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get()) : SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(), NumIterations.get()); // Loop increment (IV = IV + 1) SourceLocation IncLoc; ExprResult Inc = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, IV.get(), SemaRef.ActOnIntegerConstant(IncLoc, 1).get()); if (!Inc.isUsable()) return 0; Inc = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, IV.get(), Inc.get()); Inc = SemaRef.ActOnFinishFullExpr(Inc.get()); if (!Inc.isUsable()) return 0; // Increments for worksharing loops (LB = LB + ST; UB = UB + ST). // Used for directives with static scheduling. ExprResult NextLB, NextUB; if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) { // LB + ST NextLB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, LB.get(), ST.get()); if (!NextLB.isUsable()) return 0; // LB = LB + ST NextLB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, LB.get(), NextLB.get()); NextLB = SemaRef.ActOnFinishFullExpr(NextLB.get()); if (!NextLB.isUsable()) return 0; // UB + ST NextUB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, UB.get(), ST.get()); if (!NextUB.isUsable()) return 0; // UB = UB + ST NextUB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, UB.get(), NextUB.get()); NextUB = SemaRef.ActOnFinishFullExpr(NextUB.get()); if (!NextUB.isUsable()) return 0; } // Build updates and final values of the loop counters. bool HasErrors = false; Built.Counters.resize(NestedLoopCount); Built.Inits.resize(NestedLoopCount); Built.Updates.resize(NestedLoopCount); Built.Finals.resize(NestedLoopCount); { ExprResult Div; // Go from inner nested loop to outer. for (int Cnt = NestedLoopCount - 1; Cnt >= 0; --Cnt) { LoopIterationSpace &IS = IterSpaces[Cnt]; SourceLocation UpdLoc = IS.IncSrcRange.getBegin(); // Build: Iter = (IV / Div) % IS.NumIters // where Div is product of previous iterations' IS.NumIters. ExprResult Iter; if (Div.isUsable()) { Iter = SemaRef.BuildBinOp(CurScope, UpdLoc, BO_Div, IV.get(), Div.get()); } else { Iter = IV; assert((Cnt == (int)NestedLoopCount - 1) && "unusable div expected on first iteration only"); } if (Cnt != 0 && Iter.isUsable()) Iter = SemaRef.BuildBinOp(CurScope, UpdLoc, BO_Rem, Iter.get(), IS.NumIterations); if (!Iter.isUsable()) { HasErrors = true; break; } // Build update: IS.CounterVar(Private) = IS.Start + Iter * IS.Step auto *CounterVar = buildDeclRefExpr( SemaRef, cast(cast(IS.CounterVar)->getDecl()), IS.CounterVar->getType(), IS.CounterVar->getExprLoc(), /*RefersToCapture=*/true); ExprResult Init = BuildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit); if (!Init.isUsable()) { HasErrors = true; break; } ExprResult Update = BuildCounterUpdate(SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, Iter, IS.CounterStep, IS.Subtract); if (!Update.isUsable()) { HasErrors = true; break; } // Build final: IS.CounterVar = IS.Start + IS.NumIters * IS.Step ExprResult Final = BuildCounterUpdate( SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, IS.NumIterations, IS.CounterStep, IS.Subtract); if (!Final.isUsable()) { HasErrors = true; break; } // Build Div for the next iteration: Div <- Div * IS.NumIters if (Cnt != 0) { if (Div.isUnset()) Div = IS.NumIterations; else Div = SemaRef.BuildBinOp(CurScope, UpdLoc, BO_Mul, Div.get(), IS.NumIterations); // Add parentheses (for debugging purposes only). if (Div.isUsable()) Div = SemaRef.ActOnParenExpr(UpdLoc, UpdLoc, Div.get()); if (!Div.isUsable()) { HasErrors = true; break; } } if (!Update.isUsable() || !Final.isUsable()) { HasErrors = true; break; } // Save results Built.Counters[Cnt] = IS.CounterVar; Built.PrivateCounters[Cnt] = IS.PrivateCounterVar; Built.Inits[Cnt] = Init.get(); Built.Updates[Cnt] = Update.get(); Built.Finals[Cnt] = Final.get(); } } if (HasErrors) return 0; // Save results Built.IterationVarRef = IV.get(); Built.LastIteration = LastIteration.get(); Built.NumIterations = NumIterations.get(); Built.CalcLastIteration = SemaRef.ActOnFinishFullExpr(CalcLastIteration.get()).get(); Built.PreCond = PreCond.get(); Built.Cond = Cond.get(); Built.Init = Init.get(); Built.Inc = Inc.get(); Built.LB = LB.get(); Built.UB = UB.get(); Built.IL = IL.get(); Built.ST = ST.get(); Built.EUB = EUB.get(); Built.NLB = NextLB.get(); Built.NUB = NextUB.get(); return NestedLoopCount; } static Expr *getCollapseNumberExpr(ArrayRef Clauses) { auto CollapseClauses = OMPExecutableDirective::getClausesOfKind(Clauses); if (CollapseClauses.begin() != CollapseClauses.end()) return (*CollapseClauses.begin())->getNumForLoops(); return nullptr; } static Expr *getOrderedNumberExpr(ArrayRef Clauses) { auto OrderedClauses = OMPExecutableDirective::getClausesOfKind(Clauses); if (OrderedClauses.begin() != OrderedClauses.end()) return (*OrderedClauses.begin())->getNumForLoops(); return nullptr; } static bool checkSimdlenSafelenValues(Sema &S, const Expr *Simdlen, const Expr *Safelen) { llvm::APSInt SimdlenRes, SafelenRes; if (Simdlen->isValueDependent() || Simdlen->isTypeDependent() || Simdlen->isInstantiationDependent() || Simdlen->containsUnexpandedParameterPack()) return false; if (Safelen->isValueDependent() || Safelen->isTypeDependent() || Safelen->isInstantiationDependent() || Safelen->containsUnexpandedParameterPack()) return false; Simdlen->EvaluateAsInt(SimdlenRes, S.Context); Safelen->EvaluateAsInt(SafelenRes, S.Context); // OpenMP 4.1 [2.8.1, simd Construct, Restrictions] // If both simdlen and safelen clauses are specified, the value of the simdlen // parameter must be less than or equal to the value of the safelen parameter. if (SimdlenRes > SafelenRes) { S.Diag(Simdlen->getExprLoc(), diag::err_omp_wrong_simdlen_safelen_values) << Simdlen->getSourceRange() << Safelen->getSourceRange(); return true; } return false; } StmtResult Sema::ActOnOpenMPSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); assert(isa(AStmt) && "Captured statement expected"); OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop( OMPD_simd, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); assert((CurContext->isDependentContext() || B.builtAll()) && "omp simd loop exprs were not built"); if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. for (auto C : Clauses) { if (auto LC = dyn_cast(C)) if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), B.NumIterations, *this, CurScope)) return StmtError(); } } // OpenMP 4.1 [2.8.1, simd Construct, Restrictions] // If both simdlen and safelen clauses are specified, the value of the simdlen // parameter must be less than or equal to the value of the safelen parameter. OMPSafelenClause *Safelen = nullptr; OMPSimdlenClause *Simdlen = nullptr; for (auto *Clause : Clauses) { if (Clause->getClauseKind() == OMPC_safelen) Safelen = cast(Clause); else if (Clause->getClauseKind() == OMPC_simdlen) Simdlen = cast(Clause); if (Safelen && Simdlen) break; } if (Simdlen && Safelen && checkSimdlenSafelenValues(*this, Simdlen->getSimdlen(), Safelen->getSafelen())) return StmtError(); getCurFunction()->setHasBranchProtectedScope(); return OMPSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } StmtResult Sema::ActOnOpenMPForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); assert(isa(AStmt) && "Captured statement expected"); OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop( OMPD_for, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); assert((CurContext->isDependentContext() || B.builtAll()) && "omp for loop exprs were not built"); if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. for (auto C : Clauses) { if (auto LC = dyn_cast(C)) if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), B.NumIterations, *this, CurScope)) return StmtError(); } } getCurFunction()->setHasBranchProtectedScope(); return OMPForDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); assert(isa(AStmt) && "Captured statement expected"); OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop(OMPD_for_simd, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); assert((CurContext->isDependentContext() || B.builtAll()) && "omp for simd loop exprs were not built"); if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. for (auto C : Clauses) { if (auto LC = dyn_cast(C)) if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), B.NumIterations, *this, CurScope)) return StmtError(); } } // OpenMP 4.1 [2.8.1, simd Construct, Restrictions] // If both simdlen and safelen clauses are specified, the value of the simdlen // parameter must be less than or equal to the value of the safelen parameter. OMPSafelenClause *Safelen = nullptr; OMPSimdlenClause *Simdlen = nullptr; for (auto *Clause : Clauses) { if (Clause->getClauseKind() == OMPC_safelen) Safelen = cast(Clause); else if (Clause->getClauseKind() == OMPC_simdlen) Simdlen = cast(Clause); if (Safelen && Simdlen) break; } if (Simdlen && Safelen && checkSimdlenSafelenValues(*this, Simdlen->getSimdlen(), Safelen->getSafelen())) return StmtError(); getCurFunction()->setHasBranchProtectedScope(); return OMPForSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } StmtResult Sema::ActOnOpenMPSectionsDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { if (!AStmt) return StmtError(); assert(isa(AStmt) && "Captured statement expected"); auto BaseStmt = AStmt; while (CapturedStmt *CS = dyn_cast_or_null(BaseStmt)) BaseStmt = CS->getCapturedStmt(); if (auto C = dyn_cast_or_null(BaseStmt)) { auto S = C->children(); if (S.begin() == S.end()) return StmtError(); // All associated statements must be '#pragma omp section' except for // the first one. for (Stmt *SectionStmt : llvm::make_range(std::next(S.begin()), S.end())) { if (!SectionStmt || !isa(SectionStmt)) { if (SectionStmt) Diag(SectionStmt->getLocStart(), diag::err_omp_sections_substmt_not_section); return StmtError(); } cast(SectionStmt) ->setHasCancel(DSAStack->isCancelRegion()); } } else { Diag(AStmt->getLocStart(), diag::err_omp_sections_not_compound_stmt); return StmtError(); } getCurFunction()->setHasBranchProtectedScope(); return OMPSectionsDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPSectionDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { if (!AStmt) return StmtError(); assert(isa(AStmt) && "Captured statement expected"); getCurFunction()->setHasBranchProtectedScope(); DSAStack->setParentCancelRegion(DSAStack->isCancelRegion()); return OMPSectionDirective::Create(Context, StartLoc, EndLoc, AStmt, DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPSingleDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { if (!AStmt) return StmtError(); assert(isa(AStmt) && "Captured statement expected"); getCurFunction()->setHasBranchProtectedScope(); // OpenMP [2.7.3, single Construct, Restrictions] // The copyprivate clause must not be used with the nowait clause. OMPClause *Nowait = nullptr; OMPClause *Copyprivate = nullptr; for (auto *Clause : Clauses) { if (Clause->getClauseKind() == OMPC_nowait) Nowait = Clause; else if (Clause->getClauseKind() == OMPC_copyprivate) Copyprivate = Clause; if (Copyprivate && Nowait) { Diag(Copyprivate->getLocStart(), diag::err_omp_single_copyprivate_with_nowait); Diag(Nowait->getLocStart(), diag::note_omp_nowait_clause_here); return StmtError(); } } return OMPSingleDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); } StmtResult Sema::ActOnOpenMPMasterDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { if (!AStmt) return StmtError(); assert(isa(AStmt) && "Captured statement expected"); getCurFunction()->setHasBranchProtectedScope(); return OMPMasterDirective::Create(Context, StartLoc, EndLoc, AStmt); } StmtResult Sema::ActOnOpenMPCriticalDirective( const DeclarationNameInfo &DirName, ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { if (!AStmt) return StmtError(); assert(isa(AStmt) && "Captured statement expected"); bool ErrorFound = false; llvm::APSInt Hint; SourceLocation HintLoc; bool DependentHint = false; for (auto *C : Clauses) { if (C->getClauseKind() == OMPC_hint) { if (!DirName.getName()) { Diag(C->getLocStart(), diag::err_omp_hint_clause_no_name); ErrorFound = true; } Expr *E = cast(C)->getHint(); if (E->isTypeDependent() || E->isValueDependent() || E->isInstantiationDependent()) DependentHint = true; else { Hint = E->EvaluateKnownConstInt(Context); HintLoc = C->getLocStart(); } } } if (ErrorFound) return StmtError(); auto Pair = DSAStack->getCriticalWithHint(DirName); if (Pair.first && DirName.getName() && !DependentHint) { if (llvm::APSInt::compareValues(Hint, Pair.second) != 0) { Diag(StartLoc, diag::err_omp_critical_with_hint); if (HintLoc.isValid()) { Diag(HintLoc, diag::note_omp_critical_hint_here) << 0 << Hint.toString(/*Radix=*/10, /*Signed=*/false); } else Diag(StartLoc, diag::note_omp_critical_no_hint) << 0; if (auto *C = Pair.first->getSingleClause()) { Diag(C->getLocStart(), diag::note_omp_critical_hint_here) << 1 << C->getHint()->EvaluateKnownConstInt(Context).toString( /*Radix=*/10, /*Signed=*/false); } else Diag(Pair.first->getLocStart(), diag::note_omp_critical_no_hint) << 1; } } getCurFunction()->setHasBranchProtectedScope(); auto *Dir = OMPCriticalDirective::Create(Context, DirName, StartLoc, EndLoc, Clauses, AStmt); if (!Pair.first && DirName.getName() && !DependentHint) DSAStack->addCriticalWithHint(Dir, Hint); return Dir; } StmtResult Sema::ActOnOpenMPParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); CapturedStmt *CS = cast(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the // top and a single exit at the bottom. // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop(OMPD_parallel_for, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); assert((CurContext->isDependentContext() || B.builtAll()) && "omp parallel for loop exprs were not built"); if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. for (auto C : Clauses) { if (auto LC = dyn_cast(C)) if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), B.NumIterations, *this, CurScope)) return StmtError(); } } getCurFunction()->setHasBranchProtectedScope(); return OMPParallelForDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); CapturedStmt *CS = cast(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the // top and a single exit at the bottom. // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop(OMPD_parallel_for_simd, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. for (auto C : Clauses) { if (auto LC = dyn_cast(C)) if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), B.NumIterations, *this, CurScope)) return StmtError(); } } // OpenMP 4.1 [2.8.1, simd Construct, Restrictions] // If both simdlen and safelen clauses are specified, the value of the simdlen // parameter must be less than or equal to the value of the safelen parameter. OMPSafelenClause *Safelen = nullptr; OMPSimdlenClause *Simdlen = nullptr; for (auto *Clause : Clauses) { if (Clause->getClauseKind() == OMPC_safelen) Safelen = cast(Clause); else if (Clause->getClauseKind() == OMPC_simdlen) Simdlen = cast(Clause); if (Safelen && Simdlen) break; } if (Simdlen && Safelen && checkSimdlenSafelenValues(*this, Simdlen->getSimdlen(), Safelen->getSafelen())) return StmtError(); getCurFunction()->setHasBranchProtectedScope(); return OMPParallelForSimdDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } StmtResult Sema::ActOnOpenMPParallelSectionsDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { if (!AStmt) return StmtError(); assert(isa(AStmt) && "Captured statement expected"); auto BaseStmt = AStmt; while (CapturedStmt *CS = dyn_cast_or_null(BaseStmt)) BaseStmt = CS->getCapturedStmt(); if (auto C = dyn_cast_or_null(BaseStmt)) { auto S = C->children(); if (S.begin() == S.end()) return StmtError(); // All associated statements must be '#pragma omp section' except for // the first one. for (Stmt *SectionStmt : llvm::make_range(std::next(S.begin()), S.end())) { if (!SectionStmt || !isa(SectionStmt)) { if (SectionStmt) Diag(SectionStmt->getLocStart(), diag::err_omp_parallel_sections_substmt_not_section); return StmtError(); } cast(SectionStmt) ->setHasCancel(DSAStack->isCancelRegion()); } } else { Diag(AStmt->getLocStart(), diag::err_omp_parallel_sections_not_compound_stmt); return StmtError(); } getCurFunction()->setHasBranchProtectedScope(); return OMPParallelSectionsDirective::Create( Context, StartLoc, EndLoc, Clauses, AStmt, DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPTaskDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { if (!AStmt) return StmtError(); CapturedStmt *CS = cast(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the // top and a single exit at the bottom. // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); getCurFunction()->setHasBranchProtectedScope(); return OMPTaskDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPTaskyieldDirective(SourceLocation StartLoc, SourceLocation EndLoc) { return OMPTaskyieldDirective::Create(Context, StartLoc, EndLoc); } StmtResult Sema::ActOnOpenMPBarrierDirective(SourceLocation StartLoc, SourceLocation EndLoc) { return OMPBarrierDirective::Create(Context, StartLoc, EndLoc); } StmtResult Sema::ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc, SourceLocation EndLoc) { return OMPTaskwaitDirective::Create(Context, StartLoc, EndLoc); } StmtResult Sema::ActOnOpenMPTaskgroupDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { if (!AStmt) return StmtError(); assert(isa(AStmt) && "Captured statement expected"); getCurFunction()->setHasBranchProtectedScope(); return OMPTaskgroupDirective::Create(Context, StartLoc, EndLoc, AStmt); } StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc) { assert(Clauses.size() <= 1 && "Extra clauses in flush directive"); return OMPFlushDirective::Create(Context, StartLoc, EndLoc, Clauses); } StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { OMPClause *DependFound = nullptr; OMPClause *DependSourceClause = nullptr; OMPClause *DependSinkClause = nullptr; bool ErrorFound = false; OMPThreadsClause *TC = nullptr; OMPSIMDClause *SC = nullptr; for (auto *C : Clauses) { if (auto *DC = dyn_cast(C)) { DependFound = C; if (DC->getDependencyKind() == OMPC_DEPEND_source) { if (DependSourceClause) { Diag(C->getLocStart(), diag::err_omp_more_one_clause) << getOpenMPDirectiveName(OMPD_ordered) << getOpenMPClauseName(OMPC_depend) << 2; ErrorFound = true; } else DependSourceClause = C; if (DependSinkClause) { Diag(C->getLocStart(), diag::err_omp_depend_sink_source_not_allowed) << 0; ErrorFound = true; } } else if (DC->getDependencyKind() == OMPC_DEPEND_sink) { if (DependSourceClause) { Diag(C->getLocStart(), diag::err_omp_depend_sink_source_not_allowed) << 1; ErrorFound = true; } DependSinkClause = C; } } else if (C->getClauseKind() == OMPC_threads) TC = cast(C); else if (C->getClauseKind() == OMPC_simd) SC = cast(C); } if (!ErrorFound && !SC && isOpenMPSimdDirective(DSAStack->getParentDirective())) { // OpenMP [2.8.1,simd Construct, Restrictions] // An ordered construct with the simd clause is the only OpenMP construct // that can appear in the simd region. Diag(StartLoc, diag::err_omp_prohibited_region_simd); ErrorFound = true; } else if (DependFound && (TC || SC)) { Diag(DependFound->getLocStart(), diag::err_omp_depend_clause_thread_simd) << getOpenMPClauseName(TC ? TC->getClauseKind() : SC->getClauseKind()); ErrorFound = true; } else if (DependFound && !DSAStack->getParentOrderedRegionParam()) { Diag(DependFound->getLocStart(), diag::err_omp_ordered_directive_without_param); ErrorFound = true; } else if (TC || Clauses.empty()) { if (auto *Param = DSAStack->getParentOrderedRegionParam()) { SourceLocation ErrLoc = TC ? TC->getLocStart() : StartLoc; Diag(ErrLoc, diag::err_omp_ordered_directive_with_param) << (TC != nullptr); Diag(Param->getLocStart(), diag::note_omp_ordered_param); ErrorFound = true; } } if ((!AStmt && !DependFound) || ErrorFound) return StmtError(); if (AStmt) { assert(isa(AStmt) && "Captured statement expected"); getCurFunction()->setHasBranchProtectedScope(); } return OMPOrderedDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); } namespace { /// \brief Helper class for checking expression in 'omp atomic [update]' /// construct. class OpenMPAtomicUpdateChecker { /// \brief Error results for atomic update expressions. enum ExprAnalysisErrorCode { /// \brief A statement is not an expression statement. NotAnExpression, /// \brief Expression is not builtin binary or unary operation. NotABinaryOrUnaryExpression, /// \brief Unary operation is not post-/pre- increment/decrement operation. NotAnUnaryIncDecExpression, /// \brief An expression is not of scalar type. NotAScalarType, /// \brief A binary operation is not an assignment operation. NotAnAssignmentOp, /// \brief RHS part of the binary operation is not a binary expression. NotABinaryExpression, /// \brief RHS part is not additive/multiplicative/shift/biwise binary /// expression. NotABinaryOperator, /// \brief RHS binary operation does not have reference to the updated LHS /// part. NotAnUpdateExpression, /// \brief No errors is found. NoError }; /// \brief Reference to Sema. Sema &SemaRef; /// \brief A location for note diagnostics (when error is found). SourceLocation NoteLoc; /// \brief 'x' lvalue part of the source atomic expression. Expr *X; /// \brief 'expr' rvalue part of the source atomic expression. Expr *E; /// \brief Helper expression of the form /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'. Expr *UpdateExpr; /// \brief Is 'x' a LHS in a RHS part of full update expression. It is /// important for non-associative operations. bool IsXLHSInRHSPart; BinaryOperatorKind Op; SourceLocation OpLoc; /// \brief true if the source expression is a postfix unary operation, false /// if it is a prefix unary operation. bool IsPostfixUpdate; public: OpenMPAtomicUpdateChecker(Sema &SemaRef) : SemaRef(SemaRef), X(nullptr), E(nullptr), UpdateExpr(nullptr), IsXLHSInRHSPart(false), Op(BO_PtrMemD), IsPostfixUpdate(false) {} /// \brief Check specified statement that it is suitable for 'atomic update' /// constructs and extract 'x', 'expr' and Operation from the original /// expression. If DiagId and NoteId == 0, then only check is performed /// without error notification. /// \param DiagId Diagnostic which should be emitted if error is found. /// \param NoteId Diagnostic note for the main error message. /// \return true if statement is not an update expression, false otherwise. bool checkStatement(Stmt *S, unsigned DiagId = 0, unsigned NoteId = 0); /// \brief Return the 'x' lvalue part of the source atomic expression. Expr *getX() const { return X; } /// \brief Return the 'expr' rvalue part of the source atomic expression. Expr *getExpr() const { return E; } /// \brief Return the update expression used in calculation of the updated /// value. Always has form 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'. Expr *getUpdateExpr() const { return UpdateExpr; } /// \brief Return true if 'x' is LHS in RHS part of full update expression, /// false otherwise. bool isXLHSInRHSPart() const { return IsXLHSInRHSPart; } /// \brief true if the source expression is a postfix unary operation, false /// if it is a prefix unary operation. bool isPostfixUpdate() const { return IsPostfixUpdate; } private: bool checkBinaryOperation(BinaryOperator *AtomicBinOp, unsigned DiagId = 0, unsigned NoteId = 0); }; } // namespace bool OpenMPAtomicUpdateChecker::checkBinaryOperation( BinaryOperator *AtomicBinOp, unsigned DiagId, unsigned NoteId) { ExprAnalysisErrorCode ErrorFound = NoError; SourceLocation ErrorLoc, NoteLoc; SourceRange ErrorRange, NoteRange; // Allowed constructs are: // x = x binop expr; // x = expr binop x; if (AtomicBinOp->getOpcode() == BO_Assign) { X = AtomicBinOp->getLHS(); if (auto *AtomicInnerBinOp = dyn_cast( AtomicBinOp->getRHS()->IgnoreParenImpCasts())) { if (AtomicInnerBinOp->isMultiplicativeOp() || AtomicInnerBinOp->isAdditiveOp() || AtomicInnerBinOp->isShiftOp() || AtomicInnerBinOp->isBitwiseOp()) { Op = AtomicInnerBinOp->getOpcode(); OpLoc = AtomicInnerBinOp->getOperatorLoc(); auto *LHS = AtomicInnerBinOp->getLHS(); auto *RHS = AtomicInnerBinOp->getRHS(); llvm::FoldingSetNodeID XId, LHSId, RHSId; X->IgnoreParenImpCasts()->Profile(XId, SemaRef.getASTContext(), /*Canonical=*/true); LHS->IgnoreParenImpCasts()->Profile(LHSId, SemaRef.getASTContext(), /*Canonical=*/true); RHS->IgnoreParenImpCasts()->Profile(RHSId, SemaRef.getASTContext(), /*Canonical=*/true); if (XId == LHSId) { E = RHS; IsXLHSInRHSPart = true; } else if (XId == RHSId) { E = LHS; IsXLHSInRHSPart = false; } else { ErrorLoc = AtomicInnerBinOp->getExprLoc(); ErrorRange = AtomicInnerBinOp->getSourceRange(); NoteLoc = X->getExprLoc(); NoteRange = X->getSourceRange(); ErrorFound = NotAnUpdateExpression; } } else { ErrorLoc = AtomicInnerBinOp->getExprLoc(); ErrorRange = AtomicInnerBinOp->getSourceRange(); NoteLoc = AtomicInnerBinOp->getOperatorLoc(); NoteRange = SourceRange(NoteLoc, NoteLoc); ErrorFound = NotABinaryOperator; } } else { NoteLoc = ErrorLoc = AtomicBinOp->getRHS()->getExprLoc(); NoteRange = ErrorRange = AtomicBinOp->getRHS()->getSourceRange(); ErrorFound = NotABinaryExpression; } } else { ErrorLoc = AtomicBinOp->getExprLoc(); ErrorRange = AtomicBinOp->getSourceRange(); NoteLoc = AtomicBinOp->getOperatorLoc(); NoteRange = SourceRange(NoteLoc, NoteLoc); ErrorFound = NotAnAssignmentOp; } if (ErrorFound != NoError && DiagId != 0 && NoteId != 0) { SemaRef.Diag(ErrorLoc, DiagId) << ErrorRange; SemaRef.Diag(NoteLoc, NoteId) << ErrorFound << NoteRange; return true; } else if (SemaRef.CurContext->isDependentContext()) E = X = UpdateExpr = nullptr; return ErrorFound != NoError; } bool OpenMPAtomicUpdateChecker::checkStatement(Stmt *S, unsigned DiagId, unsigned NoteId) { ExprAnalysisErrorCode ErrorFound = NoError; SourceLocation ErrorLoc, NoteLoc; SourceRange ErrorRange, NoteRange; // Allowed constructs are: // x++; // x--; // ++x; // --x; // x binop= expr; // x = x binop expr; // x = expr binop x; if (auto *AtomicBody = dyn_cast(S)) { AtomicBody = AtomicBody->IgnoreParenImpCasts(); if (AtomicBody->getType()->isScalarType() || AtomicBody->isInstantiationDependent()) { if (auto *AtomicCompAssignOp = dyn_cast( AtomicBody->IgnoreParenImpCasts())) { // Check for Compound Assignment Operation Op = BinaryOperator::getOpForCompoundAssignment( AtomicCompAssignOp->getOpcode()); OpLoc = AtomicCompAssignOp->getOperatorLoc(); E = AtomicCompAssignOp->getRHS(); X = AtomicCompAssignOp->getLHS(); IsXLHSInRHSPart = true; } else if (auto *AtomicBinOp = dyn_cast( AtomicBody->IgnoreParenImpCasts())) { // Check for Binary Operation if(checkBinaryOperation(AtomicBinOp, DiagId, NoteId)) return true; } else if (auto *AtomicUnaryOp = dyn_cast(AtomicBody->IgnoreParenImpCasts())) { // Check for Unary Operation if (AtomicUnaryOp->isIncrementDecrementOp()) { IsPostfixUpdate = AtomicUnaryOp->isPostfix(); Op = AtomicUnaryOp->isIncrementOp() ? BO_Add : BO_Sub; OpLoc = AtomicUnaryOp->getOperatorLoc(); X = AtomicUnaryOp->getSubExpr(); E = SemaRef.ActOnIntegerConstant(OpLoc, /*uint64_t Val=*/1).get(); IsXLHSInRHSPart = true; } else { ErrorFound = NotAnUnaryIncDecExpression; ErrorLoc = AtomicUnaryOp->getExprLoc(); ErrorRange = AtomicUnaryOp->getSourceRange(); NoteLoc = AtomicUnaryOp->getOperatorLoc(); NoteRange = SourceRange(NoteLoc, NoteLoc); } } else if (!AtomicBody->isInstantiationDependent()) { ErrorFound = NotABinaryOrUnaryExpression; NoteLoc = ErrorLoc = AtomicBody->getExprLoc(); NoteRange = ErrorRange = AtomicBody->getSourceRange(); } } else { ErrorFound = NotAScalarType; NoteLoc = ErrorLoc = AtomicBody->getLocStart(); NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc); } } else { ErrorFound = NotAnExpression; NoteLoc = ErrorLoc = S->getLocStart(); NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc); } if (ErrorFound != NoError && DiagId != 0 && NoteId != 0) { SemaRef.Diag(ErrorLoc, DiagId) << ErrorRange; SemaRef.Diag(NoteLoc, NoteId) << ErrorFound << NoteRange; return true; } else if (SemaRef.CurContext->isDependentContext()) E = X = UpdateExpr = nullptr; if (ErrorFound == NoError && E && X) { // Build an update expression of form 'OpaqueValueExpr(x) binop // OpaqueValueExpr(expr)' or 'OpaqueValueExpr(expr) binop // OpaqueValueExpr(x)' and then cast it to the type of the 'x' expression. auto *OVEX = new (SemaRef.getASTContext()) OpaqueValueExpr(X->getExprLoc(), X->getType(), VK_RValue); auto *OVEExpr = new (SemaRef.getASTContext()) OpaqueValueExpr(E->getExprLoc(), E->getType(), VK_RValue); auto Update = SemaRef.CreateBuiltinBinOp(OpLoc, Op, IsXLHSInRHSPart ? OVEX : OVEExpr, IsXLHSInRHSPart ? OVEExpr : OVEX); if (Update.isInvalid()) return true; Update = SemaRef.PerformImplicitConversion(Update.get(), X->getType(), Sema::AA_Casting); if (Update.isInvalid()) return true; UpdateExpr = Update.get(); } return ErrorFound != NoError; } StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { if (!AStmt) return StmtError(); auto CS = cast(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the // top and a single exit at the bottom. // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. OpenMPClauseKind AtomicKind = OMPC_unknown; SourceLocation AtomicKindLoc; for (auto *C : Clauses) { if (C->getClauseKind() == OMPC_read || C->getClauseKind() == OMPC_write || C->getClauseKind() == OMPC_update || C->getClauseKind() == OMPC_capture) { if (AtomicKind != OMPC_unknown) { Diag(C->getLocStart(), diag::err_omp_atomic_several_clauses) << SourceRange(C->getLocStart(), C->getLocEnd()); Diag(AtomicKindLoc, diag::note_omp_atomic_previous_clause) << getOpenMPClauseName(AtomicKind); } else { AtomicKind = C->getClauseKind(); AtomicKindLoc = C->getLocStart(); } } } auto Body = CS->getCapturedStmt(); if (auto *EWC = dyn_cast(Body)) Body = EWC->getSubExpr(); Expr *X = nullptr; Expr *V = nullptr; Expr *E = nullptr; Expr *UE = nullptr; bool IsXLHSInRHSPart = false; bool IsPostfixUpdate = false; // OpenMP [2.12.6, atomic Construct] // In the next expressions: // * x and v (as applicable) are both l-value expressions with scalar type. // * During the execution of an atomic region, multiple syntactic // occurrences of x must designate the same storage location. // * Neither of v and expr (as applicable) may access the storage location // designated by x. // * Neither of x and expr (as applicable) may access the storage location // designated by v. // * expr is an expression with scalar type. // * binop is one of +, *, -, /, &, ^, |, <<, or >>. // * binop, binop=, ++, and -- are not overloaded operators. // * The expression x binop expr must be numerically equivalent to x binop // (expr). This requirement is satisfied if the operators in expr have // precedence greater than binop, or by using parentheses around expr or // subexpressions of expr. // * The expression expr binop x must be numerically equivalent to (expr) // binop x. This requirement is satisfied if the operators in expr have // precedence equal to or greater than binop, or by using parentheses around // expr or subexpressions of expr. // * For forms that allow multiple occurrences of x, the number of times // that x is evaluated is unspecified. if (AtomicKind == OMPC_read) { enum { NotAnExpression, NotAnAssignmentOp, NotAScalarType, NotAnLValue, NoError } ErrorFound = NoError; SourceLocation ErrorLoc, NoteLoc; SourceRange ErrorRange, NoteRange; // If clause is read: // v = x; if (auto AtomicBody = dyn_cast(Body)) { auto AtomicBinOp = dyn_cast(AtomicBody->IgnoreParenImpCasts()); if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) { X = AtomicBinOp->getRHS()->IgnoreParenImpCasts(); V = AtomicBinOp->getLHS()->IgnoreParenImpCasts(); if ((X->isInstantiationDependent() || X->getType()->isScalarType()) && (V->isInstantiationDependent() || V->getType()->isScalarType())) { if (!X->isLValue() || !V->isLValue()) { auto NotLValueExpr = X->isLValue() ? V : X; ErrorFound = NotAnLValue; ErrorLoc = AtomicBinOp->getExprLoc(); ErrorRange = AtomicBinOp->getSourceRange(); NoteLoc = NotLValueExpr->getExprLoc(); NoteRange = NotLValueExpr->getSourceRange(); } } else if (!X->isInstantiationDependent() || !V->isInstantiationDependent()) { auto NotScalarExpr = (X->isInstantiationDependent() || X->getType()->isScalarType()) ? V : X; ErrorFound = NotAScalarType; ErrorLoc = AtomicBinOp->getExprLoc(); ErrorRange = AtomicBinOp->getSourceRange(); NoteLoc = NotScalarExpr->getExprLoc(); NoteRange = NotScalarExpr->getSourceRange(); } } else if (!AtomicBody->isInstantiationDependent()) { ErrorFound = NotAnAssignmentOp; ErrorLoc = AtomicBody->getExprLoc(); ErrorRange = AtomicBody->getSourceRange(); NoteLoc = AtomicBinOp ? AtomicBinOp->getOperatorLoc() : AtomicBody->getExprLoc(); NoteRange = AtomicBinOp ? AtomicBinOp->getSourceRange() : AtomicBody->getSourceRange(); } } else { ErrorFound = NotAnExpression; NoteLoc = ErrorLoc = Body->getLocStart(); NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc); } if (ErrorFound != NoError) { Diag(ErrorLoc, diag::err_omp_atomic_read_not_expression_statement) << ErrorRange; Diag(NoteLoc, diag::note_omp_atomic_read_write) << ErrorFound << NoteRange; return StmtError(); } else if (CurContext->isDependentContext()) V = X = nullptr; } else if (AtomicKind == OMPC_write) { enum { NotAnExpression, NotAnAssignmentOp, NotAScalarType, NotAnLValue, NoError } ErrorFound = NoError; SourceLocation ErrorLoc, NoteLoc; SourceRange ErrorRange, NoteRange; // If clause is write: // x = expr; if (auto AtomicBody = dyn_cast(Body)) { auto AtomicBinOp = dyn_cast(AtomicBody->IgnoreParenImpCasts()); if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) { X = AtomicBinOp->getLHS(); E = AtomicBinOp->getRHS(); if ((X->isInstantiationDependent() || X->getType()->isScalarType()) && (E->isInstantiationDependent() || E->getType()->isScalarType())) { if (!X->isLValue()) { ErrorFound = NotAnLValue; ErrorLoc = AtomicBinOp->getExprLoc(); ErrorRange = AtomicBinOp->getSourceRange(); NoteLoc = X->getExprLoc(); NoteRange = X->getSourceRange(); } } else if (!X->isInstantiationDependent() || !E->isInstantiationDependent()) { auto NotScalarExpr = (X->isInstantiationDependent() || X->getType()->isScalarType()) ? E : X; ErrorFound = NotAScalarType; ErrorLoc = AtomicBinOp->getExprLoc(); ErrorRange = AtomicBinOp->getSourceRange(); NoteLoc = NotScalarExpr->getExprLoc(); NoteRange = NotScalarExpr->getSourceRange(); } } else if (!AtomicBody->isInstantiationDependent()) { ErrorFound = NotAnAssignmentOp; ErrorLoc = AtomicBody->getExprLoc(); ErrorRange = AtomicBody->getSourceRange(); NoteLoc = AtomicBinOp ? AtomicBinOp->getOperatorLoc() : AtomicBody->getExprLoc(); NoteRange = AtomicBinOp ? AtomicBinOp->getSourceRange() : AtomicBody->getSourceRange(); } } else { ErrorFound = NotAnExpression; NoteLoc = ErrorLoc = Body->getLocStart(); NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc); } if (ErrorFound != NoError) { Diag(ErrorLoc, diag::err_omp_atomic_write_not_expression_statement) << ErrorRange; Diag(NoteLoc, diag::note_omp_atomic_read_write) << ErrorFound << NoteRange; return StmtError(); } else if (CurContext->isDependentContext()) E = X = nullptr; } else if (AtomicKind == OMPC_update || AtomicKind == OMPC_unknown) { // If clause is update: // x++; // x--; // ++x; // --x; // x binop= expr; // x = x binop expr; // x = expr binop x; OpenMPAtomicUpdateChecker Checker(*this); if (Checker.checkStatement( Body, (AtomicKind == OMPC_update) ? diag::err_omp_atomic_update_not_expression_statement : diag::err_omp_atomic_not_expression_statement, diag::note_omp_atomic_update)) return StmtError(); if (!CurContext->isDependentContext()) { E = Checker.getExpr(); X = Checker.getX(); UE = Checker.getUpdateExpr(); IsXLHSInRHSPart = Checker.isXLHSInRHSPart(); } } else if (AtomicKind == OMPC_capture) { enum { NotAnAssignmentOp, NotACompoundStatement, NotTwoSubstatements, NotASpecificExpression, NoError } ErrorFound = NoError; SourceLocation ErrorLoc, NoteLoc; SourceRange ErrorRange, NoteRange; if (auto *AtomicBody = dyn_cast(Body)) { // If clause is a capture: // v = x++; // v = x--; // v = ++x; // v = --x; // v = x binop= expr; // v = x = x binop expr; // v = x = expr binop x; auto *AtomicBinOp = dyn_cast(AtomicBody->IgnoreParenImpCasts()); if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) { V = AtomicBinOp->getLHS(); Body = AtomicBinOp->getRHS()->IgnoreParenImpCasts(); OpenMPAtomicUpdateChecker Checker(*this); if (Checker.checkStatement( Body, diag::err_omp_atomic_capture_not_expression_statement, diag::note_omp_atomic_update)) return StmtError(); E = Checker.getExpr(); X = Checker.getX(); UE = Checker.getUpdateExpr(); IsXLHSInRHSPart = Checker.isXLHSInRHSPart(); IsPostfixUpdate = Checker.isPostfixUpdate(); } else if (!AtomicBody->isInstantiationDependent()) { ErrorLoc = AtomicBody->getExprLoc(); ErrorRange = AtomicBody->getSourceRange(); NoteLoc = AtomicBinOp ? AtomicBinOp->getOperatorLoc() : AtomicBody->getExprLoc(); NoteRange = AtomicBinOp ? AtomicBinOp->getSourceRange() : AtomicBody->getSourceRange(); ErrorFound = NotAnAssignmentOp; } if (ErrorFound != NoError) { Diag(ErrorLoc, diag::err_omp_atomic_capture_not_expression_statement) << ErrorRange; Diag(NoteLoc, diag::note_omp_atomic_capture) << ErrorFound << NoteRange; return StmtError(); } else if (CurContext->isDependentContext()) { UE = V = E = X = nullptr; } } else { // If clause is a capture: // { v = x; x = expr; } // { v = x; x++; } // { v = x; x--; } // { v = x; ++x; } // { v = x; --x; } // { v = x; x binop= expr; } // { v = x; x = x binop expr; } // { v = x; x = expr binop x; } // { x++; v = x; } // { x--; v = x; } // { ++x; v = x; } // { --x; v = x; } // { x binop= expr; v = x; } // { x = x binop expr; v = x; } // { x = expr binop x; v = x; } if (auto *CS = dyn_cast(Body)) { // Check that this is { expr1; expr2; } if (CS->size() == 2) { auto *First = CS->body_front(); auto *Second = CS->body_back(); if (auto *EWC = dyn_cast(First)) First = EWC->getSubExpr()->IgnoreParenImpCasts(); if (auto *EWC = dyn_cast(Second)) Second = EWC->getSubExpr()->IgnoreParenImpCasts(); // Need to find what subexpression is 'v' and what is 'x'. OpenMPAtomicUpdateChecker Checker(*this); bool IsUpdateExprFound = !Checker.checkStatement(Second); BinaryOperator *BinOp = nullptr; if (IsUpdateExprFound) { BinOp = dyn_cast(First); IsUpdateExprFound = BinOp && BinOp->getOpcode() == BO_Assign; } if (IsUpdateExprFound && !CurContext->isDependentContext()) { // { v = x; x++; } // { v = x; x--; } // { v = x; ++x; } // { v = x; --x; } // { v = x; x binop= expr; } // { v = x; x = x binop expr; } // { v = x; x = expr binop x; } // Check that the first expression has form v = x. auto *PossibleX = BinOp->getRHS()->IgnoreParenImpCasts(); llvm::FoldingSetNodeID XId, PossibleXId; Checker.getX()->Profile(XId, Context, /*Canonical=*/true); PossibleX->Profile(PossibleXId, Context, /*Canonical=*/true); IsUpdateExprFound = XId == PossibleXId; if (IsUpdateExprFound) { V = BinOp->getLHS(); X = Checker.getX(); E = Checker.getExpr(); UE = Checker.getUpdateExpr(); IsXLHSInRHSPart = Checker.isXLHSInRHSPart(); IsPostfixUpdate = true; } } if (!IsUpdateExprFound) { IsUpdateExprFound = !Checker.checkStatement(First); BinOp = nullptr; if (IsUpdateExprFound) { BinOp = dyn_cast(Second); IsUpdateExprFound = BinOp && BinOp->getOpcode() == BO_Assign; } if (IsUpdateExprFound && !CurContext->isDependentContext()) { // { x++; v = x; } // { x--; v = x; } // { ++x; v = x; } // { --x; v = x; } // { x binop= expr; v = x; } // { x = x binop expr; v = x; } // { x = expr binop x; v = x; } // Check that the second expression has form v = x. auto *PossibleX = BinOp->getRHS()->IgnoreParenImpCasts(); llvm::FoldingSetNodeID XId, PossibleXId; Checker.getX()->Profile(XId, Context, /*Canonical=*/true); PossibleX->Profile(PossibleXId, Context, /*Canonical=*/true); IsUpdateExprFound = XId == PossibleXId; if (IsUpdateExprFound) { V = BinOp->getLHS(); X = Checker.getX(); E = Checker.getExpr(); UE = Checker.getUpdateExpr(); IsXLHSInRHSPart = Checker.isXLHSInRHSPart(); IsPostfixUpdate = false; } } } if (!IsUpdateExprFound) { // { v = x; x = expr; } auto *FirstExpr = dyn_cast(First); auto *SecondExpr = dyn_cast(Second); if (!FirstExpr || !SecondExpr || !(FirstExpr->isInstantiationDependent() || SecondExpr->isInstantiationDependent())) { auto *FirstBinOp = dyn_cast(First); if (!FirstBinOp || FirstBinOp->getOpcode() != BO_Assign) { ErrorFound = NotAnAssignmentOp; NoteLoc = ErrorLoc = FirstBinOp ? FirstBinOp->getOperatorLoc() : First->getLocStart(); NoteRange = ErrorRange = FirstBinOp ? FirstBinOp->getSourceRange() : SourceRange(ErrorLoc, ErrorLoc); } else { auto *SecondBinOp = dyn_cast(Second); if (!SecondBinOp || SecondBinOp->getOpcode() != BO_Assign) { ErrorFound = NotAnAssignmentOp; NoteLoc = ErrorLoc = SecondBinOp ? SecondBinOp->getOperatorLoc() : Second->getLocStart(); NoteRange = ErrorRange = SecondBinOp ? SecondBinOp->getSourceRange() : SourceRange(ErrorLoc, ErrorLoc); } else { auto *PossibleXRHSInFirst = FirstBinOp->getRHS()->IgnoreParenImpCasts(); auto *PossibleXLHSInSecond = SecondBinOp->getLHS()->IgnoreParenImpCasts(); llvm::FoldingSetNodeID X1Id, X2Id; PossibleXRHSInFirst->Profile(X1Id, Context, /*Canonical=*/true); PossibleXLHSInSecond->Profile(X2Id, Context, /*Canonical=*/true); IsUpdateExprFound = X1Id == X2Id; if (IsUpdateExprFound) { V = FirstBinOp->getLHS(); X = SecondBinOp->getLHS(); E = SecondBinOp->getRHS(); UE = nullptr; IsXLHSInRHSPart = false; IsPostfixUpdate = true; } else { ErrorFound = NotASpecificExpression; ErrorLoc = FirstBinOp->getExprLoc(); ErrorRange = FirstBinOp->getSourceRange(); NoteLoc = SecondBinOp->getLHS()->getExprLoc(); NoteRange = SecondBinOp->getRHS()->getSourceRange(); } } } } } } else { NoteLoc = ErrorLoc = Body->getLocStart(); NoteRange = ErrorRange = SourceRange(Body->getLocStart(), Body->getLocStart()); ErrorFound = NotTwoSubstatements; } } else { NoteLoc = ErrorLoc = Body->getLocStart(); NoteRange = ErrorRange = SourceRange(Body->getLocStart(), Body->getLocStart()); ErrorFound = NotACompoundStatement; } if (ErrorFound != NoError) { Diag(ErrorLoc, diag::err_omp_atomic_capture_not_compound_statement) << ErrorRange; Diag(NoteLoc, diag::note_omp_atomic_capture) << ErrorFound << NoteRange; return StmtError(); } else if (CurContext->isDependentContext()) { UE = V = E = X = nullptr; } } } getCurFunction()->setHasBranchProtectedScope(); return OMPAtomicDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, X, V, E, UE, IsXLHSInRHSPart, IsPostfixUpdate); } StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { if (!AStmt) return StmtError(); CapturedStmt *CS = cast(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the // top and a single exit at the bottom. // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); // OpenMP [2.16, Nesting of Regions] // If specified, a teams construct must be contained within a target // construct. That target construct must contain no statements or directives // outside of the teams construct. if (DSAStack->hasInnerTeamsRegion()) { auto S = AStmt->IgnoreContainers(/*IgnoreCaptured*/ true); bool OMPTeamsFound = true; if (auto *CS = dyn_cast(S)) { auto I = CS->body_begin(); while (I != CS->body_end()) { auto OED = dyn_cast(*I); if (!OED || !isOpenMPTeamsDirective(OED->getDirectiveKind())) { OMPTeamsFound = false; break; } ++I; } assert(I != CS->body_end() && "Not found statement"); S = *I; } if (!OMPTeamsFound) { Diag(StartLoc, diag::err_omp_target_contains_not_only_teams); Diag(DSAStack->getInnerTeamsRegionLoc(), diag::note_omp_nested_teams_construct_here); Diag(S->getLocStart(), diag::note_omp_nested_statement_here) << isa(S); return StmtError(); } } getCurFunction()->setHasBranchProtectedScope(); return OMPTargetDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); } StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { if (!AStmt) return StmtError(); assert(isa(AStmt) && "Captured statement expected"); getCurFunction()->setHasBranchProtectedScope(); return OMPTargetDataDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); } StmtResult Sema::ActOnOpenMPTeamsDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { if (!AStmt) return StmtError(); CapturedStmt *CS = cast(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the // top and a single exit at the bottom. // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); getCurFunction()->setHasBranchProtectedScope(); return OMPTeamsDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); } StmtResult Sema::ActOnOpenMPCancellationPointDirective(SourceLocation StartLoc, SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion) { if (CancelRegion != OMPD_parallel && CancelRegion != OMPD_for && CancelRegion != OMPD_sections && CancelRegion != OMPD_taskgroup) { Diag(StartLoc, diag::err_omp_wrong_cancel_region) << getOpenMPDirectiveName(CancelRegion); return StmtError(); } if (DSAStack->isParentNowaitRegion()) { Diag(StartLoc, diag::err_omp_parent_cancel_region_nowait) << 0; return StmtError(); } if (DSAStack->isParentOrderedRegion()) { Diag(StartLoc, diag::err_omp_parent_cancel_region_ordered) << 0; return StmtError(); } return OMPCancellationPointDirective::Create(Context, StartLoc, EndLoc, CancelRegion); } StmtResult Sema::ActOnOpenMPCancelDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion) { if (CancelRegion != OMPD_parallel && CancelRegion != OMPD_for && CancelRegion != OMPD_sections && CancelRegion != OMPD_taskgroup) { Diag(StartLoc, diag::err_omp_wrong_cancel_region) << getOpenMPDirectiveName(CancelRegion); return StmtError(); } if (DSAStack->isParentNowaitRegion()) { Diag(StartLoc, diag::err_omp_parent_cancel_region_nowait) << 1; return StmtError(); } if (DSAStack->isParentOrderedRegion()) { Diag(StartLoc, diag::err_omp_parent_cancel_region_ordered) << 1; return StmtError(); } DSAStack->setParentCancelRegion(/*Cancel=*/true); return OMPCancelDirective::Create(Context, StartLoc, EndLoc, Clauses, CancelRegion); } static bool checkGrainsizeNumTasksClauses(Sema &S, ArrayRef Clauses) { OMPClause *PrevClause = nullptr; bool ErrorFound = false; for (auto *C : Clauses) { if (C->getClauseKind() == OMPC_grainsize || C->getClauseKind() == OMPC_num_tasks) { if (!PrevClause) PrevClause = C; else if (PrevClause->getClauseKind() != C->getClauseKind()) { S.Diag(C->getLocStart(), diag::err_omp_grainsize_num_tasks_mutually_exclusive) << getOpenMPClauseName(C->getClauseKind()) << getOpenMPClauseName(PrevClause->getClauseKind()); S.Diag(PrevClause->getLocStart(), diag::note_omp_previous_grainsize_num_tasks) << getOpenMPClauseName(PrevClause->getClauseKind()); ErrorFound = true; } } } return ErrorFound; } StmtResult Sema::ActOnOpenMPTaskLoopDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); assert(isa(AStmt) && "Captured statement expected"); OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop(OMPD_taskloop, getCollapseNumberExpr(Clauses), /*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); assert((CurContext->isDependentContext() || B.builtAll()) && "omp for loop exprs were not built"); // OpenMP, [2.9.2 taskloop Construct, Restrictions] // The grainsize clause and num_tasks clause are mutually exclusive and may // not appear on the same taskloop directive. if (checkGrainsizeNumTasksClauses(*this, Clauses)) return StmtError(); getCurFunction()->setHasBranchProtectedScope(); return OMPTaskLoopDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); assert(isa(AStmt) && "Captured statement expected"); OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop(OMPD_taskloop_simd, getCollapseNumberExpr(Clauses), /*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); assert((CurContext->isDependentContext() || B.builtAll()) && "omp for loop exprs were not built"); // OpenMP, [2.9.2 taskloop Construct, Restrictions] // The grainsize clause and num_tasks clause are mutually exclusive and may // not appear on the same taskloop directive. if (checkGrainsizeNumTasksClauses(*this, Clauses)) return StmtError(); getCurFunction()->setHasBranchProtectedScope(); return OMPTaskLoopSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } StmtResult Sema::ActOnOpenMPDistributeDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); assert(isa(AStmt) && "Captured statement expected"); OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop(OMPD_distribute, getCollapseNumberExpr(Clauses), nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); assert((CurContext->isDependentContext() || B.builtAll()) && "omp for loop exprs were not built"); getCurFunction()->setHasBranchProtectedScope(); return OMPDistributeDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { OMPClause *Res = nullptr; switch (Kind) { case OMPC_final: Res = ActOnOpenMPFinalClause(Expr, StartLoc, LParenLoc, EndLoc); break; case OMPC_num_threads: Res = ActOnOpenMPNumThreadsClause(Expr, StartLoc, LParenLoc, EndLoc); break; case OMPC_safelen: Res = ActOnOpenMPSafelenClause(Expr, StartLoc, LParenLoc, EndLoc); break; case OMPC_simdlen: Res = ActOnOpenMPSimdlenClause(Expr, StartLoc, LParenLoc, EndLoc); break; case OMPC_collapse: Res = ActOnOpenMPCollapseClause(Expr, StartLoc, LParenLoc, EndLoc); break; case OMPC_ordered: Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc, LParenLoc, Expr); break; case OMPC_device: Res = ActOnOpenMPDeviceClause(Expr, StartLoc, LParenLoc, EndLoc); break; case OMPC_num_teams: Res = ActOnOpenMPNumTeamsClause(Expr, StartLoc, LParenLoc, EndLoc); break; case OMPC_thread_limit: Res = ActOnOpenMPThreadLimitClause(Expr, StartLoc, LParenLoc, EndLoc); break; case OMPC_priority: Res = ActOnOpenMPPriorityClause(Expr, StartLoc, LParenLoc, EndLoc); break; case OMPC_grainsize: Res = ActOnOpenMPGrainsizeClause(Expr, StartLoc, LParenLoc, EndLoc); break; case OMPC_num_tasks: Res = ActOnOpenMPNumTasksClause(Expr, StartLoc, LParenLoc, EndLoc); break; case OMPC_hint: Res = ActOnOpenMPHintClause(Expr, StartLoc, LParenLoc, EndLoc); break; case OMPC_if: case OMPC_default: case OMPC_proc_bind: case OMPC_schedule: case OMPC_private: case OMPC_firstprivate: case OMPC_lastprivate: case OMPC_shared: case OMPC_reduction: case OMPC_linear: case OMPC_aligned: case OMPC_copyin: case OMPC_copyprivate: case OMPC_nowait: case OMPC_untied: case OMPC_mergeable: case OMPC_threadprivate: case OMPC_flush: case OMPC_read: case OMPC_write: case OMPC_update: case OMPC_capture: case OMPC_seq_cst: case OMPC_depend: case OMPC_threads: case OMPC_simd: case OMPC_map: case OMPC_nogroup: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } return Res; } OMPClause *Sema::ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier, Expr *Condition, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation NameModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc) { Expr *ValExpr = Condition; if (!Condition->isValueDependent() && !Condition->isTypeDependent() && !Condition->isInstantiationDependent() && !Condition->containsUnexpandedParameterPack()) { ExprResult Val = ActOnBooleanCondition(DSAStack->getCurScope(), Condition->getExprLoc(), Condition); if (Val.isInvalid()) return nullptr; ValExpr = Val.get(); } return new (Context) OMPIfClause(NameModifier, ValExpr, StartLoc, LParenLoc, NameModifierLoc, ColonLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = Condition; if (!Condition->isValueDependent() && !Condition->isTypeDependent() && !Condition->isInstantiationDependent() && !Condition->containsUnexpandedParameterPack()) { ExprResult Val = ActOnBooleanCondition(DSAStack->getCurScope(), Condition->getExprLoc(), Condition); if (Val.isInvalid()) return nullptr; ValExpr = Val.get(); } return new (Context) OMPFinalClause(ValExpr, StartLoc, LParenLoc, EndLoc); } ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc, Expr *Op) { if (!Op) return ExprError(); class IntConvertDiagnoser : public ICEConvertDiagnoser { public: IntConvertDiagnoser() : ICEConvertDiagnoser(/*AllowScopedEnumerations*/ false, false, true) {} SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_omp_not_integral) << T; } SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_omp_incomplete_type) << T; } SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override { return S.Diag(Loc, diag::err_omp_explicit_conversion) << T << ConvTy; } SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override { return S.Diag(Conv->getLocation(), diag::note_omp_conversion_here) << ConvTy->isEnumeralType() << ConvTy; } SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_omp_ambiguous_conversion) << T; } SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override { return S.Diag(Conv->getLocation(), diag::note_omp_conversion_here) << ConvTy->isEnumeralType() << ConvTy; } SemaDiagnosticBuilder diagnoseConversion(Sema &, SourceLocation, QualType, QualType) override { llvm_unreachable("conversion functions are permitted"); } } ConvertDiagnoser; return PerformContextualImplicitConversion(Loc, Op, ConvertDiagnoser); } static bool IsNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, OpenMPClauseKind CKind, bool StrictlyPositive) { if (!ValExpr->isTypeDependent() && !ValExpr->isValueDependent() && !ValExpr->isInstantiationDependent()) { SourceLocation Loc = ValExpr->getExprLoc(); ExprResult Value = SemaRef.PerformOpenMPImplicitIntegerConversion(Loc, ValExpr); if (Value.isInvalid()) return false; ValExpr = Value.get(); // The expression must evaluate to a non-negative integer value. llvm::APSInt Result; if (ValExpr->isIntegerConstantExpr(Result, SemaRef.Context) && Result.isSigned() && !((!StrictlyPositive && Result.isNonNegative()) || (StrictlyPositive && Result.isStrictlyPositive()))) { SemaRef.Diag(Loc, diag::err_omp_negative_expression_in_clause) << getOpenMPClauseName(CKind) << (StrictlyPositive ? 1 : 0) << ValExpr->getSourceRange(); return false; } } return true; } OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = NumThreads; // OpenMP [2.5, Restrictions] // The num_threads expression must evaluate to a positive integer value. if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_num_threads, /*StrictlyPositive=*/true)) return nullptr; return new (Context) OMPNumThreadsClause(ValExpr, StartLoc, LParenLoc, EndLoc); } ExprResult Sema::VerifyPositiveIntegerConstantInClause(Expr *E, OpenMPClauseKind CKind, bool StrictlyPositive) { if (!E) return ExprError(); if (E->isValueDependent() || E->isTypeDependent() || E->isInstantiationDependent() || E->containsUnexpandedParameterPack()) return E; llvm::APSInt Result; ExprResult ICE = VerifyIntegerConstantExpression(E, &Result); if (ICE.isInvalid()) return ExprError(); if ((StrictlyPositive && !Result.isStrictlyPositive()) || (!StrictlyPositive && !Result.isNonNegative())) { Diag(E->getExprLoc(), diag::err_omp_negative_expression_in_clause) << getOpenMPClauseName(CKind) << (StrictlyPositive ? 1 : 0) << E->getSourceRange(); return ExprError(); } if (CKind == OMPC_aligned && !Result.isPowerOf2()) { Diag(E->getExprLoc(), diag::warn_omp_alignment_not_power_of_two) << E->getSourceRange(); return ExprError(); } if (CKind == OMPC_collapse && DSAStack->getAssociatedLoops() == 1) DSAStack->setAssociatedLoops(Result.getExtValue()); else if (CKind == OMPC_ordered) DSAStack->setAssociatedLoops(Result.getExtValue()); return ICE; } OMPClause *Sema::ActOnOpenMPSafelenClause(Expr *Len, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { // OpenMP [2.8.1, simd construct, Description] // The parameter of the safelen clause must be a constant // positive integer expression. ExprResult Safelen = VerifyPositiveIntegerConstantInClause(Len, OMPC_safelen); if (Safelen.isInvalid()) return nullptr; return new (Context) OMPSafelenClause(Safelen.get(), StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPSimdlenClause(Expr *Len, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { // OpenMP [2.8.1, simd construct, Description] // The parameter of the simdlen clause must be a constant // positive integer expression. ExprResult Simdlen = VerifyPositiveIntegerConstantInClause(Len, OMPC_simdlen); if (Simdlen.isInvalid()) return nullptr; return new (Context) OMPSimdlenClause(Simdlen.get(), StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPCollapseClause(Expr *NumForLoops, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { // OpenMP [2.7.1, loop construct, Description] // OpenMP [2.8.1, simd construct, Description] // OpenMP [2.9.6, distribute construct, Description] // The parameter of the collapse clause must be a constant // positive integer expression. ExprResult NumForLoopsResult = VerifyPositiveIntegerConstantInClause(NumForLoops, OMPC_collapse); if (NumForLoopsResult.isInvalid()) return nullptr; return new (Context) OMPCollapseClause(NumForLoopsResult.get(), StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPOrderedClause(SourceLocation StartLoc, SourceLocation EndLoc, SourceLocation LParenLoc, Expr *NumForLoops) { // OpenMP [2.7.1, loop construct, Description] // OpenMP [2.8.1, simd construct, Description] // OpenMP [2.9.6, distribute construct, Description] // The parameter of the ordered clause must be a constant // positive integer expression if any. if (NumForLoops && LParenLoc.isValid()) { ExprResult NumForLoopsResult = VerifyPositiveIntegerConstantInClause(NumForLoops, OMPC_ordered); if (NumForLoopsResult.isInvalid()) return nullptr; NumForLoops = NumForLoopsResult.get(); } else NumForLoops = nullptr; DSAStack->setOrderedRegion(/*IsOrdered=*/true, NumForLoops); return new (Context) OMPOrderedClause(NumForLoops, StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPSimpleClause( OpenMPClauseKind Kind, unsigned Argument, SourceLocation ArgumentLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { OMPClause *Res = nullptr; switch (Kind) { case OMPC_default: Res = ActOnOpenMPDefaultClause(static_cast(Argument), ArgumentLoc, StartLoc, LParenLoc, EndLoc); break; case OMPC_proc_bind: Res = ActOnOpenMPProcBindClause( static_cast(Argument), ArgumentLoc, StartLoc, LParenLoc, EndLoc); break; case OMPC_if: case OMPC_final: case OMPC_num_threads: case OMPC_safelen: case OMPC_simdlen: case OMPC_collapse: case OMPC_schedule: case OMPC_private: case OMPC_firstprivate: case OMPC_lastprivate: case OMPC_shared: case OMPC_reduction: case OMPC_linear: case OMPC_aligned: case OMPC_copyin: case OMPC_copyprivate: case OMPC_ordered: case OMPC_nowait: case OMPC_untied: case OMPC_mergeable: case OMPC_threadprivate: case OMPC_flush: case OMPC_read: case OMPC_write: case OMPC_update: case OMPC_capture: case OMPC_seq_cst: case OMPC_depend: case OMPC_device: case OMPC_threads: case OMPC_simd: case OMPC_map: case OMPC_num_teams: case OMPC_thread_limit: case OMPC_priority: case OMPC_grainsize: case OMPC_nogroup: case OMPC_num_tasks: case OMPC_hint: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } return Res; } static std::string getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last, ArrayRef Exclude = llvm::None) { std::string Values; unsigned Bound = Last >= 2 ? Last - 2 : 0; unsigned Skipped = Exclude.size(); auto S = Exclude.begin(), E = Exclude.end(); for (unsigned i = First; i < Last; ++i) { if (std::find(S, E, i) != E) { --Skipped; continue; } Values += "'"; Values += getOpenMPSimpleClauseTypeName(K, i); Values += "'"; if (i == Bound - Skipped) Values += " or "; else if (i != Bound + 1 - Skipped) Values += ", "; } return Values; } OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind, SourceLocation KindKwLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { if (Kind == OMPC_DEFAULT_unknown) { static_assert(OMPC_DEFAULT_unknown > 0, "OMPC_DEFAULT_unknown not greater than 0"); Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) << getListOfPossibleValues(OMPC_default, /*First=*/0, /*Last=*/OMPC_DEFAULT_unknown) << getOpenMPClauseName(OMPC_default); return nullptr; } switch (Kind) { case OMPC_DEFAULT_none: DSAStack->setDefaultDSANone(KindKwLoc); break; case OMPC_DEFAULT_shared: DSAStack->setDefaultDSAShared(KindKwLoc); break; case OMPC_DEFAULT_unknown: llvm_unreachable("Clause kind is not allowed."); break; } return new (Context) OMPDefaultClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind, SourceLocation KindKwLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { if (Kind == OMPC_PROC_BIND_unknown) { Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) << getListOfPossibleValues(OMPC_proc_bind, /*First=*/0, /*Last=*/OMPC_PROC_BIND_unknown) << getOpenMPClauseName(OMPC_proc_bind); return nullptr; } return new (Context) OMPProcBindClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( OpenMPClauseKind Kind, ArrayRef Argument, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, ArrayRef ArgumentLoc, SourceLocation DelimLoc, SourceLocation EndLoc) { OMPClause *Res = nullptr; switch (Kind) { case OMPC_schedule: enum { Modifier1, Modifier2, ScheduleKind, NumberOfElements }; assert(Argument.size() == NumberOfElements && ArgumentLoc.size() == NumberOfElements); Res = ActOnOpenMPScheduleClause( static_cast(Argument[Modifier1]), static_cast(Argument[Modifier2]), static_cast(Argument[ScheduleKind]), Expr, StartLoc, LParenLoc, ArgumentLoc[Modifier1], ArgumentLoc[Modifier2], ArgumentLoc[ScheduleKind], DelimLoc, EndLoc); break; case OMPC_if: assert(Argument.size() == 1 && ArgumentLoc.size() == 1); Res = ActOnOpenMPIfClause(static_cast(Argument.back()), Expr, StartLoc, LParenLoc, ArgumentLoc.back(), DelimLoc, EndLoc); break; case OMPC_final: case OMPC_num_threads: case OMPC_safelen: case OMPC_simdlen: case OMPC_collapse: case OMPC_default: case OMPC_proc_bind: case OMPC_private: case OMPC_firstprivate: case OMPC_lastprivate: case OMPC_shared: case OMPC_reduction: case OMPC_linear: case OMPC_aligned: case OMPC_copyin: case OMPC_copyprivate: case OMPC_ordered: case OMPC_nowait: case OMPC_untied: case OMPC_mergeable: case OMPC_threadprivate: case OMPC_flush: case OMPC_read: case OMPC_write: case OMPC_update: case OMPC_capture: case OMPC_seq_cst: case OMPC_depend: case OMPC_device: case OMPC_threads: case OMPC_simd: case OMPC_map: case OMPC_num_teams: case OMPC_thread_limit: case OMPC_priority: case OMPC_grainsize: case OMPC_nogroup: case OMPC_num_tasks: case OMPC_hint: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } return Res; } static bool checkScheduleModifiers(Sema &S, OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2, SourceLocation M1Loc, SourceLocation M2Loc) { if (M1 == OMPC_SCHEDULE_MODIFIER_unknown && M1Loc.isValid()) { SmallVector Excluded; if (M2 != OMPC_SCHEDULE_MODIFIER_unknown) Excluded.push_back(M2); if (M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic) Excluded.push_back(OMPC_SCHEDULE_MODIFIER_monotonic); if (M2 == OMPC_SCHEDULE_MODIFIER_monotonic) Excluded.push_back(OMPC_SCHEDULE_MODIFIER_nonmonotonic); S.Diag(M1Loc, diag::err_omp_unexpected_clause_value) << getListOfPossibleValues(OMPC_schedule, /*First=*/OMPC_SCHEDULE_MODIFIER_unknown + 1, /*Last=*/OMPC_SCHEDULE_MODIFIER_last, Excluded) << getOpenMPClauseName(OMPC_schedule); return true; } return false; } OMPClause *Sema::ActOnOpenMPScheduleClause( OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2, OpenMPScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation M1Loc, SourceLocation M2Loc, SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc) { if (checkScheduleModifiers(*this, M1, M2, M1Loc, M2Loc) || checkScheduleModifiers(*this, M2, M1, M2Loc, M1Loc)) return nullptr; // OpenMP, 2.7.1, Loop Construct, Restrictions // Either the monotonic modifier or the nonmonotonic modifier can be specified // but not both. if ((M1 == M2 && M1 != OMPC_SCHEDULE_MODIFIER_unknown) || (M1 == OMPC_SCHEDULE_MODIFIER_monotonic && M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic) || (M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic && M2 == OMPC_SCHEDULE_MODIFIER_monotonic)) { Diag(M2Loc, diag::err_omp_unexpected_schedule_modifier) << getOpenMPSimpleClauseTypeName(OMPC_schedule, M2) << getOpenMPSimpleClauseTypeName(OMPC_schedule, M1); return nullptr; } if (Kind == OMPC_SCHEDULE_unknown) { std::string Values; if (M1Loc.isInvalid() && M2Loc.isInvalid()) { unsigned Exclude[] = {OMPC_SCHEDULE_unknown}; Values = getListOfPossibleValues(OMPC_schedule, /*First=*/0, /*Last=*/OMPC_SCHEDULE_MODIFIER_last, Exclude); } else { Values = getListOfPossibleValues(OMPC_schedule, /*First=*/0, /*Last=*/OMPC_SCHEDULE_unknown); } Diag(KindLoc, diag::err_omp_unexpected_clause_value) << Values << getOpenMPClauseName(OMPC_schedule); return nullptr; } // OpenMP, 2.7.1, Loop Construct, Restrictions // The nonmonotonic modifier can only be specified with schedule(dynamic) or // schedule(guided). if ((M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic || M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic) && Kind != OMPC_SCHEDULE_dynamic && Kind != OMPC_SCHEDULE_guided) { Diag(M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic ? M1Loc : M2Loc, diag::err_omp_schedule_nonmonotonic_static); return nullptr; } Expr *ValExpr = ChunkSize; Expr *HelperValExpr = nullptr; if (ChunkSize) { if (!ChunkSize->isValueDependent() && !ChunkSize->isTypeDependent() && !ChunkSize->isInstantiationDependent() && !ChunkSize->containsUnexpandedParameterPack()) { SourceLocation ChunkSizeLoc = ChunkSize->getLocStart(); ExprResult Val = PerformOpenMPImplicitIntegerConversion(ChunkSizeLoc, ChunkSize); if (Val.isInvalid()) return nullptr; ValExpr = Val.get(); // OpenMP [2.7.1, Restrictions] // chunk_size must be a loop invariant integer expression with a positive // value. llvm::APSInt Result; if (ValExpr->isIntegerConstantExpr(Result, Context)) { if (Result.isSigned() && !Result.isStrictlyPositive()) { Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause) << "schedule" << 1 << ChunkSize->getSourceRange(); return nullptr; } } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) { auto *ImpVar = buildVarDecl(*this, ChunkSize->getExprLoc(), ChunkSize->getType(), ".chunk."); auto *ImpVarRef = buildDeclRefExpr(*this, ImpVar, ChunkSize->getType(), ChunkSize->getExprLoc(), /*RefersToCapture=*/true); HelperValExpr = ImpVarRef; } } } return new (Context) OMPScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc, Kind, ValExpr, HelperValExpr, M1, M1Loc, M2, M2Loc); } OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, SourceLocation StartLoc, SourceLocation EndLoc) { OMPClause *Res = nullptr; switch (Kind) { case OMPC_ordered: Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc); break; case OMPC_nowait: Res = ActOnOpenMPNowaitClause(StartLoc, EndLoc); break; case OMPC_untied: Res = ActOnOpenMPUntiedClause(StartLoc, EndLoc); break; case OMPC_mergeable: Res = ActOnOpenMPMergeableClause(StartLoc, EndLoc); break; case OMPC_read: Res = ActOnOpenMPReadClause(StartLoc, EndLoc); break; case OMPC_write: Res = ActOnOpenMPWriteClause(StartLoc, EndLoc); break; case OMPC_update: Res = ActOnOpenMPUpdateClause(StartLoc, EndLoc); break; case OMPC_capture: Res = ActOnOpenMPCaptureClause(StartLoc, EndLoc); break; case OMPC_seq_cst: Res = ActOnOpenMPSeqCstClause(StartLoc, EndLoc); break; case OMPC_threads: Res = ActOnOpenMPThreadsClause(StartLoc, EndLoc); break; case OMPC_simd: Res = ActOnOpenMPSIMDClause(StartLoc, EndLoc); break; case OMPC_nogroup: Res = ActOnOpenMPNogroupClause(StartLoc, EndLoc); break; case OMPC_if: case OMPC_final: case OMPC_num_threads: case OMPC_safelen: case OMPC_simdlen: case OMPC_collapse: case OMPC_schedule: case OMPC_private: case OMPC_firstprivate: case OMPC_lastprivate: case OMPC_shared: case OMPC_reduction: case OMPC_linear: case OMPC_aligned: case OMPC_copyin: case OMPC_copyprivate: case OMPC_default: case OMPC_proc_bind: case OMPC_threadprivate: case OMPC_flush: case OMPC_depend: case OMPC_device: case OMPC_map: case OMPC_num_teams: case OMPC_thread_limit: case OMPC_priority: case OMPC_grainsize: case OMPC_num_tasks: case OMPC_hint: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } return Res; } OMPClause *Sema::ActOnOpenMPNowaitClause(SourceLocation StartLoc, SourceLocation EndLoc) { DSAStack->setNowaitRegion(); return new (Context) OMPNowaitClause(StartLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPUntiedClause(SourceLocation StartLoc, SourceLocation EndLoc) { return new (Context) OMPUntiedClause(StartLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPMergeableClause(SourceLocation StartLoc, SourceLocation EndLoc) { return new (Context) OMPMergeableClause(StartLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPReadClause(SourceLocation StartLoc, SourceLocation EndLoc) { return new (Context) OMPReadClause(StartLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPWriteClause(SourceLocation StartLoc, SourceLocation EndLoc) { return new (Context) OMPWriteClause(StartLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPUpdateClause(SourceLocation StartLoc, SourceLocation EndLoc) { return new (Context) OMPUpdateClause(StartLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPCaptureClause(SourceLocation StartLoc, SourceLocation EndLoc) { return new (Context) OMPCaptureClause(StartLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPSeqCstClause(SourceLocation StartLoc, SourceLocation EndLoc) { return new (Context) OMPSeqCstClause(StartLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPThreadsClause(SourceLocation StartLoc, SourceLocation EndLoc) { return new (Context) OMPThreadsClause(StartLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPSIMDClause(SourceLocation StartLoc, SourceLocation EndLoc) { return new (Context) OMPSIMDClause(StartLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPNogroupClause(SourceLocation StartLoc, SourceLocation EndLoc) { return new (Context) OMPNogroupClause(StartLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPVarListClause( OpenMPClauseKind Kind, ArrayRef VarList, Expr *TailExpr, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, OpenMPDependClauseKind DepKind, OpenMPLinearClauseKind LinKind, OpenMPMapClauseKind MapTypeModifier, OpenMPMapClauseKind MapType, SourceLocation DepLinMapLoc) { OMPClause *Res = nullptr; switch (Kind) { case OMPC_private: Res = ActOnOpenMPPrivateClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_firstprivate: Res = ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_lastprivate: Res = ActOnOpenMPLastprivateClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_shared: Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_reduction: Res = ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec, ReductionId); break; case OMPC_linear: Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc, LinKind, DepLinMapLoc, ColonLoc, EndLoc); break; case OMPC_aligned: Res = ActOnOpenMPAlignedClause(VarList, TailExpr, StartLoc, LParenLoc, ColonLoc, EndLoc); break; case OMPC_copyin: Res = ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_copyprivate: Res = ActOnOpenMPCopyprivateClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_flush: Res = ActOnOpenMPFlushClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_depend: Res = ActOnOpenMPDependClause(DepKind, DepLinMapLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_map: Res = ActOnOpenMPMapClause(MapTypeModifier, MapType, DepLinMapLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_if: case OMPC_final: case OMPC_num_threads: case OMPC_safelen: case OMPC_simdlen: case OMPC_collapse: case OMPC_default: case OMPC_proc_bind: case OMPC_schedule: case OMPC_ordered: case OMPC_nowait: case OMPC_untied: case OMPC_mergeable: case OMPC_threadprivate: case OMPC_read: case OMPC_write: case OMPC_update: case OMPC_capture: case OMPC_seq_cst: case OMPC_device: case OMPC_threads: case OMPC_simd: case OMPC_num_teams: case OMPC_thread_limit: case OMPC_priority: case OMPC_grainsize: case OMPC_nogroup: case OMPC_num_tasks: case OMPC_hint: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } return Res; } OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector Vars; SmallVector PrivateCopies; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP private clause."); if (isa(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); PrivateCopies.push_back(nullptr); continue; } SourceLocation ELoc = RefExpr->getExprLoc(); // OpenMP [2.1, C/C++] // A list item is a variable name. // OpenMP [2.9.3.3, Restrictions, p.1] // A variable that is part of another variable (as an array or // structure element) cannot appear in a private clause. DeclRefExpr *DE = dyn_cast_or_null(RefExpr); if (!DE || !isa(DE->getDecl())) { Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); continue; } Decl *D = DE->getDecl(); VarDecl *VD = cast(D); QualType Type = VD->getType(); if (Type->isDependentType() || Type->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); PrivateCopies.push_back(nullptr); continue; } // OpenMP [2.9.3.3, Restrictions, C/C++, p.3] // A variable that appears in a private clause must not have an incomplete // type or a reference type. if (RequireCompleteType(ELoc, Type, diag::err_omp_private_incomplete_type)) { continue; } Type = Type.getNonReferenceType(); // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] // Variables with the predetermined data-sharing attributes may not be // listed in data-sharing attributes clauses, except for the cases // listed below. For these exceptions only, listing a predetermined // variable in a data-sharing attribute clause is allowed and overrides // the variable's predetermined data-sharing attributes. DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_private); ReportOriginalDSA(*this, DSAStack, VD, DVar); continue; } // Variably modified types are not supported for tasks. if (!Type->isAnyPointerType() && Type->isVariablyModifiedType() && DSAStack->getCurrentDirective() == OMPD_task) { Diag(ELoc, diag::err_omp_variably_modified_type_not_supported) << getOpenMPClauseName(OMPC_private) << Type << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; continue; } // OpenMP [2.9.3.3, Restrictions, C/C++, p.1] // A variable of class type (or array thereof) that appears in a private // clause requires an accessible, unambiguous default constructor for the // class type. // Generate helper private variable and initialize it with the default // value. The address of the original variable is replaced by the address of // the new private variable in CodeGen. This new variable is not added to // IdResolver, so the code in the OpenMP region uses original variable for // proper diagnostics. Type = Type.getUnqualifiedType(); auto VDPrivate = buildVarDecl(*this, DE->getExprLoc(), Type, VD->getName(), VD->hasAttrs() ? &VD->getAttrs() : nullptr); ActOnUninitializedDecl(VDPrivate, /*TypeMayContainAuto=*/false); if (VDPrivate->isInvalidDecl()) continue; auto VDPrivateRefExpr = buildDeclRefExpr( *this, VDPrivate, DE->getType().getUnqualifiedType(), DE->getExprLoc()); DSAStack->addDSA(VD, DE, OMPC_private); Vars.push_back(DE); PrivateCopies.push_back(VDPrivateRefExpr); } if (Vars.empty()) return nullptr; return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars, PrivateCopies); } namespace { class DiagsUninitializedSeveretyRAII { private: DiagnosticsEngine &Diags; SourceLocation SavedLoc; bool IsIgnored; public: DiagsUninitializedSeveretyRAII(DiagnosticsEngine &Diags, SourceLocation Loc, bool IsIgnored) : Diags(Diags), SavedLoc(Loc), IsIgnored(IsIgnored) { if (!IsIgnored) { Diags.setSeverity(/*Diag*/ diag::warn_uninit_self_reference_in_init, /*Map*/ diag::Severity::Ignored, Loc); } } ~DiagsUninitializedSeveretyRAII() { if (!IsIgnored) Diags.popMappings(SavedLoc); } }; } OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector Vars; SmallVector PrivateCopies; SmallVector Inits; bool IsImplicitClause = StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid(); auto ImplicitClauseLoc = DSAStack->getConstructLoc(); for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP firstprivate clause."); if (isa(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); PrivateCopies.push_back(nullptr); Inits.push_back(nullptr); continue; } SourceLocation ELoc = IsImplicitClause ? ImplicitClauseLoc : RefExpr->getExprLoc(); // OpenMP [2.1, C/C++] // A list item is a variable name. // OpenMP [2.9.3.3, Restrictions, p.1] // A variable that is part of another variable (as an array or // structure element) cannot appear in a private clause. DeclRefExpr *DE = dyn_cast_or_null(RefExpr); if (!DE || !isa(DE->getDecl())) { Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); continue; } Decl *D = DE->getDecl(); VarDecl *VD = cast(D); QualType Type = VD->getType(); if (Type->isDependentType() || Type->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); PrivateCopies.push_back(nullptr); Inits.push_back(nullptr); continue; } // OpenMP [2.9.3.3, Restrictions, C/C++, p.3] // A variable that appears in a private clause must not have an incomplete // type or a reference type. if (RequireCompleteType(ELoc, Type, diag::err_omp_firstprivate_incomplete_type)) { continue; } Type = Type.getNonReferenceType(); // OpenMP [2.9.3.4, Restrictions, C/C++, p.1] // A variable of class type (or array thereof) that appears in a private // clause requires an accessible, unambiguous copy constructor for the // class type. auto ElemType = Context.getBaseElementType(Type).getNonReferenceType(); // If an implicit firstprivate variable found it was checked already. if (!IsImplicitClause) { DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); bool IsConstant = ElemType.isConstant(Context); // OpenMP [2.4.13, Data-sharing Attribute Clauses] // A list item that specifies a given variable may not appear in more // than one clause on the same directive, except that a variable may be // specified in both firstprivate and lastprivate clauses. if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate && DVar.CKind != OMPC_lastprivate && DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_firstprivate); ReportOriginalDSA(*this, DSAStack, VD, DVar); continue; } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] // Variables with the predetermined data-sharing attributes may not be // listed in data-sharing attributes clauses, except for the cases // listed below. For these exceptions only, listing a predetermined // variable in a data-sharing attribute clause is allowed and overrides // the variable's predetermined data-sharing attributes. // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, p.2] // Variables with const-qualified type having no mutable member may be // listed in a firstprivate clause, even if they are static data members. if (!(IsConstant || VD->isStaticDataMember()) && !DVar.RefExpr && DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_firstprivate); ReportOriginalDSA(*this, DSAStack, VD, DVar); continue; } OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); // OpenMP [2.9.3.4, Restrictions, p.2] // A list item that is private within a parallel region must not appear // in a firstprivate clause on a worksharing construct if any of the // worksharing regions arising from the worksharing construct ever bind // to any of the parallel regions arising from the parallel construct. if (isOpenMPWorksharingDirective(CurrDir) && !isOpenMPParallelDirective(CurrDir)) { DVar = DSAStack->getImplicitDSA(VD, true); if (DVar.CKind != OMPC_shared && (isOpenMPParallelDirective(DVar.DKind) || DVar.DKind == OMPD_unknown)) { Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_firstprivate) << getOpenMPClauseName(OMPC_shared); ReportOriginalDSA(*this, DSAStack, VD, DVar); continue; } } // OpenMP [2.9.3.4, Restrictions, p.3] // A list item that appears in a reduction clause of a parallel construct // must not appear in a firstprivate clause on a worksharing or task // construct if any of the worksharing or task regions arising from the // worksharing or task construct ever bind to any of the parallel regions // arising from the parallel construct. // OpenMP [2.9.3.4, Restrictions, p.4] // A list item that appears in a reduction clause in worksharing // construct must not appear in a firstprivate clause in a task construct // encountered during execution of any of the worksharing regions arising // from the worksharing construct. if (CurrDir == OMPD_task) { DVar = DSAStack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction), [](OpenMPDirectiveKind K) -> bool { return isOpenMPParallelDirective(K) || isOpenMPWorksharingDirective(K); }, false); if (DVar.CKind == OMPC_reduction && (isOpenMPParallelDirective(DVar.DKind) || isOpenMPWorksharingDirective(DVar.DKind))) { Diag(ELoc, diag::err_omp_parallel_reduction_in_task_firstprivate) << getOpenMPDirectiveName(DVar.DKind); ReportOriginalDSA(*this, DSAStack, VD, DVar); continue; } } // OpenMP 4.5 [2.15.3.4, Restrictions, p.3] // A list item that is private within a teams region must not appear in a // firstprivate clause on a distribute construct if any of the distribute // regions arising from the distribute construct ever bind to any of the // teams regions arising from the teams construct. // OpenMP 4.5 [2.15.3.4, Restrictions, p.3] // A list item that appears in a reduction clause of a teams construct // must not appear in a firstprivate clause on a distribute construct if // any of the distribute regions arising from the distribute construct // ever bind to any of the teams regions arising from the teams construct. // OpenMP 4.5 [2.10.8, Distribute Construct, p.3] // A list item may appear in a firstprivate or lastprivate clause but not // both. if (CurrDir == OMPD_distribute) { DVar = DSAStack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_private), [](OpenMPDirectiveKind K) -> bool { return isOpenMPTeamsDirective(K); }, false); if (DVar.CKind == OMPC_private && isOpenMPTeamsDirective(DVar.DKind)) { Diag(ELoc, diag::err_omp_firstprivate_distribute_private_teams); ReportOriginalDSA(*this, DSAStack, VD, DVar); continue; } DVar = DSAStack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction), [](OpenMPDirectiveKind K) -> bool { return isOpenMPTeamsDirective(K); }, false); if (DVar.CKind == OMPC_reduction && isOpenMPTeamsDirective(DVar.DKind)) { Diag(ELoc, diag::err_omp_firstprivate_distribute_in_teams_reduction); ReportOriginalDSA(*this, DSAStack, VD, DVar); continue; } DVar = DSAStack->getTopDSA(VD, false); if (DVar.CKind == OMPC_lastprivate) { Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute); ReportOriginalDSA(*this, DSAStack, VD, DVar); continue; } } } // Variably modified types are not supported for tasks. if (!Type->isAnyPointerType() && Type->isVariablyModifiedType() && DSAStack->getCurrentDirective() == OMPD_task) { Diag(ELoc, diag::err_omp_variably_modified_type_not_supported) << getOpenMPClauseName(OMPC_firstprivate) << Type << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; continue; } Type = Type.getUnqualifiedType(); auto VDPrivate = buildVarDecl(*this, ELoc, Type, VD->getName(), VD->hasAttrs() ? &VD->getAttrs() : nullptr); // Generate helper private variable and initialize it with the value of the // original variable. The address of the original variable is replaced by // the address of the new private variable in the CodeGen. This new variable // is not added to IdResolver, so the code in the OpenMP region uses // original variable for proper diagnostics and variable capturing. Expr *VDInitRefExpr = nullptr; // For arrays generate initializer for single element and replace it by the // original array element in CodeGen. if (Type->isArrayType()) { auto VDInit = buildVarDecl(*this, DE->getExprLoc(), ElemType, VD->getName()); VDInitRefExpr = buildDeclRefExpr(*this, VDInit, ElemType, ELoc); auto Init = DefaultLvalueConversion(VDInitRefExpr).get(); ElemType = ElemType.getUnqualifiedType(); auto *VDInitTemp = buildVarDecl(*this, DE->getLocStart(), ElemType, ".firstprivate.temp"); InitializedEntity Entity = InitializedEntity::InitializeVariable(VDInitTemp); InitializationKind Kind = InitializationKind::CreateCopy(ELoc, ELoc); InitializationSequence InitSeq(*this, Entity, Kind, Init); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Init); if (Result.isInvalid()) VDPrivate->setInvalidDecl(); else VDPrivate->setInit(Result.getAs()); // Remove temp variable declaration. Context.Deallocate(VDInitTemp); } else { auto *VDInit = buildVarDecl(*this, DE->getLocStart(), Type, ".firstprivate.temp"); VDInitRefExpr = buildDeclRefExpr(*this, VDInit, DE->getType(), DE->getExprLoc()); AddInitializerToDecl(VDPrivate, DefaultLvalueConversion(VDInitRefExpr).get(), /*DirectInit=*/false, /*TypeMayContainAuto=*/false); } if (VDPrivate->isInvalidDecl()) { if (IsImplicitClause) { Diag(DE->getExprLoc(), diag::note_omp_task_predetermined_firstprivate_here); } continue; } CurContext->addDecl(VDPrivate); auto VDPrivateRefExpr = buildDeclRefExpr( *this, VDPrivate, DE->getType().getUnqualifiedType(), DE->getExprLoc()); DSAStack->addDSA(VD, DE, OMPC_firstprivate); Vars.push_back(DE); PrivateCopies.push_back(VDPrivateRefExpr); Inits.push_back(VDInitRefExpr); } if (Vars.empty()) return nullptr; return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars, PrivateCopies, Inits); } OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector Vars; SmallVector SrcExprs; SmallVector DstExprs; SmallVector AssignmentOps; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP lastprivate clause."); if (isa(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); SrcExprs.push_back(nullptr); DstExprs.push_back(nullptr); AssignmentOps.push_back(nullptr); continue; } SourceLocation ELoc = RefExpr->getExprLoc(); // OpenMP [2.1, C/C++] // A list item is a variable name. // OpenMP [2.14.3.5, Restrictions, p.1] // A variable that is part of another variable (as an array or structure // element) cannot appear in a lastprivate clause. DeclRefExpr *DE = dyn_cast_or_null(RefExpr); if (!DE || !isa(DE->getDecl())) { Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); continue; } Decl *D = DE->getDecl(); VarDecl *VD = cast(D); QualType Type = VD->getType(); if (Type->isDependentType() || Type->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); SrcExprs.push_back(nullptr); DstExprs.push_back(nullptr); AssignmentOps.push_back(nullptr); continue; } // OpenMP [2.14.3.5, Restrictions, C/C++, p.2] // A variable that appears in a lastprivate clause must not have an // incomplete type or a reference type. if (RequireCompleteType(ELoc, Type, diag::err_omp_lastprivate_incomplete_type)) { continue; } Type = Type.getNonReferenceType(); // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] // Variables with the predetermined data-sharing attributes may not be // listed in data-sharing attributes clauses, except for the cases // listed below. DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_lastprivate && DVar.CKind != OMPC_firstprivate && (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_lastprivate); ReportOriginalDSA(*this, DSAStack, VD, DVar); continue; } OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); // OpenMP [2.14.3.5, Restrictions, p.2] // A list item that is private within a parallel region, or that appears in // the reduction clause of a parallel construct, must not appear in a // lastprivate clause on a worksharing construct if any of the corresponding // worksharing regions ever binds to any of the corresponding parallel // regions. DSAStackTy::DSAVarData TopDVar = DVar; if (isOpenMPWorksharingDirective(CurrDir) && !isOpenMPParallelDirective(CurrDir)) { DVar = DSAStack->getImplicitDSA(VD, true); if (DVar.CKind != OMPC_shared) { Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_lastprivate) << getOpenMPClauseName(OMPC_shared); ReportOriginalDSA(*this, DSAStack, VD, DVar); continue; } } // OpenMP [2.14.3.5, Restrictions, C++, p.1,2] // A variable of class type (or array thereof) that appears in a // lastprivate clause requires an accessible, unambiguous default // constructor for the class type, unless the list item is also specified // in a firstprivate clause. // A variable of class type (or array thereof) that appears in a // lastprivate clause requires an accessible, unambiguous copy assignment // operator for the class type. Type = Context.getBaseElementType(Type).getNonReferenceType(); auto *SrcVD = buildVarDecl(*this, DE->getLocStart(), Type.getUnqualifiedType(), ".lastprivate.src", VD->hasAttrs() ? &VD->getAttrs() : nullptr); auto *PseudoSrcExpr = buildDeclRefExpr( *this, SrcVD, Type.getUnqualifiedType(), DE->getExprLoc()); auto *DstVD = buildVarDecl(*this, DE->getLocStart(), Type, ".lastprivate.dst", VD->hasAttrs() ? &VD->getAttrs() : nullptr); auto *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, Type, DE->getExprLoc()); // For arrays generate assignment operation for single element and replace // it by the original array element in CodeGen. auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign, PseudoDstExpr, PseudoSrcExpr); if (AssignmentOp.isInvalid()) continue; AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(), /*DiscardedValue=*/true); if (AssignmentOp.isInvalid()) continue; // OpenMP 4.5 [2.10.8, Distribute Construct, p.3] // A list item may appear in a firstprivate or lastprivate clause but not // both. if (CurrDir == OMPD_distribute) { DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); if (DVar.CKind == OMPC_firstprivate) { Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute); ReportOriginalDSA(*this, DSAStack, VD, DVar); continue; } } if (TopDVar.CKind != OMPC_firstprivate) DSAStack->addDSA(VD, DE, OMPC_lastprivate); Vars.push_back(DE); SrcExprs.push_back(PseudoSrcExpr); DstExprs.push_back(PseudoDstExpr); AssignmentOps.push_back(AssignmentOp.get()); } if (Vars.empty()) return nullptr; return OMPLastprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars, SrcExprs, DstExprs, AssignmentOps); } OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector Vars; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP shared clause."); if (isa(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); continue; } SourceLocation ELoc = RefExpr->getExprLoc(); // OpenMP [2.1, C/C++] // A list item is a variable name. // OpenMP [2.14.3.2, Restrictions, p.1] // A variable that is part of another variable (as an array or structure // element) cannot appear in a shared unless it is a static data member // of a C++ class. DeclRefExpr *DE = dyn_cast(RefExpr); if (!DE || !isa(DE->getDecl())) { Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); continue; } Decl *D = DE->getDecl(); VarDecl *VD = cast(D); QualType Type = VD->getType(); if (Type->isDependentType() || Type->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); continue; } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] // Variables with the predetermined data-sharing attributes may not be // listed in data-sharing attributes clauses, except for the cases // listed below. For these exceptions only, listing a predetermined // variable in a data-sharing attribute clause is allowed and overrides // the variable's predetermined data-sharing attributes. DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared && DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_shared); ReportOriginalDSA(*this, DSAStack, VD, DVar); continue; } DSAStack->addDSA(VD, DE, OMPC_shared); Vars.push_back(DE); } if (Vars.empty()) return nullptr; return OMPSharedClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); } namespace { class DSARefChecker : public StmtVisitor { DSAStackTy *Stack; public: bool VisitDeclRefExpr(DeclRefExpr *E) { if (VarDecl *VD = dyn_cast(E->getDecl())) { DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD, false); if (DVar.CKind == OMPC_shared && !DVar.RefExpr) return false; if (DVar.CKind != OMPC_unknown) return true; DSAStackTy::DSAVarData DVarPrivate = Stack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(), false); if (DVarPrivate.CKind != OMPC_unknown) return true; return false; } return false; } bool VisitStmt(Stmt *S) { for (auto Child : S->children()) { if (Child && Visit(Child)) return true; } return false; } explicit DSARefChecker(DSAStackTy *S) : Stack(S) {} }; } // namespace OMPClause *Sema::ActOnOpenMPReductionClause( ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId) { // TODO: Allow scope specification search when 'declare reduction' is // supported. assert(ReductionIdScopeSpec.isEmpty() && "No support for scoped reduction identifiers yet."); auto DN = ReductionId.getName(); auto OOK = DN.getCXXOverloadedOperator(); BinaryOperatorKind BOK = BO_Comma; // OpenMP [2.14.3.6, reduction clause] // C // reduction-identifier is either an identifier or one of the following // operators: +, -, *, &, |, ^, && and || // C++ // reduction-identifier is either an id-expression or one of the following // operators: +, -, *, &, |, ^, && and || // FIXME: Only 'min' and 'max' identifiers are supported for now. switch (OOK) { case OO_Plus: case OO_Minus: BOK = BO_Add; break; case OO_Star: BOK = BO_Mul; break; case OO_Amp: BOK = BO_And; break; case OO_Pipe: BOK = BO_Or; break; case OO_Caret: BOK = BO_Xor; break; case OO_AmpAmp: BOK = BO_LAnd; break; case OO_PipePipe: BOK = BO_LOr; break; case OO_New: case OO_Delete: case OO_Array_New: case OO_Array_Delete: case OO_Slash: case OO_Percent: case OO_Tilde: case OO_Exclaim: case OO_Equal: case OO_Less: case OO_Greater: case OO_LessEqual: case OO_GreaterEqual: case OO_PlusEqual: case OO_MinusEqual: case OO_StarEqual: case OO_SlashEqual: case OO_PercentEqual: case OO_CaretEqual: case OO_AmpEqual: case OO_PipeEqual: case OO_LessLess: case OO_GreaterGreater: case OO_LessLessEqual: case OO_GreaterGreaterEqual: case OO_EqualEqual: case OO_ExclaimEqual: case OO_PlusPlus: case OO_MinusMinus: case OO_Comma: case OO_ArrowStar: case OO_Arrow: case OO_Call: case OO_Subscript: case OO_Conditional: case OO_Coawait: case NUM_OVERLOADED_OPERATORS: llvm_unreachable("Unexpected reduction identifier"); case OO_None: if (auto II = DN.getAsIdentifierInfo()) { if (II->isStr("max")) BOK = BO_GT; else if (II->isStr("min")) BOK = BO_LT; } break; } SourceRange ReductionIdRange; if (ReductionIdScopeSpec.isValid()) { ReductionIdRange.setBegin(ReductionIdScopeSpec.getBeginLoc()); } ReductionIdRange.setEnd(ReductionId.getEndLoc()); if (BOK == BO_Comma) { // Not allowed reduction identifier is found. Diag(ReductionId.getLocStart(), diag::err_omp_unknown_reduction_identifier) << ReductionIdRange; return nullptr; } SmallVector Vars; SmallVector Privates; SmallVector LHSs; SmallVector RHSs; SmallVector ReductionOps; for (auto RefExpr : VarList) { assert(RefExpr && "nullptr expr in OpenMP reduction clause."); if (isa(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); Privates.push_back(nullptr); LHSs.push_back(nullptr); RHSs.push_back(nullptr); ReductionOps.push_back(nullptr); continue; } if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() || RefExpr->isInstantiationDependent() || RefExpr->containsUnexpandedParameterPack()) { // It will be analyzed later. Vars.push_back(RefExpr); Privates.push_back(nullptr); LHSs.push_back(nullptr); RHSs.push_back(nullptr); ReductionOps.push_back(nullptr); continue; } auto ELoc = RefExpr->getExprLoc(); auto ERange = RefExpr->getSourceRange(); // OpenMP [2.1, C/C++] // A list item is a variable or array section, subject to the restrictions // specified in Section 2.4 on page 42 and in each of the sections // describing clauses and directives for which a list appears. // OpenMP [2.14.3.3, Restrictions, p.1] // A variable that is part of another variable (as an array or // structure element) cannot appear in a private clause. auto *DE = dyn_cast(RefExpr); auto *ASE = dyn_cast(RefExpr); auto *OASE = dyn_cast(RefExpr); if (!ASE && !OASE && (!DE || !isa(DE->getDecl()))) { Diag(ELoc, diag::err_omp_expected_var_name_or_array_item) << ERange; continue; } QualType Type; VarDecl *VD = nullptr; if (DE) { auto D = DE->getDecl(); VD = cast(D); Type = VD->getType(); } else if (ASE) { Type = ASE->getType(); auto *Base = ASE->getBase()->IgnoreParenImpCasts(); while (auto *TempASE = dyn_cast(Base)) Base = TempASE->getBase()->IgnoreParenImpCasts(); DE = dyn_cast(Base); if (DE) VD = dyn_cast(DE->getDecl()); if (!VD) { Diag(Base->getExprLoc(), diag::err_omp_expected_base_var_name) << 0 << Base->getSourceRange(); continue; } } else if (OASE) { auto BaseType = OMPArraySectionExpr::getBaseOriginalType(OASE->getBase()); if (auto *ATy = BaseType->getAsArrayTypeUnsafe()) Type = ATy->getElementType(); else Type = BaseType->getPointeeType(); auto *Base = OASE->getBase()->IgnoreParenImpCasts(); while (auto *TempOASE = dyn_cast(Base)) Base = TempOASE->getBase()->IgnoreParenImpCasts(); while (auto *TempASE = dyn_cast(Base)) Base = TempASE->getBase()->IgnoreParenImpCasts(); DE = dyn_cast(Base); if (DE) VD = dyn_cast(DE->getDecl()); if (!VD) { Diag(Base->getExprLoc(), diag::err_omp_expected_base_var_name) << 1 << Base->getSourceRange(); continue; } } // OpenMP [2.9.3.3, Restrictions, C/C++, p.3] // A variable that appears in a private clause must not have an incomplete // type or a reference type. if (RequireCompleteType(ELoc, Type, diag::err_omp_reduction_incomplete_type)) continue; // OpenMP [2.14.3.6, reduction clause, Restrictions] // Arrays may not appear in a reduction clause. if (Type.getNonReferenceType()->isArrayType()) { Diag(ELoc, diag::err_omp_reduction_type_array) << Type << ERange; if (!ASE && !OASE) { bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; } continue; } // OpenMP [2.14.3.6, reduction clause, Restrictions] // A list item that appears in a reduction clause must not be // const-qualified. if (Type.getNonReferenceType().isConstant(Context)) { Diag(ELoc, diag::err_omp_const_reduction_list_item) << getOpenMPClauseName(OMPC_reduction) << Type << ERange; if (!ASE && !OASE) { bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; } continue; } // OpenMP [2.9.3.6, Restrictions, C/C++, p.4] // If a list-item is a reference type then it must bind to the same object // for all threads of the team. if (!ASE && !OASE) { VarDecl *VDDef = VD->getDefinition(); if (Type->isReferenceType() && VDDef) { DSARefChecker Check(DSAStack); if (Check.Visit(VDDef->getInit())) { Diag(ELoc, diag::err_omp_reduction_ref_type_arg) << ERange; Diag(VDDef->getLocation(), diag::note_defined_here) << VDDef; continue; } } } // OpenMP [2.14.3.6, reduction clause, Restrictions] // The type of a list item that appears in a reduction clause must be valid // for the reduction-identifier. For a max or min reduction in C, the type // of the list item must be an allowed arithmetic data type: char, int, // float, double, or _Bool, possibly modified with long, short, signed, or // unsigned. For a max or min reduction in C++, the type of the list item // must be an allowed arithmetic data type: char, wchar_t, int, float, // double, or bool, possibly modified with long, short, signed, or unsigned. if ((BOK == BO_GT || BOK == BO_LT) && !(Type->isScalarType() || (getLangOpts().CPlusPlus && Type->isArithmeticType()))) { Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg) << getLangOpts().CPlusPlus; if (!ASE && !OASE) { bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; } continue; } if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) && !getLangOpts().CPlusPlus && Type->isFloatingType()) { Diag(ELoc, diag::err_omp_clause_floating_type_arg); if (!ASE && !OASE) { bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; } continue; } // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] // Variables with the predetermined data-sharing attributes may not be // listed in data-sharing attributes clauses, except for the cases // listed below. For these exceptions only, listing a predetermined // variable in a data-sharing attribute clause is allowed and overrides // the variable's predetermined data-sharing attributes. // OpenMP [2.14.3.6, Restrictions, p.3] // Any number of reduction clauses can be specified on the directive, // but a list item can appear only once in the reduction clauses for that // directive. DSAStackTy::DSAVarData DVar; DVar = DSAStack->getTopDSA(VD, false); if (DVar.CKind == OMPC_reduction) { Diag(ELoc, diag::err_omp_once_referenced) << getOpenMPClauseName(OMPC_reduction); if (DVar.RefExpr) { Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced); } } else if (DVar.CKind != OMPC_unknown) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_reduction); ReportOriginalDSA(*this, DSAStack, VD, DVar); continue; } // OpenMP [2.14.3.6, Restrictions, p.1] // A list item that appears in a reduction clause of a worksharing // construct must be shared in the parallel regions to which any of the // worksharing regions arising from the worksharing construct bind. OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); if (isOpenMPWorksharingDirective(CurrDir) && !isOpenMPParallelDirective(CurrDir)) { DVar = DSAStack->getImplicitDSA(VD, true); if (DVar.CKind != OMPC_shared) { Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_reduction) << getOpenMPClauseName(OMPC_shared); ReportOriginalDSA(*this, DSAStack, VD, DVar); continue; } } Type = Type.getNonLValueExprType(Context).getUnqualifiedType(); auto *LHSVD = buildVarDecl(*this, ELoc, Type, ".reduction.lhs", VD->hasAttrs() ? &VD->getAttrs() : nullptr); auto *RHSVD = buildVarDecl(*this, ELoc, Type, VD->getName(), VD->hasAttrs() ? &VD->getAttrs() : nullptr); auto PrivateTy = Type; if (OASE) { // For array sections only: // Create pseudo array type for private copy. The size for this array will // be generated during codegen. // For array subscripts or single variables Private Ty is the same as Type // (type of the variable or single array element). PrivateTy = Context.getVariableArrayType( Type, new (Context) OpaqueValueExpr(SourceLocation(), Context.getSizeType(), VK_RValue), ArrayType::Normal, /*IndexTypeQuals=*/0, SourceRange()); } // Private copy. auto *PrivateVD = buildVarDecl(*this, ELoc, PrivateTy, VD->getName(), VD->hasAttrs() ? &VD->getAttrs() : nullptr); // Add initializer for private variable. Expr *Init = nullptr; switch (BOK) { case BO_Add: case BO_Xor: case BO_Or: case BO_LOr: // '+', '-', '^', '|', '||' reduction ops - initializer is '0'. if (Type->isScalarType() || Type->isAnyComplexType()) { Init = ActOnIntegerConstant(ELoc, /*Val=*/0).get(); } break; case BO_Mul: case BO_LAnd: if (Type->isScalarType() || Type->isAnyComplexType()) { // '*' and '&&' reduction ops - initializer is '1'. Init = ActOnIntegerConstant(ELoc, /*Val=*/1).get(); } break; case BO_And: { // '&' reduction op - initializer is '~0'. QualType OrigType = Type; if (auto *ComplexTy = OrigType->getAs()) { Type = ComplexTy->getElementType(); } if (Type->isRealFloatingType()) { llvm::APFloat InitValue = llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type), /*isIEEE=*/true); Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true, Type, ELoc); } else if (Type->isScalarType()) { auto Size = Context.getTypeSize(Type); QualType IntTy = Context.getIntTypeForBitwidth(Size, /*Signed=*/0); llvm::APInt InitValue = llvm::APInt::getAllOnesValue(Size); Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc); } if (Init && OrigType->isAnyComplexType()) { // Init = 0xFFFF + 0xFFFFi; auto *Im = new (Context) ImaginaryLiteral(Init, OrigType); Init = CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get(); } Type = OrigType; break; } case BO_LT: case BO_GT: { // 'min' reduction op - initializer is 'Largest representable number in // the reduction list item type'. // 'max' reduction op - initializer is 'Least representable number in // the reduction list item type'. if (Type->isIntegerType() || Type->isPointerType()) { bool IsSigned = Type->hasSignedIntegerRepresentation(); auto Size = Context.getTypeSize(Type); QualType IntTy = Context.getIntTypeForBitwidth(Size, /*Signed=*/IsSigned); llvm::APInt InitValue = (BOK != BO_LT) ? IsSigned ? llvm::APInt::getSignedMinValue(Size) : llvm::APInt::getMinValue(Size) : IsSigned ? llvm::APInt::getSignedMaxValue(Size) : llvm::APInt::getMaxValue(Size); Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc); if (Type->isPointerType()) { // Cast to pointer type. auto CastExpr = BuildCStyleCastExpr( SourceLocation(), Context.getTrivialTypeSourceInfo(Type, ELoc), SourceLocation(), Init); if (CastExpr.isInvalid()) continue; Init = CastExpr.get(); } } else if (Type->isRealFloatingType()) { llvm::APFloat InitValue = llvm::APFloat::getLargest( Context.getFloatTypeSemantics(Type), BOK != BO_LT); Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true, Type, ELoc); } break; } case BO_PtrMemD: case BO_PtrMemI: case BO_MulAssign: case BO_Div: case BO_Rem: case BO_Sub: case BO_Shl: case BO_Shr: case BO_LE: case BO_GE: case BO_EQ: case BO_NE: case BO_AndAssign: case BO_XorAssign: case BO_OrAssign: case BO_Assign: case BO_AddAssign: case BO_SubAssign: case BO_DivAssign: case BO_RemAssign: case BO_ShlAssign: case BO_ShrAssign: case BO_Comma: llvm_unreachable("Unexpected reduction operation"); } if (Init) { AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false, /*TypeMayContainAuto=*/false); } else ActOnUninitializedDecl(RHSVD, /*TypeMayContainAuto=*/false); if (!RHSVD->hasInit()) { Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type << ReductionIdRange; if (VD) { bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; } continue; } // Store initializer for single element in private copy. Will be used during // codegen. PrivateVD->setInit(RHSVD->getInit()); PrivateVD->setInitStyle(RHSVD->getInitStyle()); auto *LHSDRE = buildDeclRefExpr(*this, LHSVD, Type, ELoc); auto *RHSDRE = buildDeclRefExpr(*this, RHSVD, Type, ELoc); auto *PrivateDRE = buildDeclRefExpr(*this, PrivateVD, PrivateTy, ELoc); ExprResult ReductionOp = BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BOK, LHSDRE, RHSDRE); if (ReductionOp.isUsable()) { if (BOK != BO_LT && BOK != BO_GT) { ReductionOp = BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BO_Assign, LHSDRE, ReductionOp.get()); } else { auto *ConditionalOp = new (Context) ConditionalOperator( ReductionOp.get(), SourceLocation(), LHSDRE, SourceLocation(), RHSDRE, Type, VK_LValue, OK_Ordinary); ReductionOp = BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BO_Assign, LHSDRE, ConditionalOp); } ReductionOp = ActOnFinishFullExpr(ReductionOp.get()); } if (ReductionOp.isInvalid()) continue; DSAStack->addDSA(VD, DE, OMPC_reduction); Vars.push_back(RefExpr); Privates.push_back(PrivateDRE); LHSs.push_back(LHSDRE); RHSs.push_back(RHSDRE); ReductionOps.push_back(ReductionOp.get()); } if (Vars.empty()) return nullptr; return OMPReductionClause::Create( Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars, ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, Privates, LHSs, RHSs, ReductionOps); } OMPClause *Sema::ActOnOpenMPLinearClause( ArrayRef VarList, Expr *Step, SourceLocation StartLoc, SourceLocation LParenLoc, OpenMPLinearClauseKind LinKind, SourceLocation LinLoc, SourceLocation ColonLoc, SourceLocation EndLoc) { SmallVector Vars; SmallVector Privates; SmallVector Inits; if ((!LangOpts.CPlusPlus && LinKind != OMPC_LINEAR_val) || LinKind == OMPC_LINEAR_unknown) { Diag(LinLoc, diag::err_omp_wrong_linear_modifier) << LangOpts.CPlusPlus; LinKind = OMPC_LINEAR_val; } for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP linear clause."); if (isa(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); Privates.push_back(nullptr); Inits.push_back(nullptr); continue; } // OpenMP [2.14.3.7, linear clause] // A list item that appears in a linear clause is subject to the private // clause semantics described in Section 2.14.3.3 on page 159 except as // noted. In addition, the value of the new list item on each iteration // of the associated loop(s) corresponds to the value of the original // list item before entering the construct plus the logical number of // the iteration times linear-step. SourceLocation ELoc = RefExpr->getExprLoc(); // OpenMP [2.1, C/C++] // A list item is a variable name. // OpenMP [2.14.3.3, Restrictions, p.1] // A variable that is part of another variable (as an array or // structure element) cannot appear in a private clause. DeclRefExpr *DE = dyn_cast(RefExpr); if (!DE || !isa(DE->getDecl())) { Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); continue; } VarDecl *VD = cast(DE->getDecl()); // OpenMP [2.14.3.7, linear clause] // A list-item cannot appear in more than one linear clause. // A list-item that appears in a linear clause cannot appear in any // other data-sharing attribute clause. DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); if (DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_linear); ReportOriginalDSA(*this, DSAStack, VD, DVar); continue; } QualType QType = VD->getType(); if (QType->isDependentType() || QType->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); Privates.push_back(nullptr); Inits.push_back(nullptr); continue; } // A variable must not have an incomplete type or a reference type. if (RequireCompleteType(ELoc, QType, diag::err_omp_linear_incomplete_type)) { continue; } if ((LinKind == OMPC_LINEAR_uval || LinKind == OMPC_LINEAR_ref) && !QType->isReferenceType()) { Diag(ELoc, diag::err_omp_wrong_linear_modifier_non_reference) << QType << getOpenMPSimpleClauseTypeName(OMPC_linear, LinKind); continue; } QType = QType.getNonReferenceType(); // A list item must not be const-qualified. if (QType.isConstant(Context)) { Diag(ELoc, diag::err_omp_const_variable) << getOpenMPClauseName(OMPC_linear); bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; continue; } // A list item must be of integral or pointer type. QType = QType.getUnqualifiedType().getCanonicalType(); const Type *Ty = QType.getTypePtrOrNull(); if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) && !Ty->isPointerType())) { Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << QType; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; continue; } // Build private copy of original var. auto *Private = buildVarDecl(*this, ELoc, QType, VD->getName(), VD->hasAttrs() ? &VD->getAttrs() : nullptr); auto *PrivateRef = buildDeclRefExpr( *this, Private, DE->getType().getUnqualifiedType(), DE->getExprLoc()); // Build var to save initial value. VarDecl *Init = buildVarDecl(*this, ELoc, QType, ".linear.start"); Expr *InitExpr; if (LinKind == OMPC_LINEAR_uval) InitExpr = VD->getInit(); else InitExpr = DE; AddInitializerToDecl(Init, DefaultLvalueConversion(InitExpr).get(), /*DirectInit*/ false, /*TypeMayContainAuto*/ false); auto InitRef = buildDeclRefExpr( *this, Init, DE->getType().getUnqualifiedType(), DE->getExprLoc()); DSAStack->addDSA(VD, DE, OMPC_linear); Vars.push_back(DE); Privates.push_back(PrivateRef); Inits.push_back(InitRef); } if (Vars.empty()) return nullptr; Expr *StepExpr = Step; Expr *CalcStepExpr = nullptr; if (Step && !Step->isValueDependent() && !Step->isTypeDependent() && !Step->isInstantiationDependent() && !Step->containsUnexpandedParameterPack()) { SourceLocation StepLoc = Step->getLocStart(); ExprResult Val = PerformOpenMPImplicitIntegerConversion(StepLoc, Step); if (Val.isInvalid()) return nullptr; StepExpr = Val.get(); // Build var to save the step value. VarDecl *SaveVar = buildVarDecl(*this, StepLoc, StepExpr->getType(), ".linear.step"); ExprResult SaveRef = buildDeclRefExpr(*this, SaveVar, StepExpr->getType(), StepLoc); ExprResult CalcStep = BuildBinOp(CurScope, StepLoc, BO_Assign, SaveRef.get(), StepExpr); CalcStep = ActOnFinishFullExpr(CalcStep.get()); // Warn about zero linear step (it would be probably better specified as // making corresponding variables 'const'). llvm::APSInt Result; bool IsConstant = StepExpr->isIntegerConstantExpr(Result, Context); if (IsConstant && !Result.isNegative() && !Result.isStrictlyPositive()) Diag(StepLoc, diag::warn_omp_linear_step_zero) << Vars[0] << (Vars.size() > 1); if (!IsConstant && CalcStep.isUsable()) { // Calculate the step beforehand instead of doing this on each iteration. // (This is not used if the number of iterations may be kfold-ed). CalcStepExpr = CalcStep.get(); } } return OMPLinearClause::Create(Context, StartLoc, LParenLoc, LinKind, LinLoc, ColonLoc, EndLoc, Vars, Privates, Inits, StepExpr, CalcStepExpr); } static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, Expr *NumIterations, Sema &SemaRef, Scope *S) { // Walk the vars and build update/final expressions for the CodeGen. SmallVector Updates; SmallVector Finals; Expr *Step = Clause.getStep(); Expr *CalcStep = Clause.getCalcStep(); // OpenMP [2.14.3.7, linear clause] // If linear-step is not specified it is assumed to be 1. if (Step == nullptr) Step = SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get(); else if (CalcStep) Step = cast(CalcStep)->getLHS(); bool HasErrors = false; auto CurInit = Clause.inits().begin(); auto CurPrivate = Clause.privates().begin(); auto LinKind = Clause.getModifier(); for (auto &RefExpr : Clause.varlists()) { Expr *InitExpr = *CurInit; // Build privatized reference to the current linear var. auto DE = cast(RefExpr); Expr *CapturedRef; if (LinKind == OMPC_LINEAR_uval) CapturedRef = cast(DE->getDecl())->getInit(); else CapturedRef = buildDeclRefExpr(SemaRef, cast(DE->getDecl()), DE->getType().getUnqualifiedType(), DE->getExprLoc(), /*RefersToCapture=*/true); // Build update: Var = InitExpr + IV * Step ExprResult Update = BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, InitExpr, IV, Step, /* Subtract */ false); Update = SemaRef.ActOnFinishFullExpr(Update.get(), DE->getLocStart(), /*DiscardedValue=*/true); // Build final: Var = InitExpr + NumIterations * Step ExprResult Final = BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef, InitExpr, NumIterations, Step, /* Subtract */ false); Final = SemaRef.ActOnFinishFullExpr(Final.get(), DE->getLocStart(), /*DiscardedValue=*/true); if (!Update.isUsable() || !Final.isUsable()) { Updates.push_back(nullptr); Finals.push_back(nullptr); HasErrors = true; } else { Updates.push_back(Update.get()); Finals.push_back(Final.get()); } ++CurInit, ++CurPrivate; } Clause.setUpdates(Updates); Clause.setFinals(Finals); return HasErrors; } OMPClause *Sema::ActOnOpenMPAlignedClause( ArrayRef VarList, Expr *Alignment, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc) { SmallVector Vars; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP aligned clause."); if (isa(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); continue; } SourceLocation ELoc = RefExpr->getExprLoc(); // OpenMP [2.1, C/C++] // A list item is a variable name. DeclRefExpr *DE = dyn_cast(RefExpr); if (!DE || !isa(DE->getDecl())) { Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); continue; } VarDecl *VD = cast(DE->getDecl()); // OpenMP [2.8.1, simd construct, Restrictions] // The type of list items appearing in the aligned clause must be // array, pointer, reference to array, or reference to pointer. QualType QType = VD->getType(); QType = QType.getNonReferenceType().getUnqualifiedType().getCanonicalType(); const Type *Ty = QType.getTypePtrOrNull(); if (!Ty || (!Ty->isDependentType() && !Ty->isArrayType() && !Ty->isPointerType())) { Diag(ELoc, diag::err_omp_aligned_expected_array_or_ptr) << QType << getLangOpts().CPlusPlus << RefExpr->getSourceRange(); bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; continue; } // OpenMP [2.8.1, simd construct, Restrictions] // A list-item cannot appear in more than one aligned clause. if (DeclRefExpr *PrevRef = DSAStack->addUniqueAligned(VD, DE)) { Diag(ELoc, diag::err_omp_aligned_twice) << RefExpr->getSourceRange(); Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) << getOpenMPClauseName(OMPC_aligned); continue; } Vars.push_back(DE); } // OpenMP [2.8.1, simd construct, Description] // The parameter of the aligned clause, alignment, must be a constant // positive integer expression. // If no optional parameter is specified, implementation-defined default // alignments for SIMD instructions on the target platforms are assumed. if (Alignment != nullptr) { ExprResult AlignResult = VerifyPositiveIntegerConstantInClause(Alignment, OMPC_aligned); if (AlignResult.isInvalid()) return nullptr; Alignment = AlignResult.get(); } if (Vars.empty()) return nullptr; return OMPAlignedClause::Create(Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars, Alignment); } OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector Vars; SmallVector SrcExprs; SmallVector DstExprs; SmallVector AssignmentOps; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP copyin clause."); if (isa(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); SrcExprs.push_back(nullptr); DstExprs.push_back(nullptr); AssignmentOps.push_back(nullptr); continue; } SourceLocation ELoc = RefExpr->getExprLoc(); // OpenMP [2.1, C/C++] // A list item is a variable name. // OpenMP [2.14.4.1, Restrictions, p.1] // A list item that appears in a copyin clause must be threadprivate. DeclRefExpr *DE = dyn_cast(RefExpr); if (!DE || !isa(DE->getDecl())) { Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); continue; } Decl *D = DE->getDecl(); VarDecl *VD = cast(D); QualType Type = VD->getType(); if (Type->isDependentType() || Type->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); SrcExprs.push_back(nullptr); DstExprs.push_back(nullptr); AssignmentOps.push_back(nullptr); continue; } // OpenMP [2.14.4.1, Restrictions, C/C++, p.1] // A list item that appears in a copyin clause must be threadprivate. if (!DSAStack->isThreadPrivate(VD)) { Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_copyin) << getOpenMPDirectiveName(OMPD_threadprivate); continue; } // OpenMP [2.14.4.1, Restrictions, C/C++, p.2] // A variable of class type (or array thereof) that appears in a // copyin clause requires an accessible, unambiguous copy assignment // operator for the class type. auto ElemType = Context.getBaseElementType(Type).getNonReferenceType(); auto *SrcVD = buildVarDecl(*this, DE->getLocStart(), ElemType.getUnqualifiedType(), ".copyin.src", VD->hasAttrs() ? &VD->getAttrs() : nullptr); auto *PseudoSrcExpr = buildDeclRefExpr( *this, SrcVD, ElemType.getUnqualifiedType(), DE->getExprLoc()); auto *DstVD = buildVarDecl(*this, DE->getLocStart(), ElemType, ".copyin.dst", VD->hasAttrs() ? &VD->getAttrs() : nullptr); auto *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, ElemType, DE->getExprLoc()); // For arrays generate assignment operation for single element and replace // it by the original array element in CodeGen. auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign, PseudoDstExpr, PseudoSrcExpr); if (AssignmentOp.isInvalid()) continue; AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(), /*DiscardedValue=*/true); if (AssignmentOp.isInvalid()) continue; DSAStack->addDSA(VD, DE, OMPC_copyin); Vars.push_back(DE); SrcExprs.push_back(PseudoSrcExpr); DstExprs.push_back(PseudoDstExpr); AssignmentOps.push_back(AssignmentOp.get()); } if (Vars.empty()) return nullptr; return OMPCopyinClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars, SrcExprs, DstExprs, AssignmentOps); } OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector Vars; SmallVector SrcExprs; SmallVector DstExprs; SmallVector AssignmentOps; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP copyprivate clause."); if (isa(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); SrcExprs.push_back(nullptr); DstExprs.push_back(nullptr); AssignmentOps.push_back(nullptr); continue; } SourceLocation ELoc = RefExpr->getExprLoc(); // OpenMP [2.1, C/C++] // A list item is a variable name. // OpenMP [2.14.4.1, Restrictions, p.1] // A list item that appears in a copyin clause must be threadprivate. DeclRefExpr *DE = dyn_cast(RefExpr); if (!DE || !isa(DE->getDecl())) { Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); continue; } Decl *D = DE->getDecl(); VarDecl *VD = cast(D); QualType Type = VD->getType(); if (Type->isDependentType() || Type->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); SrcExprs.push_back(nullptr); DstExprs.push_back(nullptr); AssignmentOps.push_back(nullptr); continue; } // OpenMP [2.14.4.2, Restrictions, p.2] // A list item that appears in a copyprivate clause may not appear in a // private or firstprivate clause on the single construct. if (!DSAStack->isThreadPrivate(VD)) { auto DVar = DSAStack->getTopDSA(VD, false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_copyprivate && DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_copyprivate); ReportOriginalDSA(*this, DSAStack, VD, DVar); continue; } // OpenMP [2.11.4.2, Restrictions, p.1] // All list items that appear in a copyprivate clause must be either // threadprivate or private in the enclosing context. if (DVar.CKind == OMPC_unknown) { DVar = DSAStack->getImplicitDSA(VD, false); if (DVar.CKind == OMPC_shared) { Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_copyprivate) << "threadprivate or private in the enclosing context"; ReportOriginalDSA(*this, DSAStack, VD, DVar); continue; } } } // Variably modified types are not supported. if (!Type->isAnyPointerType() && Type->isVariablyModifiedType()) { Diag(ELoc, diag::err_omp_variably_modified_type_not_supported) << getOpenMPClauseName(OMPC_copyprivate) << Type << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; continue; } // OpenMP [2.14.4.1, Restrictions, C/C++, p.2] // A variable of class type (or array thereof) that appears in a // copyin clause requires an accessible, unambiguous copy assignment // operator for the class type. Type = Context.getBaseElementType(Type.getNonReferenceType()) .getUnqualifiedType(); auto *SrcVD = buildVarDecl(*this, DE->getLocStart(), Type, ".copyprivate.src", VD->hasAttrs() ? &VD->getAttrs() : nullptr); auto *PseudoSrcExpr = buildDeclRefExpr(*this, SrcVD, Type, DE->getExprLoc()); auto *DstVD = buildVarDecl(*this, DE->getLocStart(), Type, ".copyprivate.dst", VD->hasAttrs() ? &VD->getAttrs() : nullptr); auto *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, Type, DE->getExprLoc()); auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign, PseudoDstExpr, PseudoSrcExpr); if (AssignmentOp.isInvalid()) continue; AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(), /*DiscardedValue=*/true); if (AssignmentOp.isInvalid()) continue; // No need to mark vars as copyprivate, they are already threadprivate or // implicitly private. Vars.push_back(DE); SrcExprs.push_back(PseudoSrcExpr); DstExprs.push_back(PseudoDstExpr); AssignmentOps.push_back(AssignmentOp.get()); } if (Vars.empty()) return nullptr; return OMPCopyprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars, SrcExprs, DstExprs, AssignmentOps); } OMPClause *Sema::ActOnOpenMPFlushClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { if (VarList.empty()) return nullptr; return OMPFlushClause::Create(Context, StartLoc, LParenLoc, EndLoc, VarList); } OMPClause * Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { if (DSAStack->getCurrentDirective() == OMPD_ordered && DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink) { Diag(DepLoc, diag::err_omp_unexpected_clause_value) << "'source' or 'sink'" << getOpenMPClauseName(OMPC_depend); return nullptr; } if (DSAStack->getCurrentDirective() != OMPD_ordered && (DepKind == OMPC_DEPEND_unknown || DepKind == OMPC_DEPEND_source || DepKind == OMPC_DEPEND_sink)) { unsigned Except[] = {OMPC_DEPEND_source, OMPC_DEPEND_sink}; Diag(DepLoc, diag::err_omp_unexpected_clause_value) << getListOfPossibleValues(OMPC_depend, /*First=*/0, /*Last=*/OMPC_DEPEND_unknown, Except) << getOpenMPClauseName(OMPC_depend); return nullptr; } SmallVector Vars; llvm::APSInt DepCounter(/*BitWidth=*/32); llvm::APSInt TotalDepCount(/*BitWidth=*/32); if (DepKind == OMPC_DEPEND_sink) { if (auto *OrderedCountExpr = DSAStack->getParentOrderedRegionParam()) { TotalDepCount = OrderedCountExpr->EvaluateKnownConstInt(Context); TotalDepCount.setIsUnsigned(/*Val=*/true); } } if ((DepKind != OMPC_DEPEND_sink && DepKind != OMPC_DEPEND_source) || DSAStack->getParentOrderedRegionParam()) { for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP shared clause."); if (isa(RefExpr) || (DepKind == OMPC_DEPEND_sink && CurContext->isDependentContext())) { // It will be analyzed later. Vars.push_back(RefExpr); continue; } SourceLocation ELoc = RefExpr->getExprLoc(); auto *SimpleExpr = RefExpr->IgnoreParenCasts(); if (DepKind == OMPC_DEPEND_sink) { if (DepCounter >= TotalDepCount) { Diag(ELoc, diag::err_omp_depend_sink_unexpected_expr); continue; } ++DepCounter; // OpenMP [2.13.9, Summary] // depend(dependence-type : vec), where dependence-type is: // 'sink' and where vec is the iteration vector, which has the form: // x1 [+- d1], x2 [+- d2 ], . . . , xn [+- dn] // where n is the value specified by the ordered clause in the loop // directive, xi denotes the loop iteration variable of the i-th nested // loop associated with the loop directive, and di is a constant // non-negative integer. SimpleExpr = SimpleExpr->IgnoreImplicit(); auto *DE = dyn_cast(SimpleExpr); if (!DE) { OverloadedOperatorKind OOK = OO_None; SourceLocation OOLoc; Expr *LHS, *RHS; if (auto *BO = dyn_cast(SimpleExpr)) { OOK = BinaryOperator::getOverloadedOperator(BO->getOpcode()); OOLoc = BO->getOperatorLoc(); LHS = BO->getLHS()->IgnoreParenImpCasts(); RHS = BO->getRHS()->IgnoreParenImpCasts(); } else if (auto *OCE = dyn_cast(SimpleExpr)) { OOK = OCE->getOperator(); OOLoc = OCE->getOperatorLoc(); LHS = OCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts(); RHS = OCE->getArg(/*Arg=*/1)->IgnoreParenImpCasts(); } else if (auto *MCE = dyn_cast(SimpleExpr)) { OOK = MCE->getMethodDecl() ->getNameInfo() .getName() .getCXXOverloadedOperator(); OOLoc = MCE->getCallee()->getExprLoc(); LHS = MCE->getImplicitObjectArgument()->IgnoreParenImpCasts(); RHS = MCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts(); } else { Diag(ELoc, diag::err_omp_depend_sink_wrong_expr); continue; } DE = dyn_cast(LHS); if (!DE) { Diag(LHS->getExprLoc(), diag::err_omp_depend_sink_expected_loop_iteration) << DSAStack->getParentLoopControlVariable( DepCounter.getZExtValue()); continue; } if (OOK != OO_Plus && OOK != OO_Minus) { Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus); continue; } ExprResult Res = VerifyPositiveIntegerConstantInClause( RHS, OMPC_depend, /*StrictlyPositive=*/false); if (Res.isInvalid()) continue; } auto *VD = dyn_cast(DE->getDecl()); if (!CurContext->isDependentContext() && DSAStack->getParentOrderedRegionParam() && (!VD || DepCounter != DSAStack->isParentLoopControlVariable(VD))) { Diag(DE->getExprLoc(), diag::err_omp_depend_sink_expected_loop_iteration) << DSAStack->getParentLoopControlVariable( DepCounter.getZExtValue()); continue; } } else { // OpenMP [2.11.1.1, Restrictions, p.3] // A variable that is part of another variable (such as a field of a // structure) but is not an array element or an array section cannot // appear in a depend clause. auto *DE = dyn_cast(SimpleExpr); auto *ASE = dyn_cast(SimpleExpr); auto *OASE = dyn_cast(SimpleExpr); if (!RefExpr->IgnoreParenImpCasts()->isLValue() || (!ASE && !DE && !OASE) || (DE && !isa(DE->getDecl())) || (ASE && !ASE->getBase()->getType()->isAnyPointerType() && !ASE->getBase()->getType()->isArrayType())) { Diag(ELoc, diag::err_omp_expected_var_name_or_array_item) << RefExpr->getSourceRange(); continue; } } Vars.push_back(RefExpr->IgnoreParenImpCasts()); } if (!CurContext->isDependentContext() && DepKind == OMPC_DEPEND_sink && TotalDepCount > VarList.size() && DSAStack->getParentOrderedRegionParam()) { Diag(EndLoc, diag::err_omp_depend_sink_expected_loop_iteration) << DSAStack->getParentLoopControlVariable(VarList.size() + 1); } if (DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink && Vars.empty()) return nullptr; } return OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc, DepKind, DepLoc, ColonLoc, Vars); } OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = Device; // OpenMP [2.9.1, Restrictions] // The device expression must evaluate to a non-negative integer value. if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_device, /*StrictlyPositive=*/false)) return nullptr; return new (Context) OMPDeviceClause(ValExpr, StartLoc, LParenLoc, EndLoc); } static bool IsCXXRecordForMappable(Sema &SemaRef, SourceLocation Loc, DSAStackTy *Stack, CXXRecordDecl *RD) { if (!RD || RD->isInvalidDecl()) return true; if (auto *CTSD = dyn_cast(RD)) if (auto *CTD = CTSD->getSpecializedTemplate()) RD = CTD->getTemplatedDecl(); auto QTy = SemaRef.Context.getRecordType(RD); if (RD->isDynamicClass()) { SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; SemaRef.Diag(RD->getLocation(), diag::note_omp_polymorphic_in_target); return false; } auto *DC = RD; bool IsCorrect = true; for (auto *I : DC->decls()) { if (I) { if (auto *MD = dyn_cast(I)) { if (MD->isStatic()) { SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; SemaRef.Diag(MD->getLocation(), diag::note_omp_static_member_in_target); IsCorrect = false; } } else if (auto *VD = dyn_cast(I)) { if (VD->isStaticDataMember()) { SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; SemaRef.Diag(VD->getLocation(), diag::note_omp_static_member_in_target); IsCorrect = false; } } } } for (auto &I : RD->bases()) { if (!IsCXXRecordForMappable(SemaRef, I.getLocStart(), Stack, I.getType()->getAsCXXRecordDecl())) IsCorrect = false; } return IsCorrect; } static bool CheckTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, DSAStackTy *Stack, QualType QTy) { NamedDecl *ND; if (QTy->isIncompleteType(&ND)) { SemaRef.Diag(SL, diag::err_incomplete_type) << QTy << SR; return false; } else if (CXXRecordDecl *RD = dyn_cast_or_null(ND)) { if (!RD->isInvalidDecl() && !IsCXXRecordForMappable(SemaRef, SL, Stack, RD)) return false; } return true; } OMPClause *Sema::ActOnOpenMPMapClause( OpenMPMapClauseKind MapTypeModifier, OpenMPMapClauseKind MapType, SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector Vars; for (auto &RE : VarList) { assert(RE && "Null expr in omp map"); if (isa(RE)) { // It will be analyzed later. Vars.push_back(RE); continue; } SourceLocation ELoc = RE->getExprLoc(); // OpenMP [2.14.5, Restrictions] // A variable that is part of another variable (such as field of a // structure) but is not an array element or an array section cannot appear // in a map clause. auto *VE = RE->IgnoreParenLValueCasts(); if (VE->isValueDependent() || VE->isTypeDependent() || VE->isInstantiationDependent() || VE->containsUnexpandedParameterPack()) { // It will be analyzed later. Vars.push_back(RE); continue; } auto *SimpleExpr = RE->IgnoreParenCasts(); auto *DE = dyn_cast(SimpleExpr); auto *ASE = dyn_cast(SimpleExpr); auto *OASE = dyn_cast(SimpleExpr); if (!RE->IgnoreParenImpCasts()->isLValue() || (!OASE && !ASE && !DE) || (DE && !isa(DE->getDecl())) || (ASE && !ASE->getBase()->getType()->isAnyPointerType() && !ASE->getBase()->getType()->isArrayType())) { Diag(ELoc, diag::err_omp_expected_var_name_or_array_item) << RE->getSourceRange(); continue; } Decl *D = nullptr; if (DE) { D = DE->getDecl(); } else if (ASE) { auto *B = ASE->getBase()->IgnoreParenCasts(); D = dyn_cast(B)->getDecl(); } else if (OASE) { auto *B = OASE->getBase(); D = dyn_cast(B)->getDecl(); } assert(D && "Null decl on map clause."); auto *VD = cast(D); // OpenMP [2.14.5, Restrictions, p.8] // threadprivate variables cannot appear in a map clause. if (DSAStack->isThreadPrivate(VD)) { auto DVar = DSAStack->getTopDSA(VD, false); Diag(ELoc, diag::err_omp_threadprivate_in_map); ReportOriginalDSA(*this, DSAStack, VD, DVar); continue; } // OpenMP [2.14.5, Restrictions, p.2] // At most one list item can be an array item derived from a given variable // in map clauses of the same construct. // OpenMP [2.14.5, Restrictions, p.3] // List items of map clauses in the same construct must not share original // storage. // OpenMP [2.14.5, Restrictions, C/C++, p.2] // A variable for which the type is pointer, reference to array, or // reference to pointer and an array section derived from that variable // must not appear as list items of map clauses of the same construct. DSAStackTy::MapInfo MI = DSAStack->IsMappedInCurrentRegion(VD); if (MI.RefExpr) { Diag(ELoc, diag::err_omp_map_shared_storage) << ELoc; Diag(MI.RefExpr->getExprLoc(), diag::note_used_here) << MI.RefExpr->getSourceRange(); continue; } // OpenMP [2.14.5, Restrictions, C/C++, p.3,4] // A variable for which the type is pointer, reference to array, or // reference to pointer must not appear as a list item if the enclosing // device data environment already contains an array section derived from // that variable. // An array section derived from a variable for which the type is pointer, // reference to array, or reference to pointer must not appear as a list // item if the enclosing device data environment already contains that // variable. QualType Type = VD->getType(); MI = DSAStack->getMapInfoForVar(VD); if (MI.RefExpr && (isa(MI.RefExpr->IgnoreParenLValueCasts()) != isa(VE)) && (Type->isPointerType() || Type->isReferenceType())) { Diag(ELoc, diag::err_omp_map_shared_storage) << ELoc; Diag(MI.RefExpr->getExprLoc(), diag::note_used_here) << MI.RefExpr->getSourceRange(); continue; } // OpenMP [2.14.5, Restrictions, C/C++, p.7] // A list item must have a mappable type. if (!CheckTypeMappable(VE->getExprLoc(), VE->getSourceRange(), *this, DSAStack, Type)) continue; Vars.push_back(RE); MI.RefExpr = RE; DSAStack->addMapInfoForVar(VD, MI); } if (Vars.empty()) return nullptr; return OMPMapClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars, MapTypeModifier, MapType, MapLoc); } OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = NumTeams; // OpenMP [teams Constrcut, Restrictions] // The num_teams expression must evaluate to a positive integer value. if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_num_teams, /*StrictlyPositive=*/true)) return nullptr; return new (Context) OMPNumTeamsClause(ValExpr, StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = ThreadLimit; // OpenMP [teams Constrcut, Restrictions] // The thread_limit expression must evaluate to a positive integer value. if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_thread_limit, /*StrictlyPositive=*/true)) return nullptr; return new (Context) OMPThreadLimitClause(ValExpr, StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPPriorityClause(Expr *Priority, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = Priority; // OpenMP [2.9.1, task Constrcut] // The priority-value is a non-negative numerical scalar expression. if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_priority, /*StrictlyPositive=*/false)) return nullptr; return new (Context) OMPPriorityClause(ValExpr, StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = Grainsize; // OpenMP [2.9.2, taskloop Constrcut] // The parameter of the grainsize clause must be a positive integer // expression. if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_grainsize, /*StrictlyPositive=*/true)) return nullptr; return new (Context) OMPGrainsizeClause(ValExpr, StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = NumTasks; // OpenMP [2.9.2, taskloop Constrcut] // The parameter of the num_tasks clause must be a positive integer // expression. if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_num_tasks, /*StrictlyPositive=*/true)) return nullptr; return new (Context) OMPNumTasksClause(ValExpr, StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { // OpenMP [2.13.2, critical construct, Description] // ... where hint-expression is an integer constant expression that evaluates // to a valid lock hint. ExprResult HintExpr = VerifyPositiveIntegerConstantInClause(Hint, OMPC_hint); if (HintExpr.isInvalid()) return nullptr; return new (Context) OMPHintClause(HintExpr.get(), StartLoc, LParenLoc, EndLoc); } Index: projects/clang380-import/contrib/llvm/tools/clang =================================================================== --- projects/clang380-import/contrib/llvm/tools/clang (revision 295858) +++ projects/clang380-import/contrib/llvm/tools/clang (revision 295859) Property changes on: projects/clang380-import/contrib/llvm/tools/clang ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /vendor/clang/dist:r295600-295853 Index: projects/clang380-import/contrib/llvm =================================================================== --- projects/clang380-import/contrib/llvm (revision 295858) +++ projects/clang380-import/contrib/llvm (revision 295859) Property changes on: projects/clang380-import/contrib/llvm ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /vendor/llvm/dist:r295600-295853 Index: projects/clang380-import/lib/clang/include/clang/Basic/Version.inc =================================================================== --- projects/clang380-import/lib/clang/include/clang/Basic/Version.inc (revision 295858) +++ projects/clang380-import/lib/clang/include/clang/Basic/Version.inc (revision 295859) @@ -1,10 +1,10 @@ /* $FreeBSD$ */ #define CLANG_VERSION 3.8.0 #define CLANG_VERSION_MAJOR 3 #define CLANG_VERSION_MINOR 8 #define CLANG_VERSION_PATCHLEVEL 0 #define CLANG_VENDOR "FreeBSD " -#define SVN_REVISION "260756" +#define SVN_REVISION "261369"