vect: Widen loop-invariant operands using their narrowest valid range
Vectorizer now uses narrow ranges of loop-invariant operands to enable more widening operations.
The GCC vectorizer can sometimes widen operands to match the result type, improving instruction efficiency. Previously, this widening was blocked if a loop-invariant operand had a range that didn’t fit within the result’s type, even if the operand’s actual range was much narrower. This change modifies the vectorizer to query the precise range of loop-invariant operands and use the narrowest type that can hold that range. This allows widening to occur more often, as seen in an x265 optimization that reduced instruction count.
In Details
The vect_widened_op_tree function in GCC's vectorizer determines if an operand can be widened to match the result type. Previously, it accepted an operand as wide as the result only if it was a direct promotion. This commit introduces vect_narrow_unprom_to_range to determine the narrowest type that holds the actual range of a loop-invariant operand. For external definitions (operands defined outside the loop), this narrowest type is used, and the demoting cast is placed outside the loop. This enables widening in cases like the x265 example where an int invariant in [0, 31] is used w…
- vectorizer
- A compiler component that transforms code to perform the same operation on multiple data elements simultaneously, typically using SIMD (Single Instruction, Multiple Data) instructions.
- loop-invariant operand
- A value used within a loop that does not change its value from one iteration to the next.
- widening
- In the context of data types, converting a value from a narrower type to a wider type (e.g.,
shorttoint). In vectorization, this can refer to operations that expand the scope or precision of vector elements. - SIMD
- Single Instruction, Multiple Data. A class of parallel computers in Flynn's taxonomy that achieves performance by processing multiple data streams with a single instruction.
- promotion
- The implicit conversion of a value from a smaller data type to a larger data type, typically to prevent loss of data during an operation.