<div dir="ltr">I've reverted this change as a speculative fix for second-stage miscompiles on a number of the sanitizer bots, e.g. <a href="http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-bootstrap-ubsan/builds/14082">http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-bootstrap-ubsan/builds/14082</a> That bot seems to have recovered with the revert in place.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Jul 25, 2019 at 5:13 AM Sanjay Patel via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@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">Author: spatel<br>
Date: Thu Jul 25 05:14:27 2019<br>
New Revision: 367011<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=367011&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=367011&view=rev</a><br>
Log:<br>
[InstCombine] try to narrow a truncated load<br>
<br>
trunc (load X) --> load (bitcast X to narrow type)<br>
<br>
We have this transform in DAGCombiner::ReduceLoadWidth(), but the truncated<br>
load pattern can interfere with other instcombine transforms, so I'd like to<br>
allow the fold sooner.<br>
<br>
Example:<br>
<a href="https://bugs.llvm.org/show_bug.cgi?id=16739" rel="noreferrer" target="_blank">https://bugs.llvm.org/show_bug.cgi?id=16739</a><br>
...in that report, we have bitcasts bracketing these ops, so those could get<br>
eliminated too.<br>
<br>
We've generally ruled out widening of loads early in IR ( LoadCombine -<br>
<a href="http://lists.llvm.org/pipermail/llvm-dev/2016-September/105291.html" rel="noreferrer" target="_blank">http://lists.llvm.org/pipermail/llvm-dev/2016-September/105291.html</a> ), but<br>
that reasoning may not apply to narrowing if we can preserve information<br>
such as the dereferenceable range.<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D64432" rel="noreferrer" target="_blank">https://reviews.llvm.org/D64432</a><br>
<br>
Modified:<br>
    llvm/trunk/lib/Transforms/InstCombine/InstCombineCasts.cpp<br>
    llvm/trunk/test/Transforms/InstCombine/trunc-load.ll<br>
<br>
Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineCasts.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineCasts.cpp?rev=367011&r1=367010&r2=367011&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineCasts.cpp?rev=367011&r1=367010&r2=367011&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineCasts.cpp (original)<br>
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineCasts.cpp Thu Jul 25 05:14:27 2019<br>
@@ -681,6 +681,42 @@ static Instruction *shrinkInsertElt(Cast<br>
   return nullptr;<br>
 }<br>
<br>
+static Instruction *narrowLoad(TruncInst &Trunc,<br>
+                               InstCombiner::BuilderTy &Builder,<br>
+                               const DataLayout &DL) {<br>
+  // Check the layout to ensure we are not creating an unsupported operation.<br>
+  // TODO: Create a GEP to offset the load?<br>
+  if (!DL.isLittleEndian())<br>
+    return nullptr;<br>
+  unsigned NarrowBitWidth = Trunc.getDestTy()->getPrimitiveSizeInBits();<br>
+  if (!DL.isLegalInteger(NarrowBitWidth))<br>
+    return nullptr;<br>
+<br>
+  // Match a truncated load with no other uses.<br>
+  Value *X;<br>
+  if (!match(Trunc.getOperand(0), m_OneUse(m_Load(m_Value(X)))))<br>
+    return nullptr;<br>
+  LoadInst *WideLoad = cast<LoadInst>(Trunc.getOperand(0));<br>
+  if (!WideLoad->isSimple())<br>
+    return nullptr;<br>
+<br>
+  // Don't narrow this load if we would lose information about the<br>
+  // dereferenceable range.<br>
+  bool CanBeNull;<br>
+  uint64_t DerefBits = X->getPointerDereferenceableBytes(DL, CanBeNull) * 8;<br>
+  if (DerefBits < WideLoad->getType()->getPrimitiveSizeInBits())<br>
+    return nullptr;<br>
+<br>
+  // trunc (load X) --> load (bitcast X)<br>
+  PointerType *PtrTy = PointerType::get(Trunc.getDestTy(),<br>
+                                        WideLoad->getPointerAddressSpace());<br>
+  Value *Bitcast = Builder.CreatePointerCast(X, PtrTy);<br>
+  LoadInst *NarrowLoad = new LoadInst(Trunc.getDestTy(), Bitcast);<br>
+  NarrowLoad->setAlignment(WideLoad->getAlignment());<br>
+  copyMetadataForLoad(*NarrowLoad, *WideLoad);<br>
+  return NarrowLoad;<br>
+}<br>
+<br>
 Instruction *InstCombiner::visitTrunc(TruncInst &CI) {<br>
   if (Instruction *Result = commonCastTransforms(CI))<br>
     return Result;<br>
@@ -840,6 +876,9 @@ Instruction *InstCombiner::visitTrunc(Tr<br>
   if (Instruction *I = foldVecTruncToExtElt(CI, *this))<br>
     return I;<br>
<br>
+  if (Instruction *NewLoad = narrowLoad(CI, Builder, DL))<br>
+    return NewLoad;<br>
+<br>
   return nullptr;<br>
 }<br>
<br>
<br>
Modified: llvm/trunk/test/Transforms/InstCombine/trunc-load.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/trunc-load.ll?rev=367011&r1=367010&r2=367011&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/trunc-load.ll?rev=367011&r1=367010&r2=367011&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/Transforms/InstCombine/trunc-load.ll (original)<br>
+++ llvm/trunk/test/Transforms/InstCombine/trunc-load.ll Thu Jul 25 05:14:27 2019<br>
@@ -29,10 +29,15 @@ define i32 @truncload_small_deref(i64* d<br>
 ; On little-endian, we can narrow the load without an offset.<br>
<br>
 define i32 @truncload_deref(i64* dereferenceable(8) %ptr) {<br>
-; CHECK-LABEL: @truncload_deref(<br>
-; CHECK-NEXT:    [[X:%.*]] = load i64, i64* [[PTR:%.*]], align 4<br>
-; CHECK-NEXT:    [[R:%.*]] = trunc i64 [[X]] to i32<br>
-; CHECK-NEXT:    ret i32 [[R]]<br>
+; LE-LABEL: @truncload_deref(<br>
+; LE-NEXT:    [[TMP1:%.*]] = bitcast i64* [[PTR:%.*]] to i32*<br>
+; LE-NEXT:    [[R:%.*]] = load i32, i32* [[TMP1]], align 4<br>
+; LE-NEXT:    ret i32 [[R]]<br>
+;<br>
+; BE-LABEL: @truncload_deref(<br>
+; BE-NEXT:    [[X:%.*]] = load i64, i64* [[PTR:%.*]], align 4<br>
+; BE-NEXT:    [[R:%.*]] = trunc i64 [[X]] to i32<br>
+; BE-NEXT:    ret i32 [[R]]<br>
 ;<br>
   %x = load i64, i64* %ptr<br>
   %r = trunc i64 %x to i32<br>
@@ -42,10 +47,15 @@ define i32 @truncload_deref(i64* derefer<br>
 ; Preserve alignment.<br>
<br>
 define i16 @truncload_align(i32* dereferenceable(14) %ptr) {<br>
-; CHECK-LABEL: @truncload_align(<br>
-; CHECK-NEXT:    [[X:%.*]] = load i32, i32* [[PTR:%.*]], align 16<br>
-; CHECK-NEXT:    [[R:%.*]] = trunc i32 [[X]] to i16<br>
-; CHECK-NEXT:    ret i16 [[R]]<br>
+; LE-LABEL: @truncload_align(<br>
+; LE-NEXT:    [[TMP1:%.*]] = bitcast i32* [[PTR:%.*]] to i16*<br>
+; LE-NEXT:    [[R:%.*]] = load i16, i16* [[TMP1]], align 16<br>
+; LE-NEXT:    ret i16 [[R]]<br>
+;<br>
+; BE-LABEL: @truncload_align(<br>
+; BE-NEXT:    [[X:%.*]] = load i32, i32* [[PTR:%.*]], align 16<br>
+; BE-NEXT:    [[R:%.*]] = trunc i32 [[X]] to i16<br>
+; BE-NEXT:    ret i16 [[R]]<br>
 ;<br>
   %x = load i32, i32* %ptr, align 16<br>
   %r = trunc i32 %x to i16<br>
@@ -98,12 +108,40 @@ define i32 @truncload_volatile(i64* dere<br>
 ; Preserve address space.<br>
<br>
 define i32 @truncload_address_space(i64 addrspace(1)* dereferenceable(8) %ptr) {<br>
-; CHECK-LABEL: @truncload_address_space(<br>
-; CHECK-NEXT:    [[X:%.*]] = load i64, i64 addrspace(1)* [[PTR:%.*]], align 4<br>
-; CHECK-NEXT:    [[R:%.*]] = trunc i64 [[X]] to i32<br>
-; CHECK-NEXT:    ret i32 [[R]]<br>
+; LE-LABEL: @truncload_address_space(<br>
+; LE-NEXT:    [[TMP1:%.*]] = bitcast i64 addrspace(1)* [[PTR:%.*]] to i32 addrspace(1)*<br>
+; LE-NEXT:    [[R:%.*]] = load i32, i32 addrspace(1)* [[TMP1]], align 4<br>
+; LE-NEXT:    ret i32 [[R]]<br>
+;<br>
+; BE-LABEL: @truncload_address_space(<br>
+; BE-NEXT:    [[X:%.*]] = load i64, i64 addrspace(1)* [[PTR:%.*]], align 4<br>
+; BE-NEXT:    [[R:%.*]] = trunc i64 [[X]] to i32<br>
+; BE-NEXT:    ret i32 [[R]]<br>
 ;<br>
   %x = load i64, i64 addrspace(1)* %ptr, align 4<br>
   %r = trunc i64 %x to i32<br>
   ret i32 %r<br>
 }<br>
+<br>
+; Most metadata should be transferred to the narrow load.<br>
+; TODO: We lost the range.<br>
+<br>
+define i32 @truncload_metadata(i64* dereferenceable(8) %ptr) {<br>
+; LE-LABEL: @truncload_metadata(<br>
+; LE-NEXT:    [[TMP1:%.*]] = bitcast i64* [[PTR:%.*]] to i32*<br>
+; LE-NEXT:    [[R:%.*]] = load i32, i32* [[TMP1]], align 4, !invariant.load !0, !nontemporal !1<br>
+; LE-NEXT:    ret i32 [[R]]<br>
+;<br>
+; BE-LABEL: @truncload_metadata(<br>
+; BE-NEXT:    [[X:%.*]] = load i64, i64* [[PTR:%.*]], align 4, !range !0, !invariant.load !1, !nontemporal !2<br>
+; BE-NEXT:    [[R:%.*]] = trunc i64 [[X]] to i32<br>
+; BE-NEXT:    ret i32 [[R]]<br>
+;<br>
+  %x = load i64, i64* %ptr, align 4, !invariant.load !0, !nontemporal !1, !range !2<br>
+  %r = trunc i64 %x to i32<br>
+  ret i32 %r<br>
+}<br>
+<br>
+!0 = !{}<br>
+!1 = !{i32 1}<br>
+!2 = !{i64 0, i64 2}<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div>