<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri","sans-serif";}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:#0563C1;
text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
{mso-style-priority:99;
color:#954F72;
text-decoration:underline;}
span.EmailStyle17
{mso-style-type:personal-compose;
font-family:"Calibri","sans-serif";
color:windowtext;}
.MsoChpDefault
{mso-style-type:export-only;
font-family:"Calibri","sans-serif";}
@page WordSection1
{size:8.5in 11.0in;
margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
{page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="EN-US" link="#0563C1" vlink="#954F72">
<div class="WordSection1">
<p class="MsoNormal">Hello,<o:p></o:p></p>
<p class="MsoNormal"> <o:p></o:p></p>
<p class="MsoNormal">I was looking at the following test case which is very relevant in imaging applications.
<o:p></o:p></p>
<p class="MsoNormal"> <o:p></o:p></p>
<p class="MsoNormal"><i>int sad(unsigned char *pix1, unsigned char *pix2)</i><o:p></o:p></p>
<p class="MsoNormal"><i>{ </i><o:p></o:p></p>
<p class="MsoNormal"><i> int sum = 0;</i><o:p></o:p></p>
<p class="MsoNormal"><i> for( int x = 0; x < 16; x++ )
</i><o:p></o:p></p>
<p class="MsoNormal"><i> {
</i><o:p></o:p></p>
<p class="MsoNormal"><i> sum += abs( pix1[x] - pix2[x] );
</i><o:p></o:p></p>
<p class="MsoNormal"><i> }</i><o:p></o:p></p>
<p class="MsoNormal"><i> return sum;</i><o:p></o:p></p>
<p class="MsoNormal"><i>}</i><o:p></o:p></p>
<p class="MsoNormal"> <o:p></o:p></p>
<p class="MsoNormal">The llvm IR generated after all the IR optimizations is<o:p></o:p></p>
<p class="MsoNormal"> <o:p></o:p></p>
<p class="MsoNormal">…..<o:p></o:p></p>
<p class="MsoNormal"> %9 = bitcast i8* %8 to <4 x i8>*<o:p></o:p></p>
<p class="MsoNormal"> %wide.load.1 = load <4 x i8>* %9, align 1<o:p></o:p></p>
<p class="MsoNormal"> %10 = zext <4 x i8> %wide.load.1 to <4 x i32><o:p></o:p></p>
<p class="MsoNormal"> %11 = getelementptr inbounds i8* %pix2, i64 4<o:p></o:p></p>
<p class="MsoNormal"> %12 = bitcast i8* %11 to <4 x i8>*<o:p></o:p></p>
<p class="MsoNormal"> %wide.load7.1 = load <4 x i8>* %12, align 1<o:p></o:p></p>
<p class="MsoNormal"> %13 = zext <4 x i8> %wide.load7.1 to <4 x i32><o:p></o:p></p>
<p class="MsoNormal"> %14 = sub nsw <4 x i32> %10, %13<o:p></o:p></p>
<p class="MsoNormal"> %15 = icmp uge <4 x i8> %wide.load.1, %wide.load7.1<o:p></o:p></p>
<p class="MsoNormal"> %16 = sub nsw <4 x i32> zeroinitializer, %14<o:p></o:p></p>
<p class="MsoNormal"> %17 = select <4 x i1> %15, <4 x i32> %14, <4 x i32> %16<o:p></o:p></p>
<p class="MsoNormal"> %18 = add nsw <4 x i32> %17, %7<o:p></o:p></p>
<p class="MsoNormal"> %19 = getelementptr inbounds i8* %pix1, i64 8<o:p></o:p></p>
<p class="MsoNormal">…..<o:p></o:p></p>
<p class="MsoNormal"> <o:p></o:p></p>
<p class="MsoNormal">The test case is a perfect example for the generation of Sum of Absolute Difference (SAD) instruction which is present in most of the targets. The proposed generated IR is : ( directly x86 intrinsic is called just to demonstrate the difference
) <o:p></o:p></p>
<p class="MsoNormal"> <o:p></o:p></p>
<p class="MsoNormal">…..<o:p></o:p></p>
<p class="MsoNormal">%6 = bitcast i8* %5 to x86_mmx*<o:p></o:p></p>
<p class="MsoNormal"> %wide.load8.1 = load x86_mmx* %6, align 1<o:p></o:p></p>
<p class="MsoNormal"> %7 = getelementptr inbounds i8* %pix2, i64 8<o:p></o:p></p>
<p class="MsoNormal"> %8 = bitcast i8* %7 to x86_mmx*<o:p></o:p></p>
<p class="MsoNormal"> %wide.load79.1 = load x86_mmx* %8, align 1<o:p></o:p></p>
<p class="MsoNormal"> %9 = call x86_mmx @llvm.x86.mmx.psad.bw(x86_mmx %wide.load8.1, x86_mmx %wide.load79.1)<o:p></o:p></p>
<p class="MsoNormal"> %10 = bitcast x86_mmx %9 to i64<o:p></o:p></p>
<p class="MsoNormal"> %11 = trunc i64 %10 to i32<o:p></o:p></p>
<p class="MsoNormal"> %12 = add i32 %11, %4<o:p></o:p></p>
<p class="MsoNormal">…..<o:p></o:p></p>
<p class="MsoNormal"> <o:p></o:p></p>
<p class="MsoNormal">This Loop optimization can reduce the loop to only one instruction for every 4 or 8 or 16 iterations of the loop ( depending on the target sad instruction).<o:p></o:p></p>
<p class="MsoNormal"> <o:p></o:p></p>
<p class="MsoNormal"><b><span style="font-size:14.0pt">Proposed Solution</span></b><o:p></o:p></p>
<p class="MsoNormal"><b><span style="font-size:14.0pt"> </span></b><o:p></o:p></p>
<p class="MsoNormal">The sad pattern shown above which is the abs pattern with reduction variable ( sequence of sub, icomp, sub, select, add ) can be replaced with an intrinsic call.
<o:p></o:p></p>
<p class="MsoNormal">For a non-unrolled loop we can do this in LoopVectorization where all the infrastructure for identifying reduction variables is already there.
<o:p></o:p></p>
<p class="MsoNormal">We just need to identify the sad pattern, remove those instructions and call an intrinsic.
<o:p></o:p></p>
<p class="MsoNormal">This can be done in the loop body which Vectorizer creates (vector.body) without disturbing the scalar body of the loop.<o:p></o:p></p>
<p class="MsoNormal"> <o:p></o:p></p>
<p class="MsoNormal">For this to happen in LoopVectorizer, we also need to influence the cost modeling of LV. For computing cost for different Vectorization Factors, we should remove the cost of sad pattern and add the cost of intrinsic.<o:p></o:p></p>
<p class="MsoNormal">If selected vectorization factor comes to be equal to any operand vector size of basic SAD instruction for that particular target (8 for x86 target) then we can go ahead and replace with intrinsic.<o:p></o:p></p>
<p class="MsoNormal"> <o:p></o:p></p>
<p class="MsoNormal">This intrinsic call can be a call to llvm intrinsic which can be lowered into different target intrinsic calls depending on the VF selected.<o:p></o:p></p>
<p class="MsoNormal"> <o:p></o:p></p>
<p class="MsoNormal">For unrolled loops, we can target in SLPVectorizer.<o:p></o:p></p>
<p class="MsoNormal"> <o:p></o:p></p>
<p class="MsoNormal">The work in loopVectorizer using llvm intrinsic call is ready for x86 codegen and can send the patch after this discussion.
<o:p></o:p></p>
<p class="MsoNormal">( Attached contains complete IR with and without 8 byte SAD for the above test case after optimizations )<o:p></o:p></p>
<p class="MsoNormal"> <o:p></o:p></p>
<p class="MsoNormal">Please provide your thoughts.<o:p></o:p></p>
<p class="MsoNormal"> <o:p></o:p></p>
<p class="MsoNormal">Thank you,<o:p></o:p></p>
<p class="MsoNormal">Vijender <o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
</body>
</html>