Background
1. Technical field
This disclosure relates to vector processing, and more particularly to the processing of particular vector instructions that perform certain arithmetic and logical operations.
2. Description of the related art
In a conventional vector processor that exploits data-level parallelism (DLP), vectorization of loops in program code may affect the widespread adoption of DLP processors. In a typical program, a large portion of execution time is spent in loops. Unfortunately, many of these loops have characteristics that render them unvectorizable in conventional DLP processors. Thus, the performance benefits gained from attempting to vectorize program code can be limited.
One obstacle to vectorizing loops in program code in conventional systems is dependencies between iterations of the loop. For example, loop-carried data dependencies and memory-address aliasing are two such dependencies. These dependencies can be identified by a compiler during the compiler's static analysis of program code, but they cannot be completely resolved until runtime data is available. Thus, because the compiler cannot conclusively determine that runtime dependencies will not be encountered, the compiler cannot vectorize the loop. Hence, because existing systems require that the compiler determine the extent of available parallelism during compilation, relatively little code can be vectorized.
Summary of the embodiments
Various embodiments of recurrent minima and maxima instructions are disclosed. Broadly speaking, a system and method are contemplated in which a processor may execute instructions that cause the processor to receive an operand vector and a control vector and to optionally receive a basis vector and a selection vector, and to perform a maxima or minima operation dependent upon these vectors.
In one embodiment, the method includes a processor receiving an input vector and a control vector. The processor may also generate a result vector. Each of the input vectors, the control vector, and the result vector may include a respective number of elements that occupy ordered element positions. For each given one of the ordered element positions, the processor may perform a maxima or minima operation dependent upon the control vector and the input vector.
In one specific implementation, the method may also include the processor receiving a selection vector that may include a number of ordered elements. The processor may also select a basis value from a basis vector at an element position corresponding to the first active element in the selection vector.
In another specific implementation, the method may also include the processor selecting the basis value from the last element of the basis vector when the first active element of the selection vector occurs in the first element position of the selection vector.
Brief description of the drawings
FIG. 1 is a block diagram of one embodiment of a computer system.
FIG. 2 is a block diagram illustrating additional details of an embodiment of the processor shown in FIG. 1.
FIG. 3 is a diagram illustrating an example parallelization of a program code loop.
FIG. 4A is a diagram illustrating a sequence of variable states during scalar execution of the loop shown in Example 1.
FIG. 4B is a diagram illustrating a progression of execution for Macroscalar vectorized program code of the loop of Example 1.
FIG. 5A and FIG. 5B are diagrams illustrating one embodiment of the vectorization of program source code.
FIG. 6A is a diagram illustrating one embodiment of non-speculative vectorized program code.
FIG. 6B is a diagram illustrating another embodiment of speculative vectorized program code.
FIG. 7 is a diagram illustrating one embodiment of vectorized program code.
FIG. 8 is a diagram illustrating another embodiment of vectorized program code.
FIG. 9 is a flow diagram depicting the operation of one embodiment of the processor of FIG. 2 during execution of program instructions that implement a wrapping summation operation.
FIG. 10 is a flow diagram depicting the operation of one embodiment of the processor of FIG. 2 during execution of program instructions that implement a wrapping difference operation.
FIG. 11 is a flow diagram depicting the operation of one embodiment of the processor of FIG. 2 during execution of program instructions that implement a wrapping product operation.
FIG. 12 is a flow diagram depicting the operation of one embodiment of the processor of FIG. 2 during execution of program instructions that implement a wrapping quotient operation.
FIG. 13 is a flow diagram depicting the operation of one embodiment of the processor of FIG. 2 during execution of program instructions that implement a wrapping maxima operation.
FIG. 14 is a flow diagram depicting the operation of one embodiment of the processor of FIG. 2 during execution of program instructions that implement a wrapping minima operation.
FIG. 15 is a flow diagram depicting the operation of one embodiment of the processor of FIG. 2 during execution of program instructions that implement a wrapping shift operation.
FIG. 16 is a flow diagram depicting the operation of one embodiment of the processor of FIG. 2 during execution of program instructions that implement a wrapping Boolean operation.
FIG. 17 is a flow diagram depicting the operation of one embodiment of the processor of FIG. 2 during execution of program instructions that implement a wrapping fixed-value accumulation operation.
FIG. 18 is a flow diagram depicting the operation of one embodiment of the processor of FIG. 2 during execution of program instructions that implement wrapping negation operations.
Specific embodiments are shown by way of example in the drawings and will herein be described in detail. It should be understood, however, that the drawings and detailed description are not intended to limit the claims to the particular embodiments disclosed, even where only a single embodiment is described with respect to a particular feature. On the contrary, the intention is to cover all modifications, equivalents and alternatives that would be apparent to a person skilled in the art having the benefit of this disclosure. Examples of features provided in the disclosure are intended to be illustrative rather than restrictive unless stated otherwise.
As used throughout this application, the word "may" is used in a permissive sense (i.e., meaning having the potential to), rather than the mandatory sense (i.e., meaning must). Similarly, the words "include," "including," and "includes" mean including, but not limited to.
Various units, circuits, or other components may be described as "configured to" perform a task or tasks. In such contexts, "configured to" is a broad recitation of structure generally meaning "having circuitry that" performs the task or tasks during operation. As such, the unit/circuit/component can be configured to perform the task even when the unit/circuit/component is not currently on. In general, the circuitry that forms the structure corresponding to "configured to" may include hardware circuits. Similarly, various units/circuits/components may be described as performing a task or tasks, for convenience in the description. Such descriptions should be interpreted as including the phrase "configured to." Reciting a unit/circuit/component that is configured to perform one or more tasks is expressly intended not to invoke 35 U.S.C. .sctn.112, paragraph six, interpretation for that unit/circuit/component.
The scope of the present disclosure includes any feature or combination of features disclosed herein (either explicitly or implicitly), or any generalization thereof, whether or not it mitigates any or all of the problems addressed herein. Accordingly, new claims may be formulated during prosecution of this application (or an application claiming priority thereto) to any such combination of features. In particular, with reference to the appended claims, features from dependent claims may be combined with those of the independent claims and features from respective independent claims may be combined in any appropriate manner and not merely in the specific combinations enumerated in the appended claims.
Detailed description
Computer System Overview
Turning now to FIG. 1, a block diagram of one embodiment of a computer system is shown. Computer system 100 includes a processor 102, a level two (L2) cache 106, a memory 108, and a mass-storage device 110. As shown, processor 102 includes a level one (L1) cache 104. It is noted that although specific components are shown and described in computer system 100, in alternative embodiments different components and numbers of components may be present in computer system 100. For example, computer system 100 may not include some of the memory hierarchy (e.g., memory 108 and/or mass-storage device 110). Alternatively, although the L2 cache 106 is shown external to the processor 102, it is contemplated that in other embodiments, the L2 cache 106 may be internal to the processor 102. It is further noted that in such embodiments, a level three (L3) cache (not shown) may be used. In addition, computer system 100 may include graphics processors, video cards, video-capture devices, user-interface devices, network cards, optical drives, and/or other peripheral devices that are coupled to processor 102 using a bus, a network, or another suitable communication channel (all not shown for simplicity).
In various embodiments, processor 102 may be representative of a general-purpose processor that performs computational operations. For example, processor 102 may be a central processing unit (CPU) such as a microprocessor, a microcontroller, an application-specific integrated circuit (ASIC), or a field-programmable gate array (FPGA). However, as described further below, processor 102 may include one or more mechanisms for vector processing (e.g., vector execution units). An example vector execution unit of processor 102 is described in greater detail below in conjunction with the description of FIG. 2.
The mass-storage device 110, memory 108, L2 cache 106, and L1 cache 104 are storage devices that collectively form a memory hierarchy that stores data and instructions for processor 102. More particularly, the mass-storage device 110 may be a high-capacity, non-volatile memory, such as a disk drive or a large flash memory unit with a long access time, while L1 cache 104, L2 cache 106, and memory 108 may be smaller, with shorter access times. These faster semiconductor memories store copies of frequently used data. Memory 108 may be representative of a memory device in the dynamic random access memory (DRAM) family of memory devices. The size of memory 108 is typically larger than L1 cache 104 and L2 cache 106, whereas L1 cache 104 and L2 cache 106 are typically implemented using smaller devices in the static random access memories (SRAM) family of devices. In some embodiments, L2 cache 106, memory 108, and mass-storage device 110 are shared between one or more processors in computer system 100.
In some embodiments, the devices in the memory hierarchy (i.e., L1 cache 104, etc.) can access (i.e., read and/or write) multiple cache lines per cycle. These embodiments may enable more effective processing of memory accesses that occur based on a vector of pointers or array indices to non-contiguous memory addresses.
It is noted the data structures and program instructions (i.e., code) described below may be stored on a non-transitory computer-readable storage device, which may be any device or storage medium that can store code and/or data for use by a computer system (e.g., computer system 100). Generally speaking, a non-transitory computer-readable storage device includes, but is not limited to, volatile memory, non-volatile memory, magnetic and optical storage devices such as disk drives, magnetic tape, compact discs (CDs), digital versatile discs or digital video discs (DVDs), or other media capable of storing computer-readable media now known or later developed. As such, mass-storage device 110, memory 108, L2 cache 106, and L1 cache 104 are all examples of non-transitory computer readable storage devices.
Processor
Referring to FIG. 2, a block diagram illustrating additional details of an embodiment of the processor of FIG. 1 is shown. In the embodiment shown in FIG. 2, processor 102 may include a number of pipeline stages, although for brevity not all are shown in FIG. 2. Accordingly, as shown, processor 102 includes L1 cache 104, an instruction fetch unit 201, an integer execution unit 202, a floating-point execution unit 206, and a vector execution unit 204. It is noted that integer execution unit 202, floating-point execution unit 206, and vector execution unit 204 as a group may be interchangeably referred to as "the execution units."
In various embodiments, the execution units may perform computational operations such as logical operations, mathematical operations, or bitwise operations, for example, for an associated type of operand. More specifically, integer execution unit 202 may perform computational operations that involve integer operands, floating-point execution unit 206 may perform computational operations that involve floating-point operands, and vector execution unit 204 may perform computational operations that involve vector operands. Any suitable configurations may be employed for integer execution unit 202 and floating-point execution unit 206, depending on the particular configuration of architectural and performance parameters governing a particular processor design. As noted above, although the embodiment of processor 102 shown in FIG. 2 includes a particular set of components, it is contemplated that in alternative embodiments processor 102 may include different numbers or types of execution units, functional units, and pipeline stages such as an instruction decode unit, a scheduler or reservations station, a reorder buffer, a memory management unit, I/O interfaces, etc. that may be coupled to the execution units.
The vector execution unit 204 may be representative of a single-instruction-multiple-data (SIMD) execution unit in the classical sense, in that it may perform the same operation on multiple data elements in parallel. However, it is noted that in some embodiments, the vector instructions described here may differ from other implementations of SIMD instructions. For example, in an embodiment, elements of a vector operated on by a vector instruction may have a size that does not vary with the number of elements in the vector. By contrast, in some SIMD implementations, data element size does vary with the number of data elements operated on (e.g., a SIMD architecture might support operations on eight 8-bit elements, but only four 16-bit elements, two 32-bit elements, etc.). In one embodiment, the vector execution unit 204 may operate on some or all of the data elements that are included in vectors of operands. More particularly, the vector execution unit 204 may be configured to concurrently operate on different elements of a vector operand of a vector program instruction.
In one embodiment, the vector execution unit 204 may include a vector register file (not shown) which may include vector registers that can hold operand vectors and result vectors for the vector execution unit 204. In some embodiments, there may be 32 vector registers in the vector register file, and each vector register may include 128 bits. However, in alternative embodiments, there may be different numbers of vector registers and/or different numbers of bits per register.
The vector execution unit 204 may be configured to retrieve operands from the vector registers and to execute vector instructions that cause vector execution unit 204 to perform operations in parallel on some or all of the data elements in the operand vector. For example, vector execution unit 204 can perform logical operations, mathematical operations, or bitwise operations on the elements in the vector. Vector execution unit 204 may perform one vector operation per instruction cycle (although as described above, a "cycle" may include more than one clock cycle that may be used to trigger, synchronize, and/or control vector execution unit 204's computational operations).
In one embodiment, vector execution unit 204 may support vectors that hold N data elements (e.g., bytes, words, doublewords, etc.), where N may be any positive whole number. In these embodiments, vector execution unit 204 may perform operations on N or fewer of the data elements in an operand vector in parallel. For example, in an embodiment where the vector is 256 bits in length, the data elements being operated on are four-byte elements, and the operation is adding a value to the data elements, these embodiments can add the value to any number of the elements in the vector. It is noted that N may be different for different implementations of processor 102.
The vector execution unit 204 may, in various embodiments, include at least one control signal that enables the dynamic limitation of the data elements in an operand vector on which vector execution unit 204 operates. Specifically, depending on the state of the control signal, vector execution unit 204 may selectively operate on any or all of the data elements in the vector. For example, in an embodiment where the vector is 512 bits in length and the data elements being operated on are four-byte elements, the control signal can be asserted to prevent operations from being performed on some or all of 16 data elements in the operand vector. Note that "dynamically" limiting the data elements in the operand vector upon which operations are performed can involve asserting the control signal separately for each cycle at runtime.
In some embodiments, as described in greater detail below, based on the values contained in a vector of predicates or one or more scalar predicates, vector execution unit 204 applies vector operations to selected vector data elements only. In some embodiments, the remaining data elements in a result vector remain unaffected (which may also be referred to as "predication") or are forced to zero (which may also be referred to as "zeroing" or "zeroing predication"). In some embodiments, the clocks for the data element processing subsystems ("lanes") that are unused due to predication or zeroing in vector execution unit 204 can be power and/or clock-gated, thereby reducing dynamic power consumption in vector execution unit 204.
In various embodiments, the architecture may be vector-length agnostic to allow it to adapt parallelism at runtime. More particularly, when instructions or operations are vector-length agnostic, the operation (i.e., instruction, etc.) may be executed using vectors of any length, up to the limitations imposed by the supporting hardware. For example, in embodiments in which vector execution hardware supports vectors that can include eight separate four-byte elements (thus having a vector length of eight elements), a vector-length agnostic operation can operate on any number of the eight elements in the vector. On a different hardware implementation that supports a different vector length (e.g., four elements), the vector-length agnostic operation may operate on the different number of elements made available to it by the underlying hardware. Thus, a compiler or programmer need not have explicit knowledge of the vector length supported by the underlying hardware (e.g., vector execution unit 204). In such embodiments, a compiler generates or a programmer writes program code that need not rely on (or use) a specific vector length. In some embodiments it may be forbidden to specify a specific vector size in program code. Thus, the compiled code in these embodiments (i.e., binary code) runs on other execution units that may have differing vector lengths, while potentially realizing performance gains from processors that support longer vectors. In such embodiments, the vector length may for a given hardware unit such as a processor may be read from a system register during runtime. Consequently, as process technology allows longer vectors, execution of legacy binary code simply speeds up without any effort by software developers.
Generally, vector lengths may be implemented as powers of two (e.g., two, four, eight, etc.). However, in some embodiments, vector lengths need not be powers of two. Specifically, vectors of three, seven, or another number of data elements can be used in the same way as vectors with power-of-two numbers of data elements.
In various embodiments, each data element in the vector can contain an address that is used by vector execution unit 204 for performing a set of memory accesses in parallel. In such embodiments, if one or more elements of the vector contain invalid memory addresses, invalid memory-read operations can occur. Accordingly, invalid memory-read operations that would otherwise result in program termination may instead cause any elements with valid addresses to be read and elements with invalid elements to be flagged, allowing program execution to continue in the face of speculative, and in hindsight illegal, read operations.
In some embodiments, processor 102 (and hence vector execution unit 204) is able to operate on and use vectors of pointers. In such embodiments, the number of data elements per vector is the same as the number of pointers per vector, regardless of the size of the data type. Instructions that operate on memory may have variants that indicate the size of the memory access, but elements in processor registers should be the same as the pointer size. In these embodiments, processors that support both 32-bit and 64-bit addressing modes may choose to allow twice as many elements per vector in 32-bit mode, thereby achieving greater throughput. This implies a distinct throughput advantage to 32-bit addressing, assuming the same width data path. Implementation-specific techniques can be used to relax the requirement. For example, double-precision floating-point numbers can be supported in 32-bit mode through register pairing or some other specialized mechanism.
Macroscalar Architecture Overview
An instruction set architecture (referred to as the Macroscalar Architecture) and supporting hardware may allow compilers to generate program code for loops without having to completely determine parallelism at compile-time, and without discarding useful static analysis information. Various embodiments of the Macroscalar Architecture will now be described. Specifically, as described further below, a set of instructions is provided that does not mandate parallelism for loops but, instead, enables parallelism to be exploited at runtime if dynamic conditions permit. Accordingly, the architecture includes instructions that enable code generated by the compiler to dynamically switch between non-parallel (scalar) and parallel (vector) execution for loop iterations depending on conditions at runtime by switching the amount of parallelism used.
Thus, the architecture provides instructions that enable an undetermined amount of vector parallelism for loop iterations but do not require that the parallelism be used at runtime. More specifically, the architecture includes a set of vector-length agnostic instructions whose effective vector length can vary depending on runtime conditions. Thus, if runtime dependencies demand non-parallel execution of the code, then execution occurs with an effective vector length of one element. Likewise, if runtime conditions permit parallel execution, the same code executes in a vector-parallel manner to whatever degree is allowed by runtime dependencies (and the vector length of the underlying hardware). For example, if two out of eight elements of the vector can safely execute in parallel, a processor such as processor 102 may execute the two elements in parallel. In these embodiments, expressing program code in a vector-length agnostic format enables a broad range of vectorization opportunities that are not present in existing systems.
In various embodiments, during compilation, a compiler first analyzes the loop structure of a given loop in program code and performs static dependency analysis. The compiler then generates program code that retains static analysis information and instructs a processor such as processor 102, for example, how to resolve runtime dependencies and to process the program code with the maximum amount of parallelism possible. More specifically, the compiler may provide vector instructions for performing corresponding sets of loop iterations in parallel, and may provide vector-control instructions for dynamically limiting the execution of the vector instructions to prevent data dependencies between the iterations of the loop from causing an error. This approach defers the determination of parallelism to runtime, where the information on runtime dependencies is available, thereby allowing the software and processor to adapt parallelism to dynamically changing conditions. An example of a program code loop parallelization is shown in FIG. 3.
Referring to the left side of FIG. 3, an execution pattern is shown with four iterations (e.g., iterations 1-4) of a loop that have not been parallelized, where each loop includes instructions A-G. Serial operations are shown with instructions vertically stacked. On the right side of FIG. 3 is a version of the loop that has been parallelized. In this example, each instruction within an iteration depends on at least one instruction before it, so that there is a static dependency chain between the instructions of a given iteration. Hence, the instructions within a given iteration cannot be parallelized (i.e., instructions A-G within a given iteration are always serially executed with respect to the other instructions in the iteration). However, in alternative embodiments the instructions within a given iteration may be parallelizable.
As shown by the arrows between the iterations of the loop in FIG. 3, there is a possibility of a runtime data dependency between instruction E in a given iteration and instruction D of the subsequent iteration. However, during compilation, the compiler can only determine that there exists the possibility of data dependency between these instructions, but the compiler cannot tell in which iterations dependencies will actually materialize because this information is only available at runtime. In this example, a data dependency that actually materializes at runtime is shown by the solid arrows from 1E to 2D, and 3E to 4D, while a data dependency that doesn't materialize at runtime is shown using the dashed arrow from 2E to 3D. Thus, as shown, a runtime data dependency actually occurs between the first/second and third/fourth iterations.
Because no data dependency exists between the second and third iterations, the second and third iterations can safely be processed in parallel. Furthermore, instructions A-C and F-G of a given iteration have dependencies only within an iteration and, therefore, instruction A of a given iteration is able to execute in parallel with instruction A of all other iterations, instruction B can also execute in parallel with instruction B of all other iterations, and so forth. However, because instruction D in the second iteration depends on instruction E in the first iteration, instructions D and E in the first iteration must be executed before instruction D for the second iteration can be executed.
Accordingly, in the parallelized loop on the right side, the iterations of such a loop are executed to accommodate both the static and runtime data dependencies, while achieving maximum parallelism. More particularly, instructions A-C and F-G of all four iterations are executed in parallel. But, because instruction D in the second iteration depends on instruction E in the first iteration, instructions D and E in the first iteration must be executed before instruction D for the second iteration can be executed. However, because there is no data dependency between the second and third iterations, instructions D and E for these iterations can be executed in parallel.
Examples of the Macroscalar Architecture
The following examples introduce Macroscalar operations and demonstrate their use in vectorizing loops such as the loop shown in FIG. 3 and described above in the parallelized loop example. For ease of understanding, these examples are presented using pseudocode in the C++ format.
It is noted that the following example embodiments are for discussion purposes. The instructions and operations shown and described below are merely intended to aid an understanding of the architecture. However, in alternative embodiments, instructions or operations may be implemented in a different way, for example, using a microcode sequence of more primitive operations or using a different sequence of sub-operations. Note that further decomposition of instructions is avoided so that information about the macro-operation and the corresponding usage model is not obscured.
Notation
In describing the below examples, the following format is used for variables, which are vector quantities unless otherwise noted:
p5=a<b;
Elements of vector p5 are set to 0 or 1 depending on the result of testing a<b. Note that vector p5 can be a "predicate vector," as described in more detail below. Some instructions that generate predicate vectors also set processor status flags to reflect the resulting predicates. For example, the processor status flags or condition-codes can include the FIRST, LAST, NONE, and/or ALL flags.
{tilde over ( )}p5; a=b+c;
Only elements in vector `a` designated by active (i.e., non-zero) elements in the predicate vector p5 receive the result of b+c. The remaining elements of a are unchanged. This operation is called "predication," and is denoted using the tilde ("{tilde over ( )}") sign before the predicate vector.
!p5; a=b+c;
Only elements in vector `a` designated by active (i.e., non-zero) elements in the predicate vector p5 receive the result of b+c. The remaining elements of a are set to zero. This operation is called "zeroing," and is denoted using the exclamation point ("!") sign before the predicate vector.
TABLE-US-00001 if (FIRST( )) goto ...; // Also LAST( ), ANY( ), ALL( ), CARRY( ), ABOVE( ), or NONE( ), (where ANY( ) == !NONE( ))
The preceding instructions test the processor status flags and branch accordingly.
x+=VECLEN;
VECLEN is a machine value that communicates the number of elements per vector. The value is determined at runtime by the processor executing the code, rather than being determined by the assembler.
//Comment
In a similar way to many common programming languages, the following examples use the double forward slash to indicate comments. These comments can provide information regarding the values contained in the indicated vector or explanation of operations being performed in a corresponding example.
In these examples, other C++-formatted operators retain their conventional meanings, but are applied across the vector on an element-by-element basis. Where function calls are employed, they imply a single instruction that places any value returned into a destination register. For simplicity in understanding, all vectors are vectors of integers, but alternative embodiments support other data formats.
Structural Loop-Carried Dependencies
In the code Example 1 below, a program code loop that is "non-vectorizable" using conventional vector architectures is shown. (Note that in addition to being non-vectorizable, this loop is also not multi-threadable on conventional multi-threading architectures due to the fine-grain nature of the data dependencies.) For clarity, this loop has been distilled to the fundamental loop-carried dependencies that make the loop unvectorizable.
In this example, the variables r and s have loop-carried dependencies that prevent vectorization using conventional architectures. Notice, however, that the loop is vectorizable as long as the condition (A [x]<FACTOR) is known to be always true or always false. These assumptions change when the condition is allowed to vary during execution (the common case). For simplicity in this example, we presume that no aliasing exists between A[ ] and B[ ].
Example 1
Program Code Loop
TABLE-US-00002 r = 0; s = 0; for (x=0; x<KSIZE; ++x) { if (A[x] < FACTOR) { r = A[x+s]; } else { s = A[x+r]; } B[x] = r + s; }
Using the Macroscalar architecture, the loop in Example 1 can be vectorized by partitioning the vector into segments for which the conditional (A[x]<FACTOR) does not change. Examples of processes for partitioning such vectors, as well as examples of instructions that enable the partitioning, are presented below. It is noted that for this example the described partitioning need only be applied to instructions within the conditional clause. The first read of A[x] and the final operation B[x]=r+s can always be executed in parallel across a full vector, except potentially on the final loop iteration.
Instructions and examples of vectorized code are shown and described to explain the operation of a vector processor such as processor 102 of FIG. 2, in conjunction with the Macroscalar architecture. The following description is generally organized so that a number of instructions are described and then one or more vectorized code samples that use the instructions are presented. In some cases, a particular type of vectorization issue is explored in a given example.
dest=VectorReadInt(Base, Offset)
VectorReadlnt is an instruction for performing a memory read operation. A vector of offsets, Offset, scaled by the data size (integer in this case) is added to a scalar base address, Base, to form a vector of memory addresses which are then read into a destination vector. If the instruction is predicated or zeroed, only addresses corresponding to active elements are read. In the described embodiments, reads to invalid addresses are allowed to fault, but such faults only result in program termination if the first active address is invalid.
VectorWritelnt(Base, Offset, Value)
VectorWritelnt is an instruction for performing a memory write operation. A vector of offsets, Offset, scaled by the data size (integer in this case) is added to a scalar base address, Base, to form a vector of memory addresses. A vector of values, Value, is written to these memory addresses. If this instruction is predicated or zeroed, data is written only to active addresses. In the described embodiments, writes to illegal addresses always generate faults.
dest=VectorIndex(Start, Increment)
VectorIndex is an instruction for generating vectors of values that monotonically adjust by the increment from a scalar starting value specified by Start. This instruction can be used for initializing loop index variables when the index adjustment is constant. When predication or zeroing is applied, the first active element receives the starting value, and the increment is only applied to subsequent active elements. For example: x=VectorIndex(0,1); // x={0 1 2 3 4 5 6 7}
dest=PropagatePostT(dest, src, pred)
The PropagatePostT instruction propagates the value of active elements in src, as determined by pred, to subsequent inactive elements of dest. Active elements, and any inactive elements that precede the first active element, remain unchanged in dest. The purpose of this instruction is to take a value that is conditionally calculated, and propagate the conditionally calculated value to subsequent loop iterations as occurs in the equivalent scalar code. For example:
TABLE-US-00003 Entry: dest = {8 9 A B C D E F} src = {1 2 3 4 5 6 7 8} pred = {0 0 1 1 0 0 1 0} Exit: dest = {8 9 A B 4 4 E 7}
dest=PropagatePriorF(src, pred)
The PropagatePriorF instruction propagates the value of the inactive elements of src, as determined by pred, into subsequent active elements in dest. Inactive elements are copied from src to dest. If the first element of the predicate is active, then the last element of src is propagated to that position. For example:
TABLE-US-00004 Entry: src = {1 2 3 4 5 6 7 8} pred = {1 0 1 1 0 0 1 0} Exit: dest = {8 2 2 2 5 6 6 8}
dest=ConditionalStop(pred, deps)
The ConditionalStop instruction evaluates a vector of predicates, pred, and identifies transitions between adjacent predicate elements that imply data dependencies as specified by deps. The scalar value deps can be thought of as an array of four bits, each of which designates a possible transition between true/false elements in pred, as processed from left to right. These bits convey the presence of the indicated dependency if set, and guarantee the absence of the dependency if not set. They are:
kTF--Implies a loop-carried dependency from an iteration for which the predicate is true, to the subsequent iteration for which the value of the predicate is false.
kFF--Implies a loop-carried dependency from an iteration for which the predicate is false, to the subsequent iteration for which the value of the predicate is false.
kFT--Implies a loop-carried dependency from an iteration for which the predicate is false, to the subsequent iteration for which the value of the predicate is true.
kTT--Implies a loop-carried dependency from an iteration for which the predicate is true, to the subsequent iteration for which the value of the predicate is true.
The element position corresponding to the iteration that generates the data that is depended upon is stored in the destination vector at the element position corresponding to the iteration that depends on the data. If no data dependency exists, a value of 0 is stored in the destination vector at that element. The resulting dependency index vector, or DIV, contains a vector of element-position indices that represent dependencies. For the reasons described below, the first element of the vector is element number 1 (rather than 0).
As an example, consider the dependencies in the loop of Example 1 above. In this loop, transitions between true and false iterations of the conditional clause represent a loop-carried dependency that requires a break in parallelism. This can be handled using the following instructions:
TABLE-US-00005 p1 = (t < FACTOR); // p1 = {00001100} p2 = ConditionalStop(p1, kTF|kFT); // p2 = {00004060}
Because the 4th iteration generates the required data, and the 5th iteration depends on it, a 4 is stored in position 5 of the output vector p2 (which is the DIV). The same applies for the 7th iteration, which depends on data from the 6th iteration. Other elements of the DIV are set to 0 to indicate the absence of dependencies. (Note that in this example the first element of the vector is element number 1.)
dest=GeneratePredicates(Pred, DIV)
GeneratePredicates takes the dependency index vector, DIV, and generates predicates corresponding to the next group of elements that may safely be processed in parallel, given the previous group that was processed, indicated by pred. If no elements of Pred are active, predicates are generated for the first group of elements that may safely be processed in parallel. If Pred indicates that the final elements of the vector have been processed, then the instruction generates a result vector of inactive predicates indicating that no elements should be processed and the ZF flag is set. The CF flag is set to indicate that the last element of the results is active. Using the values in the first example, GeneratePredicates operates as follows:
TABLE-US-00006 Entry Conditions: // i2 = {0 0 0 0 4 0 6 0} p2 = 0; // p2 = {0 0 0 0 0 0 0 0} Loop2: p2 = GeneratePredicates(p2,i2); // p2` = {1 1 1 1 0 0 0 0} CF = 0, ZF = 0 if(!PLAST( )) goto Loop2 // p2`` = {0 0 0 0 1 1 0 0} CF = 0, ZF = 0 // p2``` = {0 0 0 0 0 0 1 1} CF = 1, ZF = 0
The description continues in the full USPTO document.