<div dir="ltr"><div>Makes sense, thanks for the quick response. I've filed a bug report:<br></div><div><a href="http://llvm.org/bugs/show_bug.cgi?id=22049">http://llvm.org/bugs/show_bug.cgi?id=22049</a><br></div><div><br></div><div>In general, it appears that the issue arises when articulating the alignment of an array in a struct. In this case, loads and stores from the array don't share a use/def chain with the alignment fact. I believe this is a result of a prior optimization pass canonicalizing 1) a struct GEP to the start of the array, followed by 2) a GEP indexing into the array, into a single 1+2) struct GEP with an offset. (I didn't share my original un-optimized IR with an intact use-def chain as I didn't realize the underlying issue until now).<br></div><div><br></div><div>Alternatively, if there was a way to add alignment metadata to an array in a struct type declaration, that would offer a more direct solution for my specific use case. To my knowledge, such an annotation is not supported.</div><div><br></div><div>v/r,</div><div>Josh</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Sun, Dec 28, 2014 at 5:21 PM, Hal Finkel <span dir="ltr"><<a href="mailto:hfinkel@anl.gov" target="_blank">hfinkel@anl.gov</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">----- Original Message -----<br>
> From: "Josh Klontz" <<a href="mailto:josh.klontz@gmail.com">josh.klontz@gmail.com</a>><br>
> To: "Dev" <<a href="mailto:llvmdev@cs.uiuc.edu">llvmdev@cs.uiuc.edu</a>><br>
> Sent: Friday, December 26, 2014 8:27:43 AM<br>
> Subject: [LLVMdev] Correct usage of `llvm.assume` for loop vectorization      alignment?<br>
><br>
> Using LLVM ToT and Hal's helpful slide deck [1], I've been trying to<br>
> use `llvm.assume` to communicate pointer alignment guarantees to<br>
> vector load and store instructions. For example, in [2] %5 and %9<br>
> are guaranteed to be 32-byte aligned. However, if I run this IR<br>
> through `opt -O3 -datalayout -S`, the vectorized loads and stores<br>
> are still 1-byte aligned [3]. What's going wrong? Do I have to move<br>
> the `llvm.assume` into the loop body?<br>
<br>
</span>Hi John,<br>
<br>
The problem is that you're asserting an alignment fact about:<br>
<span class="">  %9 = getelementptr inbounds %u8XY* %0, i64 0, i32 6, i64 0<br>
<br>
</span>and you want this to apply to pointers derived from this value within the loop:<br>
<span class="">  %17 = getelementptr %u8XY* %0, i64 0, i32 6, i64 %index<br>
<br>
</span>I'm pretty sure we currently only look 'up' the use/def chain for alignment facts, and so nothing triggers because %17 is derived from %0, and there is no alignment fact asserted directly on %0.<br>
<br>
Can you please file a bug report about this (at <a href="http://llvm.org/bugs/" target="_blank">http://llvm.org/bugs/</a>)? I think that we can likely fix this.<br>
<br>
 -Hal<br>
<div><div class="h5"><br>
><br>
><br>
> v/r,<br>
> Josh<br>
><br>
><br>
><br>
><br>
><br>
> [1]<br>
> <a href="http://llvm.org/devmtg/2014-10/Slides/Finkel-IntrinsicsMetadataAttributes.pdf" target="_blank">http://llvm.org/devmtg/2014-10/Slides/Finkel-IntrinsicsMetadataAttributes.pdf</a><br>
><br>
><br>
> [2]<br>
> ; ModuleID = 'align.ll'<br>
><br>
><br>
> %u8XY = type { i32, i32, i32, i32, i32, i32, [0 x i8] }<br>
><br>
><br>
> ; Function Attrs: noduplicate nounwind readonly<br>
> declare noalias %u8XY* @likely_new(i32 zeroext, i32 zeroext, i32<br>
> zeroext, i32 zeroext, i32 zeroext, i8* noalias nocapture) #0<br>
><br>
><br>
> ; Function Attrs: nounwind<br>
> declare void @llvm.assume(i1) #1<br>
><br>
><br>
> ; Function Attrs: nounwind<br>
> define %u8XY* @benchmark(%u8XY*) #1 {<br>
> entry:<br>
> %1 = getelementptr inbounds %u8XY* %0, i64 0, i32 3<br>
> %columns = load i32* %1, align 4, !range !0<br>
> %2 = getelementptr inbounds %u8XY* %0, i64 0, i32 4<br>
> %rows = load i32* %2, align 4, !range !0<br>
> %3 = tail call %u8XY* @likely_new(i32 24584, i32 1, i32 %columns, i32<br>
> %rows, i32 1, i8* null)<br>
> %4 = zext i32 %rows to i64<br>
> %dst_y_step = zext i32 %columns to i64<br>
> %5 = getelementptr inbounds %u8XY* %3, i64 0, i32 6, i64 0<br>
> %6 = ptrtoint i8* %5 to i64<br>
> %7 = and i64 %6, 31<br>
> %8 = icmp eq i64 %7, 0<br>
> tail call void @llvm.assume(i1 %8)<br>
> %9 = getelementptr inbounds %u8XY* %0, i64 0, i32 6, i64 0<br>
> %10 = ptrtoint i8* %9 to i64<br>
> %11 = and i64 %10, 31<br>
> %12 = icmp eq i64 %11, 0<br>
> tail call void @llvm.assume(i1 %12)<br>
> %13 = mul nuw nsw i64 %4, %dst_y_step<br>
> br label %x_body<br>
><br>
><br>
> x_body: ; preds = %x_body, %entry<br>
> %y = phi i64 [ 0, %entry ], [ %y_increment, %x_body ]<br>
> %14 = getelementptr %u8XY* %0, i64 0, i32 6, i64 %y<br>
> %15 = load i8* %14, align 1, !llvm.mem.parallel_loop_access !1<br>
> %.lobit = lshr i8 %15, 7<br>
> %16 = getelementptr %u8XY* %3, i64 0, i32 6, i64 %y<br>
> store i8 %.lobit, i8* %16, align 1, !llvm.mem.parallel_loop_access !1<br>
> %y_increment = add nuw nsw i64 %y, 1<br>
> %y_postcondition = icmp eq i64 %y_increment, %13<br>
> br i1 %y_postcondition, label %y_exit, label %x_body, !llvm.loop !2<br>
><br>
><br>
> y_exit: ; preds = %x_body<br>
> ret %u8XY* %3<br>
> }<br>
><br>
><br>
> attributes #0 = { noduplicate nounwind readonly }<br>
> attributes #1 = { nounwind }<br>
><br>
><br>
> !0 = !{i32 1, i32 -1}<br>
> !1 = !{!1}<br>
> !2 = !{!2}<br>
><br>
><br>
> [3]<br>
> ; ModuleID = 'align.ll'<br>
><br>
><br>
> %u8XY = type { i32, i32, i32, i32, i32, i32, [0 x i8] }<br>
><br>
><br>
> ; Function Attrs: noduplicate nounwind readonly<br>
> declare noalias %u8XY* @likely_new(i32 zeroext, i32 zeroext, i32<br>
> zeroext, i32 zeroext, i32 zeroext, i8* noalias nocapture) #0<br>
><br>
><br>
> ; Function Attrs: nounwind<br>
> declare void @llvm.assume(i1) #1<br>
><br>
><br>
> ; Function Attrs: nounwind<br>
> define %u8XY* @benchmark(%u8XY*) #1 {<br>
> entry:<br>
> %1 = getelementptr inbounds %u8XY* %0, i64 0, i32 3<br>
> %columns = load i32* %1, align 4, !range !0<br>
> %2 = getelementptr inbounds %u8XY* %0, i64 0, i32 4<br>
> %rows = load i32* %2, align 4, !range !0<br>
> %3 = tail call %u8XY* @likely_new(i32 24584, i32 1, i32 %columns, i32<br>
> %rows, i32 1, i8* null)<br>
> %4 = zext i32 %rows to i64<br>
> %dst_y_step = zext i32 %columns to i64<br>
> %5 = getelementptr inbounds %u8XY* %3, i64 0, i32 6, i64 0<br>
> %6 = ptrtoint i8* %5 to i64<br>
> %7 = and i64 %6, 31<br>
> %8 = icmp eq i64 %7, 0<br>
> tail call void @llvm.assume(i1 %8)<br>
> %9 = getelementptr inbounds %u8XY* %0, i64 0, i32 6, i64 0<br>
> %10 = ptrtoint i8* %9 to i64<br>
> %11 = and i64 %10, 31<br>
> %12 = icmp eq i64 %11, 0<br>
> tail call void @llvm.assume(i1 %12)<br>
> %13 = mul nuw nsw i64 %4, %dst_y_step<br>
> %14 = zext i32 %rows to i64<br>
> %15 = zext i32 %columns to i64<br>
> %16 = mul nuw i64 %14, %15<br>
> %n.vec = and i64 %16, -4<br>
> %cmp.zero = icmp eq i64 %n.vec, 0<br>
> br i1 %cmp.zero, label %middle.block, label %vector.body.preheader<br>
><br>
><br>
> vector.body.preheader: ; preds = %entry<br>
> br label %vector.body<br>
><br>
><br>
> vector.body: ; preds = %vector.body.preheader, %vector.body<br>
> %index = phi i64 [ %index.next, %vector.body ], [ 0,<br>
> %vector.body.preheader ]<br>
> %17 = getelementptr %u8XY* %0, i64 0, i32 6, i64 %index<br>
> %18 = bitcast i8* %17 to <4 x i8>*<br>
> %wide.load = load <4 x i8>* %18, align 1<br>
> %19 = lshr <4 x i8> %wide.load, <i8 7, i8 7, i8 7, i8 7><br>
> %20 = getelementptr %u8XY* %3, i64 0, i32 6, i64 %index<br>
> %21 = bitcast i8* %20 to <4 x i8>*<br>
> store <4 x i8> %19, <4 x i8>* %21, align 1<br>
> %index.next = add i64 %index, 4<br>
> %22 = icmp eq i64 %index.next, %n.vec<br>
> br i1 %22, label %middle.block.loopexit, label %vector.body,<br>
> !llvm.loop !1<br>
><br>
><br>
> middle.block.loopexit: ; preds = %vector.body<br>
> br label %middle.block<br>
><br>
><br>
> middle.block: ; preds = %middle.block.loopexit, %entry<br>
> %resume.val = phi i64 [ 0, %entry ], [ %n.vec, %middle.block.loopexit<br>
> ]<br>
> %cmp.n = icmp eq i64 %16, %resume.val<br>
> br i1 %cmp.n, label %y_exit, label %x_body.preheader<br>
><br>
><br>
> x_body.preheader: ; preds = %middle.block<br>
> br label %x_body<br>
><br>
><br>
> x_body: ; preds = %x_body.preheader, %x_body<br>
> %y = phi i64 [ %y_increment, %x_body ], [ %resume.val,<br>
> %x_body.preheader ]<br>
> %23 = getelementptr %u8XY* %0, i64 0, i32 6, i64 %y<br>
> %24 = load i8* %23, align 1, !llvm.mem.parallel_loop_access !4<br>
> %.lobit = lshr i8 %24, 7<br>
> %25 = getelementptr %u8XY* %3, i64 0, i32 6, i64 %y<br>
> store i8 %.lobit, i8* %25, align 1, !llvm.mem.parallel_loop_access !4<br>
> %y_increment = add nuw nsw i64 %y, 1<br>
> %y_postcondition = icmp eq i64 %y_increment, %13<br>
> br i1 %y_postcondition, label %y_exit.loopexit, label %x_body,<br>
> !llvm.loop !5<br>
><br>
><br>
> y_exit.loopexit: ; preds = %x_body<br>
> br label %y_exit<br>
><br>
><br>
> y_exit: ; preds = %y_exit.loopexit, %middle.block<br>
> ret %u8XY* %3<br>
> }<br>
><br>
><br>
> attributes #0 = { noduplicate nounwind readonly }<br>
> attributes #1 = { nounwind }<br>
><br>
><br>
> !0 = !{i32 1, i32 -1}<br>
> !1 = !{!1, !2, !3}<br>
> !2 = !{!"llvm.loop.vectorize.width", i32 1}<br>
> !3 = !{!"llvm.loop.interleave.count", i32 1}<br>
> !4 = !{!4}<br>
> !5 = !{!5, !2, !3}<br>
</div></div>> _______________________________________________<br>
> LLVM Developers mailing list<br>
> <a href="mailto:LLVMdev@cs.uiuc.edu">LLVMdev@cs.uiuc.edu</a>         <a href="http://llvm.cs.uiuc.edu" target="_blank">http://llvm.cs.uiuc.edu</a><br>
> <a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev</a><br>
><br>
<span class="HOEnZb"><font color="#888888"><br>
--<br>
Hal Finkel<br>
Assistant Computational Scientist<br>
Leadership Computing Facility<br>
Argonne National Laboratory<br>
</font></span></blockquote></div><br></div>