| //------------------------------------------------------------------------------------------------------- |
| // Copyright (C) Microsoft. All rights reserved. |
| // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. |
| //------------------------------------------------------------------------------------------------------- |
| #pragma once |
| |
| class IntBoundedValueInfo : public ValueInfo |
| { |
| private: |
| const IntBounds *const bounds; |
| |
| // Definitely-int values are inherently not negative zero. This member variable, if true, indicates that this value was |
| // produced by an int-specialized instruction that prevented a negative zero result using a negative zero bailout |
| // (BailOutOnNegativeZero). Negative zero tracking in the dead-store phase tracks this information to see if some of these |
| // negative zero bailout checks can be removed. |
| bool wasNegativeZeroPreventedByBailout; |
| |
| protected: |
| IntBoundedValueInfo(const ValueType type, const IntBounds *const bounds, const bool wasNegativeZeroPreventedByBailout) |
| : |
| ValueInfo( |
| type.IsInt() |
| ? bounds->ConstantBounds().GetValueType() |
| : bounds->ConstantBounds().IsLikelyTaggable() ? type : type.ToLikelyUntaggedInt(), |
| ValueStructureKind::IntBounded), |
| bounds(bounds), |
| wasNegativeZeroPreventedByBailout(wasNegativeZeroPreventedByBailout) |
| { |
| Assert(type.IsLikelyInt()); |
| Assert(Type().IsLikelyInt()); |
| Assert(Type().IsInt() == type.IsInt()); |
| bounds->Verify(); |
| |
| // Bounds for definitely int values should have relative bounds, otherwise those values should use one of the other |
| // value infos |
| Assert(bounds->RequiresIntBoundedValueInfo(Type())); |
| |
| Assert(!wasNegativeZeroPreventedByBailout || type.IsInt()); |
| Assert(!wasNegativeZeroPreventedByBailout || bounds->ConstantLowerBound() <= 0); |
| Assert(!wasNegativeZeroPreventedByBailout || bounds->ConstantUpperBound() >= 0); |
| } |
| |
| public: |
| static IntBoundedValueInfo *New( |
| const ValueType type, |
| const IntBounds *const bounds, |
| const bool wasNegativeZeroPreventedByBailout, |
| JitArenaAllocator *const allocator) |
| { |
| Assert(allocator); |
| return JitAnew(allocator, IntBoundedValueInfo, type, bounds, wasNegativeZeroPreventedByBailout); |
| } |
| |
| IntBoundedValueInfo *Copy(JitArenaAllocator *const allocator) const |
| { |
| Assert(allocator); |
| return JitAnew(allocator, IntBoundedValueInfo, *this); |
| } |
| |
| public: |
| const IntBounds *Bounds() const |
| { |
| return bounds; |
| } |
| |
| bool WasNegativeZeroPreventedByBailout() const |
| { |
| return wasNegativeZeroPreventedByBailout; |
| } |
| }; |
| |
| class LoopCount |
| { |
| private: |
| bool hasBeenGenerated; |
| |
| // Information needed to generate the loop count instructions |
| // loopCountMinusOne = (left - right + offset) / minMagnitudeChange |
| StackSym *leftSym, *rightSym; |
| int offset, minMagnitudeChange; |
| |
| // Information needed to use the computed loop count |
| StackSym *loopCountMinusOneSym; |
| StackSym *loopCountSym; // Not generated by default and depends on loopCountMinusOneSym |
| int loopCountMinusOneConstantValue; |
| |
| public: |
| LoopCount(StackSym *const leftSym, StackSym *const rightSym, const int offset, const int minMagnitudeChange) |
| : leftSym(leftSym), rightSym(rightSym), offset(offset), minMagnitudeChange(minMagnitudeChange), hasBeenGenerated(false), loopCountSym(nullptr) |
| { |
| Assert(leftSym || rightSym); |
| Assert(!leftSym || leftSym->GetType() == TyInt32 || leftSym->GetType() == TyUint32); |
| Assert(!rightSym || rightSym->GetType() == TyInt32 || rightSym->GetType() == TyUint32); |
| Assert(minMagnitudeChange > 0); |
| } |
| |
| LoopCount(StackSym *const loopCountMinusOneSym) : loopCountMinusOneSym(loopCountMinusOneSym), hasBeenGenerated(true), loopCountSym(nullptr) |
| { |
| Assert(loopCountMinusOneSym); |
| } |
| |
| LoopCount(StackSym *const loopCountMinusOneSym, StackSym *const loopCountSym) : |
| loopCountMinusOneSym(loopCountMinusOneSym), |
| loopCountSym(loopCountSym), |
| hasBeenGenerated(true) |
| { |
| Assert(loopCountMinusOneSym); |
| } |
| |
| LoopCount(const int loopCountMinusOneConstantValue) |
| : loopCountMinusOneSym(nullptr), loopCountMinusOneConstantValue(loopCountMinusOneConstantValue), hasBeenGenerated(true), loopCountSym(nullptr) |
| { |
| Assert(loopCountMinusOneConstantValue >= 0); |
| } |
| |
| public: |
| bool HasBeenGenerated() const |
| { |
| return hasBeenGenerated; |
| } |
| |
| bool HasGeneratedLoopCountSym() const |
| { |
| // Consider loop count sym generated if there is no loopCountMinusOneSym and it has been generated |
| return hasBeenGenerated && (loopCountSym != nullptr || loopCountMinusOneSym == nullptr); |
| } |
| |
| StackSym *LeftSym() const |
| { |
| Assert(!HasBeenGenerated()); |
| return leftSym; |
| } |
| |
| StackSym *RightSym() const |
| { |
| Assert(!HasBeenGenerated()); |
| return rightSym; |
| } |
| |
| int Offset() const |
| { |
| Assert(!HasBeenGenerated()); |
| return offset; |
| } |
| |
| int MinMagnitudeChange() const |
| { |
| Assert(!HasBeenGenerated()); |
| return minMagnitudeChange; |
| } |
| |
| StackSym *LoopCountMinusOneSym() const |
| { |
| Assert(HasBeenGenerated()); |
| return loopCountMinusOneSym; |
| } |
| |
| StackSym *LoopCountSym() const |
| { |
| Assert(HasGeneratedLoopCountSym()); |
| return loopCountSym; |
| } |
| |
| void SetLoopCountSym(StackSym *const loopCountSym) |
| { |
| Assert(HasBeenGenerated()); |
| Assert(loopCountSym); |
| |
| this->loopCountSym = loopCountSym; |
| } |
| |
| void SetLoopCountMinusOneSym(StackSym *const loopCountMinusOneSym) |
| { |
| Assert(!HasBeenGenerated()); |
| Assert(loopCountMinusOneSym); |
| |
| hasBeenGenerated = true; |
| this->loopCountMinusOneSym = loopCountMinusOneSym; |
| } |
| |
| int LoopCountMinusOneConstantValue() const |
| { |
| Assert(!LoopCountMinusOneSym()); |
| return loopCountMinusOneConstantValue; |
| } |
| }; |
| |
| class GlobOpt::AddSubConstantInfo |
| { |
| private: |
| StackSym *srcSym; |
| Value *srcValue; |
| bool srcValueIsLikelyConstant; |
| int32 offset; |
| |
| public: |
| AddSubConstantInfo() : srcSym(nullptr) |
| { |
| } |
| |
| public: |
| bool HasInfo() const |
| { |
| return !!srcSym; |
| } |
| |
| StackSym *SrcSym() const |
| { |
| Assert(HasInfo()); |
| return srcSym; |
| } |
| |
| Value *SrcValue() const |
| { |
| Assert(HasInfo()); |
| return srcValue; |
| } |
| |
| bool SrcValueIsLikelyConstant() const |
| { |
| Assert(HasInfo()); |
| return srcValueIsLikelyConstant; |
| } |
| |
| int32 Offset() const |
| { |
| Assert(HasInfo()); |
| return offset; |
| } |
| |
| public: |
| void Set(StackSym *const srcSym, Value *const srcValue, const bool srcValueIsLikelyConstant, const int32 offset); |
| }; |
| |
| class GlobOpt::ArrayLowerBoundCheckHoistInfo |
| { |
| protected: |
| BasicBlock *compatibleBoundCheckBlock; |
| Loop *loop; |
| |
| // Info populated for a compatible bound check and for hoisting out of loop |
| StackSym *indexSym; |
| int offset; |
| ValueNumber indexValueNumber; |
| |
| // Info populated for hoisting out of loop |
| Value *indexValue; |
| IntConstantBounds indexConstantBounds; // also populated for constant index, when there's a compatible bound check |
| bool isLoopCountBasedBound; |
| |
| // Info populated for hoisting out of loop using a loop count based bound, when the bound needs to be generated |
| LoopCount *loopCount; |
| int maxMagnitudeChange; |
| |
| public: |
| ArrayLowerBoundCheckHoistInfo() : compatibleBoundCheckBlock(nullptr), loop(nullptr) |
| { |
| } |
| |
| public: |
| bool HasAnyInfo() const |
| { |
| return CompatibleBoundCheckBlock() || Loop(); |
| } |
| |
| BasicBlock *CompatibleBoundCheckBlock() const |
| { |
| Assert(!(compatibleBoundCheckBlock && loop)); |
| return compatibleBoundCheckBlock; |
| } |
| |
| Loop *Loop() const |
| { |
| Assert(!(compatibleBoundCheckBlock && loop)); |
| return loop; |
| } |
| |
| StackSym *IndexSym() const |
| { |
| Assert(HasAnyInfo()); |
| return indexSym; |
| } |
| |
| int Offset() const |
| { |
| Assert(HasAnyInfo()); |
| return offset; |
| } |
| |
| void UpdateOffset(int newOffset) |
| { |
| Assert(HasAnyInfo()); |
| offset = newOffset; |
| } |
| |
| ValueNumber IndexValueNumber() const |
| { |
| Assert(HasAnyInfo()); |
| Assert(IndexSym()); |
| return indexValueNumber; |
| } |
| |
| Value *IndexValue() const |
| { |
| Assert(Loop()); |
| return indexValue; |
| } |
| |
| const IntConstantBounds &IndexConstantBounds() const |
| { |
| Assert(Loop() || CompatibleBoundCheckBlock() && !IndexSym()); |
| return indexConstantBounds; |
| } |
| |
| bool IsLoopCountBasedBound() const |
| { |
| Assert(Loop()); |
| return isLoopCountBasedBound; |
| } |
| |
| LoopCount *LoopCount() const |
| { |
| Assert(Loop()); |
| return loopCount; |
| } |
| |
| int MaxMagnitudeChange() const |
| { |
| Assert(LoopCount()); |
| return maxMagnitudeChange; |
| } |
| |
| |
| public: |
| void SetCompatibleBoundCheck(BasicBlock *const compatibleBoundCheckBlock, StackSym *const indexSym, const int offset, const ValueNumber indexValueNumber); |
| void SetLoop(::Loop *const loop, const int indexConstantValue, const bool isLoopCountBasedBound = false); |
| void SetLoop(::Loop *const loop, StackSym *const indexSym, const int offset, Value *const indexValue, const IntConstantBounds &indexConstantBounds, const bool isLoopCountBasedBound = false); |
| void SetLoopCount(::LoopCount *const loopCount, const int maxMagnitudeChange); |
| }; |
| |
| class GlobOpt::ArrayUpperBoundCheckHoistInfo : protected ArrayLowerBoundCheckHoistInfo |
| { |
| private: |
| typedef ArrayLowerBoundCheckHoistInfo Base; |
| |
| private: |
| // Info populated for hoisting out of loop |
| Value *headSegmentLengthValue; |
| IntConstantBounds headSegmentLengthConstantBounds; |
| |
| public: |
| using Base::HasAnyInfo; |
| using Base::CompatibleBoundCheckBlock; |
| using Base::Loop; |
| using Base::IndexSym; |
| using Base::Offset; |
| using Base::UpdateOffset; |
| using Base::IndexValueNumber; |
| using Base::IndexValue; |
| using Base::IndexConstantBounds; |
| using Base::IsLoopCountBasedBound; |
| using Base::LoopCount; |
| using Base::MaxMagnitudeChange; |
| |
| public: |
| Value *HeadSegmentLengthValue() const |
| { |
| Assert(Loop()); |
| return headSegmentLengthValue; |
| } |
| |
| const IntConstantBounds &HeadSegmentLengthConstantBounds() const |
| { |
| Assert(Loop()); |
| return headSegmentLengthConstantBounds; |
| } |
| |
| public: |
| using Base::SetCompatibleBoundCheck; |
| using Base::SetLoopCount; |
| |
| protected: |
| using Base::SetLoop; |
| |
| public: |
| void SetCompatibleBoundCheck(BasicBlock *const compatibleBoundCheckBlock, const int indexConstantValue); |
| void SetLoop(::Loop *const loop, const int indexConstantValue, Value *const headSegmentLengthValue, const IntConstantBounds &headSegmentLengthConstantBounds, const bool isLoopCountBasedBound = false); |
| void SetLoop(::Loop *const loop, StackSym *const indexSym, const int offset, Value *const indexValue, const IntConstantBounds &indexConstantBounds, Value *const headSegmentLengthValue, const IntConstantBounds &headSegmentLengthConstantBounds, const bool isLoopCountBasedBound = false); |
| }; |