<div dir="ltr">The issue isn't limited to calls either. If a half is a liveout of one basic block and used by another basic block. We'll emit an fp_round with 1 for the second argument in the receiving basic block. But the producing basic block won't have done anything to make it true.<div><br></div><div><br clear="all"><div><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature">~Craig</div></div><br></div></div><br><div class="gmail_quote"><div dir="ltr">On Wed, Jan 23, 2019 at 11:53 AM Richard Smith <<a href="mailto:richard@metafoo.co.uk">richard@metafoo.co.uk</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto"><div><div class="gmail_quote"><div dir="ltr" class="gmail-m_-2757709289891774387gmail_attr">On Wed, 23 Jan 2019, 11:27 Craig Topper via llvm-dev, <<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr">While looking at the codegen Andy showed, I notice that the initial SelectionDAG looks like this for x86-64.<div><br></div><div><div> t0: ch = EntryToken</div><div> t2: f32,ch = CopyFromReg t0, Register:f32 %0</div><div> t6: f16 = fp_round t2, TargetConstant:i64<1></div><div> t4: f32,ch = CopyFromReg t0, Register:f32 %1</div><div> t7: f16 = fp_round t4, TargetConstant:i64<1></div><div> t8: f16 = fmul t6, t7</div><div> t10: i64 = Constant<0></div><div> t12: ch = store<(store 2 into @x)> t0, t8, GlobalAddress:i64<half* @x> 0, undef:i64</div><div> t13: f32 = fp_extend t8</div><div> t16: ch,glue = CopyToReg t12, Register:f32 $xmm0, t13</div><div> t17: ch = X86ISD::RET_FLAG t16, TargetConstant:i32<0>, Register:f32 $xmm0, t16:1</div><div><br></div><div>The FP_ROUNDs for the arguments each have the flag set that indicates that the fp_round doesn't lose any information. This is the TargetConstant:i64<1> as the second operand.</div><div><br></div><div>As far as I can tell, any caller of this would have an FP_EXTEND from f16 to f32 in their initial selection dag for calling this function. When the FP_EXTENDs are type legalized by DAGTypeLegalizer::PromoteFloatOp_FP_EXTEND, the FP_EXTEND will be removed completely with no replacement operations. I believe this means there is no guarantee that the f32 value passed in doesn't contain precision beyond the range of f16. So the fp_round nodes saying no information is lost in the callee are not accurate.</div></div></div></div></div></blockquote></div></div><div dir="auto"><br></div><div dir="auto">That seems wrong to me from an ABI perspective; I would expect the burden to be on the caller to only pass a valid "half" value to a "half" parameter. But this leads back to Andy's point: we're inventing an ABI rule here.</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div><div><div dir="ltr" class="gmail-m_-2757709289891774387m_5935810940887226763gmail_signature">~Craig</div></div><br></div></div></div></div><br><div class="gmail_quote"><div dir="ltr">On Tue, Jan 22, 2019 at 10:38 AM Kaylor, Andrew via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" rel="noreferrer" target="_blank">cfe-dev@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div lang="EN-US">
<div class="gmail-m_-2757709289891774387m_5935810940887226763gmail-m_1447868208451550669WordSection1">
<p class="MsoNormal">I'd like to start a discussion about how clang supports _Float16 for target architectures that don't have direct support for 16-bit floating point arithmetic.<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">The current clang language extensions documentation says, "If half-precision instructions are unavailable, values will be promoted to single-precision, similar to the semantics of __fp16 except that the results will be stored in single-precision."
This is somewhat vague (to me) as to what is meant by promotion of values, and the part about results being stored in single-precision isn't what actually happens.<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">Consider this example:<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal"><span style="color:black">_Float16 x;</span><u></u><u></u></p>
<p class="MsoNormal"><span style="color:black">_Float16 f(_Float16 y, _Float16 z) {</span><u></u><u></u></p>
<p class="MsoNormal"><span style="color:black"> x = y * z;</span><u></u><u></u></p>
<p class="MsoNormal"><span style="color:blue"> </span>return<span style="color:black"> x;</span><u></u><u></u></p>
<p class="MsoNormal"><span style="color:black">}</span><u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">When compiling with “-march=core-avx2” that results (after some trivial cleanup) in this IR:<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">@x = global half 0xH0000, align 2<u></u><u></u></p>
<p class="MsoNormal">define half @f(half, half) {<u></u><u></u></p>
<p class="MsoNormal"> %3 = fmul half %0, %1<u></u><u></u></p>
<p class="MsoNormal"> store half %3, half* @x<u></u><u></u></p>
<p class="MsoNormal"> ret half %3<u></u><u></u></p>
<p class="MsoNormal">}<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">That’s not too unreasonable I suppose, except for the fact that it hasn’t taken the lack of target support for half-precision arithmetic into account yet. That will happen in the selection DAG. The assembly code generated looks like this
(with my annotations):<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">f: # @f<u></u><u></u></p>
<p class="MsoNormal"># %bb.0:<u></u><u></u></p>
<p class="MsoNormal"> vcvtps2ph xmm1, xmm1, 4 # Convert argument 1 from single to half<u></u><u></u></p>
<p class="MsoNormal"> vcvtph2ps xmm1, xmm1 # Convert argument 1 back to single<u></u><u></u></p>
<p class="MsoNormal"> vcvtps2ph xmm0, xmm0, 4 # Convert argument 0 from single to half<u></u><u></u></p>
<p class="MsoNormal"> vcvtph2ps xmm0, xmm0 # Convert argument 0 back to single<u></u><u></u></p>
<p class="MsoNormal"> vmulss xmm0, xmm0, xmm1 # xmm0 = xmm0*xmm1 (single precision)<u></u><u></u></p>
<p class="MsoNormal"> vcvtps2ph xmm1, xmm0, 4 # Convert the single precision result to half<u></u><u></u></p>
<p class="MsoNormal"> vmovd eax, xmm1 # Move the half precision result to eax<u></u><u></u></p>
<p class="MsoNormal"> mov word ptr [rip + x], ax # Store the half precision result in the global, x<u></u><u></u></p>
<p class="MsoNormal"> ret # Return the single precision result still in xmm0<u></u><u></u></p>
<p class="MsoNormal">.Lfunc_end0:<u></u><u></u></p>
<p class="MsoNormal"> # -- End function<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">Something odd has happened here, and it may not be obvious what it is. This code begins by converting xmm0 and xmm1 from single to half and then back to single. The first conversion is happening because the back end decided that it needed
to change the types of the parameters to single precision but the function body is expecting half precision values. However, since the target can’t perform the required computation with half precision values they must be converted back to single for the multiplication.
The single precision result of the multiplication is converted to half precision to be stored in the global value, x, but the result is returned as single precision (via xmm0).<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">I’m not primarily worried about the extra conversions here. We can’t get rid of them because we can’t prove they aren’t rounding, but that’s a secondary issue. What I’m worried about is that we allowed/required the back end to improvise
an ABI to satisfy the incoming IR, and the choice it made is questionable.<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">For a point of comparison, I looked at what gcc does. Currently, gcc only allows _Float16 in C, not C++, and if you try to use it with a target that doesn’t have native support for half-precision arithmetic, it tells you “’_Float16’ is
not supported on this target.” That seems preferable to making up an ABI on the fly.<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">I haven’t looked at what happens with clang when compiling for other targets that don’t have native support for half-precision arithmetic, but I would imagine that similar problems exist.<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">Thoughts?<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">Thanks,<u></u><u></u></p>
<p class="MsoNormal">Andy<u></u><u></u></p>
</div>
</div>
_______________________________________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@lists.llvm.org" rel="noreferrer" target="_blank">cfe-dev@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br>
</blockquote></div>
_______________________________________________<br>
LLVM Developers mailing list<br>
<a href="mailto:llvm-dev@lists.llvm.org" rel="noreferrer" target="_blank">llvm-dev@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev</a><br>
</blockquote></div></div></div>
</blockquote></div>