<div dir="ltr"><div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small">Tim,</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small"><br></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small">
Glad to know we get agreement now!</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small"><br></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small">
To make sure we are really on the same page, I still want to give some more comments.</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small"><br></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small">
I think maybe AAPCS64 isn't clear enough to define what "element aligned short vector" is, and current the "short vector" is always defined as "total size aligned short vector". We should probably propose to add more details around this in AAPCS64.</div>
<div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small"><br></div><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div class=""><br>
</div>That's certainly an approach (one I favoured until recently). It would<br>
be more friendly to LLVM's expectations, but harder for the AAPCS. I<br>
believe for that to work bitcasts would have to become non-trivial,<br>
and be inserted at all function-call boundaries involving vectors. For<br>
example (illustrating function calls):<br>
<br>
    declare void @foo(<4 x i16>)<br>
    define void @bar(<4 x i16>* %addr) {<br>
      %vec = load <4 x i16>* %addr<br>
      call void @foo(<4 x i16> %vec)<br>
      ret void<br>
    }<br>
<br>
The AAPCS requires us to pass %vec *as if* it had been loaded by<br>
"ldr", so if we use "ld1 {v0.4h}" we need some kind of "rev"<br>
instruction to reformat it before the call. Otherwise a round-trip via<br>
GCC (for example) could produce incorrect results (say, if @foo simply<br>
stored the vector back to %addr).<br>
<br></blockquote><div class="gmail_default"><span style="font-family:arial,helvetica,sans-serif"><br></span></div><div class="gmail_default"><span style="font-family:arial,helvetica,sans-serif">For "rev" instructions, ARMv8ARM says "</span><font face="arial, helvetica, sans-serif">An application or device driver might have to interface to memory-mapped peripheral registers or shared memory</font></div>
<div class="gmail_default"><font face="arial, helvetica, sans-serif">structures that are not the same endianness as the internal data structures.", so we would only need this instruction if we want to interact between little-endian and big-endian. For the scenario of supporting an unique one only, either of big or little, we needn't to use this instruction at all, because with the hardware endianness support, ldr/ld1 could always behave correctly for different endianness.</font></div>
<div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small"></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

Similarly, an isolated bitcast is non-trivial:<br>
<br>
    define void @foo(<4 x i16>* %in, <8 x i8>* %out) {<br>
      %shortvec = load <4 x i16>* %in<br>
      %charvec = bitcast <4 x i16> %shortvec to <8 x i8><br>
      store <8 x i8> %charvec, <8 x i8>* %out<br>
      ret void<br>
    }<br>
<br>
Bitcast is specified in the LangRef to be equivalent to storing one<br>
type and loading the other, so this fragment is (by definition of<br>
bitcast) equivalent to:<br>
<br>
    define void @foo(<4 x i16>* %in, <8 x i8>* %out) {<br>
      %tmp = alloca <4 x i16><br>
      %shortvec = load <4 x i16>* %in<br>
      store <4 x i16> %shortvec, <4 x i16>* %tmp<br>
      %tmp.char = bitcast <4 x i16>* %tmp to <8 x i8>*<br>
      %charvec = load <8  x i8>* %tmp.char<br>
      store <8 x i8> %charvec, <8 x i8>* %out<br>
      ret void<br>
    }<br>
<br>
Under the ld1/st1 scheme this could clearly generate code like:<br>
     [...]<br>
     ld1 {v0.4h}, [x0]<br>
     st1 {v0.4h}, [sp]<br>
     ld1 {v0.8b}, [sp]<br>
     st1 {v0.8b}, [x1]<br>
     [...]<br>
<br>
If you want to go back to the original bitcast for efficiency<br>
(skipping that middle st1/ld1 pair), you'll see that the bitcast has<br>
to be a non-trivial operation (some kind of "rev" again, I believe).<br>
<br></blockquote><span style="font-family:arial,helvetica,sans-serif"><div class="gmail_quote"><span style="font-family:arial,helvetica,sans-serif"><br></span></div>For all the cases <div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small;display:inline">
given</div> above, alignment isn't really specified, so llvm should just follow default layout, that is, total size alignment. <div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small;display:inline">
Therefore</div> we should always generate ldr<div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small;display:inline">/str</div> for all of them.<div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small;display:inline">
 For the bitcast, I don't think we should generate any instruction. If only ldr/str and ld1/st1 can be used in pair, we shouldn't have any issue at all. </div></span><span style="font-family:arial,helvetica,sans-serif">But "rev" should still be useful <div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small;display:inline">
for the scenario as described in ARMv8ARM.</div></span></div><div class="gmail_quote"><div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small"></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

It can be made to work in the backend (and would isolate the<br>
big-endian changes more, which is why I preferred it earlier), but I<br>
suspect it will produce worse code on the whole.<br>
<div class=""><br></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class="">> As Albrecht mentioned, maybe the solution is "The frontend must give the<br>

> backend a totally different type for short vectors". To some extension, I<br>
> agree with his point.<br>
<br>
</div>I don't think there's any need for the backend to have dual types. All<br>
programmer-visible semantics can be represented with just one,<br>
provided the front-end is aware of the difference. But until such<br>
types come along in ACLE (hopefully never), we probably needn't<br>
discuss it.<br>
<div class=""><br>
>> If we decided to support strict alignment mode efficiently, we would<br>
>> probably want to emit an "ld1 {v0.8b}" (i.e. always use the .8b or<br>
>> .16b version), since that's got the same semantics as ldr.<br>
><br>
> It is only true for little-endian, isn't it?<br>
<br>
</div>I don't believe so. I think "ld1 {v0.8b}" is equivalent to "ldr d0" on<br>
both endians (and the equivalent 16b statement).<br>
<div class=""><br>
> If we always use ldr/str for bit-endian without caring about alignment,<br>
> 1) It would not work for non-strict mode, because the address might be<br>
> unaligned.<br>
<br>
</div>Unaligned loads are already expanded to support strict mode. Try compiling this:<br>
<br>
    define <4 x i16> @foo(<4 x i16>* %addr) {<br>
<div class="">      %val = load < 4 x i16>* %addr, align 2<br>
</div>      ret <4 x i16> %val<br>
    }<br>
<br>
As part of the optimisation to make that more efficient, the<br>
programmer would have to be wary of endian issues. It could be done in<br>
either scheme, of course.<br></blockquote><div><br></div><div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small">I would say for this case, to support strict mode, we should have to use ld1, although the address might have been expanded to 8-byte aligned, because "align 2" implies the data is from an array of elements, and the other model passing data to this function should have known the data will be loaded by "align 2", so it uses st1. This should be guaranteed by the interfaces between those two modules, i.e. the .h file in C, which should be included by both modules, then the semantic can be guaranteed. For whatever the optimizations are applied, we should not change this interface, I think.</div>
</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div class=""><br>
> 2) The data may come from a real array of elements rather than HVA, and the<br>
> semantic of using ldr/str is conflict with the end-user's definition,<br>
<br>
</div>I don't believe so. Clang will generate array accesses as scalar<br>
operations. The vectorizer may transform them, but only into<br>
well-specifier LLVM IR. How we implement that is our choice, and we<br>
can use either ld1 or ldr. Do you have a counter-example?<br>
<br></blockquote><div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small">Yes, we can apply optimization, but we should change the semantic interface crossing functions. My example is in a .h file, if we define,</div>
</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small"><br></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small">extern int16_t a[4];</div>
<div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small"><br></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small">In function f1 defined in file file1, and function f2 in file file2, we should guarantee to use ld1/st1 to load/store variable a. This would guarantee system works for both little-endian and big-endian, unless we use different endianness for f1 and f2. In C, we say (a++ == &a[1]) is true, this should be guaranteed for big-endian as well.</div>
<div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small"><br></div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small">For local variable within a single function, yes, you can do whatever optimizations you want, and the alignment can also be changed.</div>
<div><br></div><div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small">Thanks,</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif;font-size:small">-Jiangning</div>
<br></div></div>
</div></div>