<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body text="#000000" bgcolor="#FFFFFF">
<br>
<div class="moz-cite-prefix">On 07/30/2018 05:34 AM, Chandler
Carruth wrote:<br>
</div>
<blockquote type="cite"
cite="mid:CAAwGriHftEBQS-9GAR7VN6YmQjB5eYTZoRcb18DbDE17prwq+A@mail.gmail.com">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<div dir="ltr">I strongly suspect that there remains widespread
concern with the direction of this, I know I have them.
<div><br>
</div>
<div>I don't think that many of the people who have that concern
have had time to come back to this RFC and make progress on
it, likely because of other commitments or simply the amount
of churn around SVE related patches and such. That is at least
why I haven't had time to return to this RFC and try to write
more detailed feedback.</div>
<div><br>
</div>
<div>Certainly, I would want to see pretty clear and considered
support for this change to the IR type system from Hal, Chris,
Eric and/or other long time maintainers of core LLVM IR
components before it moves forward, and I don't see that in
this thread.</div>
</div>
</blockquote>
<br>
At a high level, I'm happy with this approach. I think it will be
important for LLVM to support runtime-determined vector lengths - I
see the customizability and power-efficiency constraints that
motivate these designs continuing to increase in importance. I'm
still undecided on whether this makes vector code nicer even for
fixed-vector-length architectures, but some of the design decisions
that it forces, such as having explicit intrinsics for reductions
and other horizontal operations, seem like the right direction
regardless. I have two questions:<br>
<br>
1.<br>
<blockquote type="cite">This is a proposal for how to deal with
querying the size of scalable types for<br>
> analysis of IR. While it has not been implemented in full, </blockquote>
<br>
Is this still true? The details here need to all work out,
obviously, and we should make sure that any issues are identified.<br>
<br>
2. I know that there has been some discussion around support for
changing the vector length during program execution (e.g., to
account for some (proposed?) RISC-V feature), perhaps even during
the execution of a single function. I'm very concerned about this
idea because it is not at all clear to me how to limit information
transfer contaminated with the vector size from propagating between
different regions. As a result, I'm concerned about trying to add
this on later, and so if this is part of the plan, I think that we
need to think through the details up front because it could have a
major impact on the design.<br>
<br>
Thanks again,<br>
Hal<br>
<br>
<blockquote type="cite"
cite="mid:CAAwGriHftEBQS-9GAR7VN6YmQjB5eYTZoRcb18DbDE17prwq+A@mail.gmail.com">
<div dir="ltr">
<div><br>
</div>
<div>Put differently: I don't think silence is assent here. You
really need some clear signal of consensus.</div>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr">On Mon, Jul 30, 2018 at 2:23 AM Graham Hunter
<<a href="mailto:Graham.Hunter@arm.com"
moz-do-not-send="true">Graham.Hunter@arm.com</a>> wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0 0 0
.8ex;border-left:1px #ccc solid;padding-left:1ex">Hi,<br>
<br>
Are there any objections to going ahead with this? If not,
we'll try to get the patches reviewed and committed after the
7.0 branch occurs.<br>
<br>
-Graham<br>
<br>
> On 2 Jul 2018, at 10:53, Graham Hunter <<a
href="mailto:Graham.Hunter@arm.com" target="_blank"
moz-do-not-send="true">Graham.Hunter@arm.com</a>> wrote:<br>
> <br>
> Hi,<br>
> <br>
> I've updated the RFC slightly based on the discussion
within the thread, reposted below. Let me know if I've missed
anything or if more clarification is needed.<br>
> <br>
> Thanks,<br>
> <br>
> -Graham<br>
> <br>
>
=============================================================<br>
> Supporting SIMD instruction sets with variable vector
lengths<br>
>
=============================================================<br>
> <br>
> In this RFC we propose extending LLVM IR to support
code-generation for variable<br>
> length vector architectures like Arm's SVE or RISC-V's
'V' extension. Our<br>
> approach is backwards compatible and should be as
non-intrusive as possible; the<br>
> only change needed in other backends is how size is
queried on vector types, and<br>
> it only requires a change in which function is called. We
have created a set of<br>
> proof-of-concept patches to represent a simple vectorized
loop in IR and<br>
> generate SVE instructions from that IR. These patches
(listed in section 7 of<br>
> this rfc) can be found on Phabricator and are intended to
illustrate the scope<br>
> of changes required by the general approach described in
this RFC.<br>
> <br>
> ==========<br>
> Background<br>
> ==========<br>
> <br>
> *ARMv8-A Scalable Vector Extensions* (SVE) is a new
vector ISA extension for<br>
> AArch64 which is intended to scale with hardware such
that the same binary<br>
> running on a processor with longer vector registers can
take advantage of the<br>
> increased compute power without recompilation.<br>
> <br>
> As the vector length is no longer a compile-time known
value, the way in which<br>
> the LLVM vectorizer generates code requires modifications
such that certain<br>
> values are now runtime evaluated expressions instead of
compile-time constants.<br>
> <br>
> Documentation for SVE can be found at<br>
> <a
href="https://developer.arm.com/docs/ddi0584/latest/arm-architecture-reference-manual-supplement-the-scalable-vector-extension-sve-for-armv8-a"
rel="noreferrer" target="_blank" moz-do-not-send="true">https://developer.arm.com/docs/ddi0584/latest/arm-architecture-reference-manual-supplement-the-scalable-vector-extension-sve-for-armv8-a</a><br>
> <br>
> ========<br>
> Contents<br>
> ========<br>
> <br>
> The rest of this RFC covers the following topics:<br>
> <br>
> 1. Types -- a proposal to extend VectorType to be able to
represent vectors that<br>
> have a length which is a runtime-determined multiple of
a known base length.<br>
> <br>
> 2. Size Queries - how to reason about the size of types
for which the size isn't<br>
> fully known at compile time.<br>
> <br>
> 3. Representing the runtime multiple of vector length in
IR for use in address<br>
> calculations and induction variable comparisons.<br>
> <br>
> 4. Generating 'constant' values in IR for vectors with a
runtime-determined<br>
> number of elements.<br>
> <br>
> 5. An explanation of splitting/concatentating scalable
vectors.<br>
> <br>
> 6. A brief note on code generation of these new
operations for AArch64.<br>
> <br>
> 7. An example of C code and matching IR using the
proposed extensions.<br>
> <br>
> 8. A list of patches demonstrating the changes required
to emit SVE instructions<br>
> for a loop that has already been vectorized using the
extensions described<br>
> in this RFC.<br>
> <br>
> ========<br>
> 1. Types<br>
> ========<br>
> <br>
> To represent a vector of unknown length a boolean
`Scalable` property has been<br>
> added to the `VectorType` class, which indicates that the
number of elements in<br>
> the vector is a runtime-determined integer multiple of
the `NumElements` field.<br>
> Most code that deals with vectors doesn't need to know
the exact length, but<br>
> does need to know relative lengths -- e.g. get a vector
with the same number of<br>
> elements but a different element type, or with half or
double the number of<br>
> elements.<br>
> <br>
> In order to allow code to transparently support scalable
vectors, we introduce<br>
> an `ElementCount` class with two members:<br>
> <br>
> - `unsigned Min`: the minimum number of elements.<br>
> - `bool Scalable`: is the element count an unknown
multiple of `Min`?<br>
> <br>
> For non-scalable vectors (``Scalable=false``) the scale
is considered to be<br>
> equal to one and thus `Min` represents the exact number
of elements in the<br>
> vector.<br>
> <br>
> The intent for code working with vectors is to use
convenience methods and avoid<br>
> directly dealing with the number of elements. If needed,
calling<br>
> `getElementCount` on a vector type instead of
`getVectorNumElements` can be used<br>
> to obtain the (potentially scalable) number of elements.
Overloaded division and<br>
> multiplication operators allow an ElementCount instance
to be used in much the<br>
> same manner as an integer for most cases.<br>
> <br>
> This mixture of compile-time and runtime quantities allow
us to reason about the<br>
> relationship between different scalable vector types
without knowing their<br>
> exact length.<br>
> <br>
> The runtime multiple is not expected to change during
program execution for SVE,<br>
> but it is possible. The model of scalable vectors
presented in this RFC assumes<br>
> that the multiple will be constant within a function but
not necessarily across<br>
> functions. As suggested in the recent RISC-V rfc, a new
function attribute to<br>
> inherit the multiple across function calls will allow for
function calls with<br>
> vector arguments/return values and inlining/outlining
optimizations.<br>
> <br>
> IR Textual Form<br>
> ---------------<br>
> <br>
> The textual form for a scalable vector is:<br>
> <br>
> ``<scalable <n> x <type>>``<br>
> <br>
> where `type` is the scalar type of each element, `n` is
the minimum number of<br>
> elements, and the string literal `scalable` indicates
that the total number of<br>
> elements is an unknown multiple of `n`; `scalable` is
just an arbitrary choice<br>
> for indicating that the vector is scalable, and could be
substituted by another.<br>
> For fixed-length vectors, the `scalable` is omitted, so
there is no change in<br>
> the format for existing vectors.<br>
> <br>
> Scalable vectors with the same `Min` value have the same
number of elements, and<br>
> the same number of bytes if `Min * sizeof(type)` is the
same (assuming they are<br>
> used within the same function):<br>
> <br>
> ``<scalable 4 x i32>`` and ``<scalable 4 x
i8>`` have the same number of<br>
> elements.<br>
> <br>
> ``<scalable 4 x i32>`` and ``<scalable 8 x
i16>`` have the same number of<br>
> bytes.<br>
> <br>
> IR Bitcode Form<br>
> ---------------<br>
> <br>
> To serialize scalable vectors to bitcode, a new boolean
field is added to the<br>
> type record. If the field is not present the type will
default to a fixed-length<br>
> vector type, preserving backwards compatibility.<br>
> <br>
> Alternatives Considered<br>
> -----------------------<br>
> <br>
> We did consider one main alternative -- a dedicated
target type, like the<br>
> x86_mmx type.<br>
> <br>
> A dedicated target type would either need to extend all
existing passes that<br>
> work with vectors to recognize the new type, or to
duplicate all that code<br>
> in order to get reasonable code generation and
autovectorization.<br>
> <br>
> This hasn't been done for the x86_mmx type, and so it is
only capable of<br>
> providing support for C-level intrinsics instead of being
used and recognized by<br>
> passes inside llvm.<br>
> <br>
> Although our current solution will need to change some of
the code that creates<br>
> new VectorTypes, much of that code doesn't need to care
about whether the types<br>
> are scalable or not -- they can use preexisting methods
like<br>
> `getHalfElementsVectorType`. If the code is a little more
complex,<br>
> `ElementCount` structs can be used instead of an
`unsigned` value to represent<br>
> the number of elements.<br>
> <br>
> ===============<br>
> 2. Size Queries<br>
> ===============<br>
> <br>
> This is a proposal for how to deal with querying the size
of scalable types for<br>
> analysis of IR. While it has not been implemented in
full, the general approach<br>
> works well for calculating offsets into structures with
scalable types in a<br>
> modified version of ComputeValueVTs in our downstream
compiler.<br>
> <br>
> For current IR types that have a known size, all query
functions return a single<br>
> integer constant. For scalable types a second integer is
needed to indicate the<br>
> number of bytes/bits which need to be scaled by the
runtime multiple to obtain<br>
> the actual length.<br>
> <br>
> For primitive types, `getPrimitiveSizeInBits()` will
function as it does today,<br>
> except that it will no longer return a size for vector
types (it will return 0,<br>
> as it does for other derived types). The majority of
calls to this function are<br>
> already for scalar rather than vector types.<br>
> <br>
> For derived types, a function
`getScalableSizePairInBits()` will be added, which<br>
> returns a pair of integers (one to indicate unscaled
bits, the other for bits<br>
> that need to be scaled by the runtime multiple). For
backends that do not need<br>
> to deal with scalable types the existing methods will
suffice, but a debug-only<br>
> assert will be added to them to ensure they aren't used
on scalable types.<br>
> <br>
> Similar functionality will be added to DataLayout.<br>
> <br>
> Comparisons between sizes will use the following methods,
assuming that X and<br>
> Y are non-zero integers and the form is of { unscaled,
scaled }.<br>
> <br>
> { X, 0 } <cmp> { Y, 0 }: Normal unscaled
comparison.<br>
> <br>
> { 0, X } <cmp> { 0, Y }: Normal comparison within a
function, or across<br>
> functions that inherit vector
length. Cannot be<br>
> compared across non-inheriting
functions.<br>
> <br>
> { X, 0 } > { 0, Y }: Cannot return true.<br>
> <br>
> { X, 0 } = { 0, Y }: Cannot return true.<br>
> <br>
> { X, 0 } < { 0, Y }: Can return true.<br>
> <br>
> { Xu, Xs } <cmp> { Yu, Ys }: Gets complicated, need
to subtract common<br>
> terms and try the above
comparisons; it<br>
> may not be possible to get a
good answer.<br>
> <br>
> It's worth noting that we don't expect the last case
(mixed scaled and<br>
> unscaled sizes) to occur. Richard Sandiford's proposed C
extensions<br>
> (<a
href="http://lists.llvm.org/pipermail/cfe-dev/2018-May/057830.html"
rel="noreferrer" target="_blank" moz-do-not-send="true">http://lists.llvm.org/pipermail/cfe-dev/2018-May/057830.html</a>)
explicitly<br>
> prohibits mixing fixed-size types into sizeless struct.<br>
> <br>
> I don't know if we need a 'maybe' or 'unknown' result for
cases comparing scaled<br>
> vs. unscaled; I believe the gcc implementation of SVE
allows for such<br>
> results, but that supports a generic polynomial length
representation.<br>
> <br>
> My current intention is to rely on functions that clone
or copy values to<br>
> check whether they are being used to copy scalable
vectors across function<br>
> boundaries without the inherit vlen attribute and raise
an error there instead<br>
> of requiring passing the Function a type size is from for
each comparison. If<br>
> there's a strong preference for moving the check to the
size comparison function<br>
> let me know; I will be starting work on patches for this
later in the year if<br>
> there's no major problems with the idea.<br>
> <br>
> Future Work<br>
> -----------<br>
> <br>
> Since we cannot determine the exact size of a scalable
vector, the<br>
> existing logic for alias detection won't work when
multiple accesses<br>
> share a common base pointer with different offsets.<br>
> <br>
> However, SVE's predication will mean that a dynamic
'safe' vector length<br>
> can be determined at runtime, so after initial support
has been added we<br>
> can work on vectorizing loops using runtime predication
to avoid aliasing<br>
> problems.<br>
> <br>
> Alternatives Considered<br>
> -----------------------<br>
> <br>
> Marking scalable vectors as unsized doesn't work well, as
many parts of<br>
> llvm dealing with loads and stores assert that
'isSized()' returns true<br>
> and make use of the size when calculating offsets.<br>
> <br>
> We have considered introducing multiple helper functions
instead of<br>
> using direct size queries, but that doesn't cover all
cases. It may<br>
> still be a good idea to introduce them to make the
purpose in a given<br>
> case more obvious, e.g.
'requiresSignExtension(Type*,Type*)'.<br>
> <br>
> ========================================<br>
> 3. Representing Vector Length at Runtime<br>
> ========================================<br>
> <br>
> With a scalable vector type defined, we now need a way to
represent the runtime<br>
> length in IR in order to generate addresses for
consecutive vectors in memory<br>
> and determine how many elements have been processed in an
iteration of a loop.<br>
> <br>
> We have added an experimental `vscale` intrinsic to
represent the runtime<br>
> multiple. Multiplying the result of this intrinsic by the
minimum number of<br>
> elements in a vector gives the total number of elements
in a scalable vector.<br>
> <br>
> Fixed-Length Code<br>
> -----------------<br>
> <br>
> Assuming a vector type of <4 x <ty>><br>
> ``<br>
> vector.body:<br>
> %index = phi i64 [ %index.next, %vector.body ], [ 0,
%vector.body.preheader ]<br>
> ;; <loop body><br>
> ;; Increment induction var<br>
> %index.next = add i64 %index, 4<br>
> ;; <check and branch><br>
> ``<br>
> Scalable Equivalent<br>
> -------------------<br>
> <br>
> Assuming a vector type of <scalable 4 x <ty>><br>
> ``<br>
> vector.body:<br>
> %index = phi i64 [ %index.next, %vector.body ], [ 0,
%vector.body.preheader ]<br>
> ;; <loop body><br>
> ;; Increment induction var<br>
> %vscale64 = call i64
@llvm.experimental.vector.vscale.64()<br>
> %index.next = add i64 %index, mul (i64 %vscale64, i64 4)<br>
> ;; <check and branch><br>
> ``<br>
> ===========================<br>
> 4. Generating Vector Values<br>
> ===========================<br>
> For constant vector values, we cannot specify all the
elements as we can for<br>
> fixed-length vectors; fortunately only a small number of
easily synthesized<br>
> patterns are required for autovectorization. The
`zeroinitializer` constant<br>
> can be used in the same manner as fixed-length vectors
for a constant zero<br>
> splat. This can then be combined with `insertelement` and
`shufflevector`<br>
> to create arbitrary value splats in the same manner as
fixed-length vectors.<br>
> <br>
> For constants consisting of a sequence of values, an
experimental `stepvector`<br>
> intrinsic has been added to represent a simple constant
of the form<br>
> `<0, 1, 2... num_elems-1>`. To change the starting
value a splat of the new<br>
> start can be added, and changing the step requires
multiplying by a splat.<br>
> <br>
> Fixed-Length Code<br>
> -----------------<br>
> ``<br>
> ;; Splat a value<br>
> %insert = insertelement <4 x i32> undef, i32
%value, i32 0<br>
> %splat = shufflevector <4 x i32> %insert, <4 x
i32> undef, <4 x i32> zeroinitializer<br>
> ;; Add a constant sequence<br>
> %add = add <4 x i32> %splat, <i32 2, i32 4, i32
6, i32 8><br>
> ``<br>
> Scalable Equivalent<br>
> -------------------<br>
> ``<br>
> ;; Splat a value<br>
> %insert = insertelement <scalable 4 x i32> undef,
i32 %value, i32 0<br>
> %splat = shufflevector <scalable 4 x i32> %insert,
<scalable 4 x i32> undef, <scalable 4 x i32>
zeroinitializer<br>
> ;; Splat offset + stride (the same in this case)<br>
> %insert2 = insertelement <scalable 4 x i32> under,
i32 2, i32 0<br>
> %str_off = shufflevector <scalable 4 x i32>
%insert2, <scalable 4 x i32> undef, <scalable 4 x
i32> zeroinitializer<br>
> ;; Create sequence for scalable vector<br>
> %stepvector = call <scalable 4 x i32>
@llvm.experimental.vector.stepvector.nxv4i32()<br>
> %mulbystride = mul <scalable 4 x i32> %stepvector,
%str_off<br>
> %addoffset = add <scalable 4 x i32> %mulbystride,
%str_off<br>
> ;; Add the runtime-generated sequence<br>
> %add = add <scalable 4 x i32> %splat, %addoffset<br>
> ``<br>
> Future Work<br>
> -----------<br>
> <br>
> Intrinsics cannot currently be used for constant folding.
Our downstream<br>
> compiler (using Constants instead of intrinsics) relies
quite heavily on this<br>
> for good code generation, so we will need to find new
ways to recognize and<br>
> fold these values.<br>
> <br>
> ===========================================<br>
> 5. Splitting and Combining Scalable Vectors<br>
> ===========================================<br>
> <br>
> Splitting and combining scalable vectors in IR is done in
the same manner as<br>
> for fixed-length vectors, but with a non-constant mask
for the shufflevector.<br>
> <br>
> The following is an example of splitting a <scalable 4
x double> into two<br>
> separate <scalable 2 x double> values.<br>
> <br>
> ``<br>
> %vscale64 = call i64
@llvm.experimental.vector.vscale.64()<br>
> ;; Stepvector generates the element ids for first
subvector<br>
> %sv1 = call <scalable 2 x i64>
@llvm.experimental.vector.stepvector.nxv2i64()<br>
> ;; Add vscale * 2 to get the starting element for the
second subvector<br>
> %ec = mul i64 %vscale64, 2<br>
> %ec.ins = insertelement <scalable 2 x i64> undef,
i64 %ec, i32 0<br>
> %ec.splat = shufflevector <scalable 2 x i64> %9,
<scalable 2 x i64> undef, <scalable 2 x i32>
zeroinitializer<br>
> %sv2 = add <scalable 2 x i64> %ec.splat,
%stepvec64<br>
> ;; Perform the extracts<br>
> %res1 = shufflevector <scalable 4 x double> %in,
<scalable 4 x double> undef, <scalable 2 x i64>
%sv1<br>
> %res2 = shufflevector <scalable 4 x double> %in,
<scalable 4 x double> undef, <scalable 2 x i64>
%sv2<br>
> ``<br>
> <br>
> ==================<br>
> 6. Code Generation<br>
> ==================<br>
> <br>
> IR splats will be converted to an experimental
splatvector intrinsic in<br>
> SelectionDAGBuilder.<br>
> <br>
> All three intrinsics are custom lowered and legalized in
the AArch64 backend.<br>
> <br>
> Two new AArch64ISD nodes have been added to represent the
same concepts<br>
> at the SelectionDAG level, while splatvector maps onto
the existing<br>
> AArch64ISD::DUP.<br>
> <br>
> GlobalISel<br>
> ----------<br>
> <br>
> Since GlobalISel was enabled by default on AArch64, it
was necessary to add<br>
> scalable vector support to the LowLevelType
implementation. A single bit was<br>
> added to the raw_data representation for vectors and
vectors of pointers.<br>
> <br>
> In addition, types that only exist in destination
patterns are planted in<br>
> the enumeration of available types for generated code.
While this may not be<br>
> necessary in future, generating an all-true 'ptrue' value
was necessary to<br>
> convert a predicated instruction into an unpredicated
one.<br>
> <br>
> ==========<br>
> 7. Example<br>
> ==========<br>
> <br>
> The following example shows a simple C loop which assigns
the array index to<br>
> the array elements matching that index. The IR shows how
vscale and stepvector<br>
> are used to create the needed values and to advance the
index variable in the<br>
> loop.<br>
> <br>
> C Code<br>
> ------<br>
> <br>
> ``<br>
> void IdentityArrayInit(int *a, int count) {<br>
> for (int i = 0; i < count; ++i)<br>
> a[i] = i;<br>
> }<br>
> ``<br>
> <br>
> Scalable IR Vector Body<br>
> -----------------------<br>
> <br>
> ``<br>
> vector.body.preheader:<br>
> ;; Other setup<br>
> ;; Stepvector used to create initial identity vector<br>
> %stepvector = call <scalable 4 x i32>
@llvm.experimental.vector.stepvector.nxv4i32()<br>
> br vector.body<br>
> <br>
> vector.body<br>
> %index = phi i64 [ %index.next, %vector.body ], [ 0,
%vector.body.preheader ]<br>
> %0 = phi i64 [ %1, %vector.body ], [ 0,
%vector.body.preheader ]<br>
> <br>
> ;; stepvector used for index identity on entry
to loop body ;;<br>
> %vec.ind7 = phi <scalable 4 x i32> [ %step.add8,
%vector.body ],<br>
> [ %stepvector,
%vector.body.preheader ]<br>
> %vscale64 = call i64
@llvm.experimental.vector.vscale.64()<br>
> %vscale32 = trunc i64 %vscale64 to i32<br>
> %1 = add i64 %0, mul (i64 %vscale64, i64 4)<br>
> <br>
> ;; vscale splat used to increment identity
vector ;;<br>
> %insert = insertelement <scalable 4 x i32> undef,
i32 mul (i32 %vscale32, i32 4), i32 0<br>
> %splat shufflevector <scalable 4 x i32> %insert,
<scalable 4 x i32> undef, <scalable 4 x i32>
zeroinitializer<br>
> %step.add8 = add <scalable 4 x i32> %vec.ind7,
%splat<br>
> %2 = getelementptr inbounds i32, i32* %a, i64 %0<br>
> %3 = bitcast i32* %2 to <scalable 4 x i32>*<br>
> store <scalable 4 x i32> %vec.ind7, <scalable 4
x i32>* %3, align 4<br>
> <br>
> ;; vscale used to increment loop index<br>
> %index.next = add i64 %index, mul (i64 %vscale64, i64 4)<br>
> %4 = icmp eq i64 %index.next, %n.vec<br>
> br i1 %4, label %middle.block, label %vector.body,
!llvm.loop !5<br>
> ``<br>
> <br>
> ==========<br>
> 8. Patches<br>
> ==========<br>
> <br>
> List of patches:<br>
> <br>
> 1. Extend VectorType: <a
href="https://reviews.llvm.org/D32530" rel="noreferrer"
target="_blank" moz-do-not-send="true">https://reviews.llvm.org/D32530</a><br>
> 2. Vector element type Tablegen constraint: <a
href="https://reviews.llvm.org/D47768" rel="noreferrer"
target="_blank" moz-do-not-send="true">https://reviews.llvm.org/D47768</a><br>
> 3. LLT support for scalable vectors: <a
href="https://reviews.llvm.org/D47769" rel="noreferrer"
target="_blank" moz-do-not-send="true">https://reviews.llvm.org/D47769</a><br>
> 4. EVT strings and Type mapping: <a
href="https://reviews.llvm.org/D47770" rel="noreferrer"
target="_blank" moz-do-not-send="true">https://reviews.llvm.org/D47770</a><br>
> 5. SVE Calling Convention: <a
href="https://reviews.llvm.org/D47771" rel="noreferrer"
target="_blank" moz-do-not-send="true">https://reviews.llvm.org/D47771</a><br>
> 6. Intrinsic lowering cleanup: <a
href="https://reviews.llvm.org/D47772" rel="noreferrer"
target="_blank" moz-do-not-send="true">https://reviews.llvm.org/D47772</a><br>
> 7. Add VScale intrinsic: <a
href="https://reviews.llvm.org/D47773" rel="noreferrer"
target="_blank" moz-do-not-send="true">https://reviews.llvm.org/D47773</a><br>
> 8. Add StepVector intrinsic: <a
href="https://reviews.llvm.org/D47774" rel="noreferrer"
target="_blank" moz-do-not-send="true">https://reviews.llvm.org/D47774</a><br>
> 9. Add SplatVector intrinsic: <a
href="https://reviews.llvm.org/D47775" rel="noreferrer"
target="_blank" moz-do-not-send="true">https://reviews.llvm.org/D47775</a><br>
> 10. Initial store patterns: <a
href="https://reviews.llvm.org/D47776" rel="noreferrer"
target="_blank" moz-do-not-send="true">https://reviews.llvm.org/D47776</a><br>
> 11. Initial addition patterns: <a
href="https://reviews.llvm.org/D47777" rel="noreferrer"
target="_blank" moz-do-not-send="true">https://reviews.llvm.org/D47777</a><br>
> 12. Initial left-shift patterns: <a
href="https://reviews.llvm.org/D47778" rel="noreferrer"
target="_blank" moz-do-not-send="true">https://reviews.llvm.org/D47778</a><br>
> 13. Implement copy logic for Z regs: <a
href="https://reviews.llvm.org/D47779" rel="noreferrer"
target="_blank" moz-do-not-send="true">https://reviews.llvm.org/D47779</a><br>
> 14. Prevectorized loop unit test: <a
href="https://reviews.llvm.org/D47780" rel="noreferrer"
target="_blank" moz-do-not-send="true">https://reviews.llvm.org/D47780</a><br>
> <br>
<br>
</blockquote>
</div>
</blockquote>
<br>
<pre class="moz-signature" cols="72">--
Hal Finkel
Lead, Compiler Technology and Programming Languages
Leadership Computing Facility
Argonne National Laboratory</pre>
</body>
</html>