<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=utf-8">
<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;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:#0563C1;
        text-decoration:underline;}
p.MsoListParagraph, li.MsoListParagraph, div.MsoListParagraph
        {mso-style-priority:34;
        margin-top:0in;
        margin-right:0in;
        margin-bottom:0in;
        margin-left:.5in;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
span.EmailStyle18
        {mso-style-type:personal-reply;
        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;}
/* List Definitions */
@list l0
        {mso-list-id:1605921364;
        mso-list-type:hybrid;
        mso-list-template-ids:-1409509350 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
@list l0:level1
        {mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-.25in;}
@list l0:level2
        {mso-level-number-format:alpha-lower;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-.25in;}
@list l0:level3
        {mso-level-number-format:roman-lower;
        mso-level-tab-stop:none;
        mso-level-number-position:right;
        text-indent:-9.0pt;}
@list l0:level4
        {mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-.25in;}
@list l0:level5
        {mso-level-number-format:alpha-lower;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-.25in;}
@list l0:level6
        {mso-level-number-format:roman-lower;
        mso-level-tab-stop:none;
        mso-level-number-position:right;
        text-indent:-9.0pt;}
@list l0:level7
        {mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-.25in;}
@list l0:level8
        {mso-level-number-format:alpha-lower;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-.25in;}
@list l0:level9
        {mso-level-number-format:roman-lower;
        mso-level-tab-stop:none;
        mso-level-number-position:right;
        text-indent:-9.0pt;}
ol
        {margin-bottom:0in;}
ul
        {margin-bottom:0in;}
--></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" style="word-wrap:break-word">
<div class="WordSection1">
<p class="MsoNormal">I suspect the transform you’re trying to do is more complicated than you’re making it out to be.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">In general, if you have a class that isn’t “POD for the purpose of layout” (<a href="https://itanium-cxx-abi.github.io/cxx-abi/abi.html">https://itanium-cxx-abi.github.io/cxx-abi/abi.html</a>), derived classes can store data in the tail
 padding.  So the “padding” might contain data the program cares about.  If you want to overwrite that space, you need to prove there isn’t a derived class storing data there.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Possible proof approaches:<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<ol style="margin-top:0in" start="1" type="1">
<li class="MsoListParagraph" style="margin-left:0in;mso-list:l0 level1 lfo1">If the class is marked “final”, there aren’t any derived classes.<o:p></o:p></li><li class="MsoListParagraph" style="margin-left:0in;mso-list:l0 level1 lfo1">Array indexing with the wrong pointer type might be illegal.<o:p></o:p></li></ol>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">-Eli<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<div style="border:none;border-left:solid blue 1.5pt;padding:0in 0in 0in 4.0pt">
<div>
<div style="border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal"><b>From:</b> cfe-dev <cfe-dev-bounces@lists.llvm.org> <b>On Behalf Of
</b>Han Zhu via cfe-dev<br>
<b>Sent:</b> Wednesday, July 21, 2021 11:46 AM<br>
<b>To:</b> cfe-dev@lists.llvm.org; llvm-dev@lists.llvm.org<br>
<b>Subject:</b> [EXT] [cfe-dev] How to tell if a class contains tail padding?<o:p></o:p></p>
</div>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<p class="MsoNormal">Hi,<br>
<br>
I'm working on an optimization to improve LoopIdiomRecognize pass. For a trivial loop like this:<br>
<br>
```<br>
struct S {<br>
  int a;<br>
  int b;<br>
  char c;<br>
  // 3 bytes padding<br>
};<br>
<br>
unsigned copy_noalias(S* __restrict__ a, S* b, int n) {<br>
  for (int i = 0; i < n; i++) {<br>
    a[i] = b[i];<br>
  }<br>
  return sizeof(a[0]);<br>
}<br>
```<br>
<br>
Clang generates the below loop (some parts of IR omitted):<br>
```<br>
%struct.S = type { i32, i32, i8 }<br>
<br>
for.body:                                         ; preds = %for.cond<br>
  %2 = load %struct.S*, %struct.S** %b.addr, align 8<br>
  %3 = load i32, i32* %i, align 4<br>
  %idxprom = sext i32 %3 to i64<br>
  %arrayidx = getelementptr inbounds %struct.S, %struct.S* %2, i64 %idxprom<br>
  %4 = load %struct.S*, %struct.S** %a.addr, align 8<br>
  %5 = load i32, i32* %i, align 4<br>
  %idxprom1 = sext i32 %5 to i64<br>
  %arrayidx2 = getelementptr inbounds %struct.S, %struct.S* %4, i64 %idxprom1<br>
  %6 = bitcast %struct.S* %arrayidx2 to i8*<br>
  %7 = bitcast %struct.S* %arrayidx to i8*<br>
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %6, i8* align 4 %7, i64 12, i1 false)<br>
  br label %for.inc<br>
```<br>
<br>
It can be transformed into a single memcpy:<br>
<br>
```<br>
for.body.preheader:                               ; preds = %entry<br>
  %b10 = bitcast %struct.S* %b to i8*<br>
  %a9 = bitcast %struct.S* %a to i8*<br>
  %0 = zext i32 %n to i64<br>
  %1 = mul nuw nsw i64 %0, 12<br>
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %a9, i8* align 4 %b10, i64 %1, i1 false)<br>
  br label %for.cond.cleanup<br>
```<br>
<br>
The problem is, if the copied elements are a class, this doesn't work. For a<br>
class with the same members:<br>
```<br>
%class.C = type <{ i32, i32, i8, [3 x i8] }><br>
```<br>
<br>
Clang does some optimization to generate a memcpy of nine bytes, omitting the<br>
tail padding:<br>
<br>
```<br>
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %6, i8* align 4 %7, i64 9, i1 false)<br>
```<br>
<br>
Then in LLVM, we find the memcpy is not touching every byte of the array, so<br>
we abort the transformation.<br>
<br>
If we could tell the untouched three bytes are padding, we should be able to<br>
still do the optimization, but LLVM doesn't seem to have this information. I<br>
tried using `DataLayout::getTypeStoreSize()`, and it returned 12 bytes. I also<br>
tried `StructLayout`, and it treats the tail padding as a regular class member.<br>
<br>
Is there an API in LLVM to tell if a class has tail padding? If not, would it<br>
be useful to add this feature?<br>
<br>
Thanks,<br>
Han<o:p></o:p></p>
</div>
</div>
</div>
</body>
</html>