<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Fri, May 16, 2014 at 4:47 PM, Louis Gerbarg <span dir="ltr"><<a href="mailto:lgg@apple.com" target="_blank">lgg@apple.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Author: louis<br>
Date: Fri May 16 18:47:24 2014<br>
New Revision: 209049<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=209049&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=209049&view=rev</a><br>
Log:<br>
Add support for combining GEPs across PHI nodes<br>
<br>
Currently LLVM will generally merge GEPs. This allows backends to use more<br>
complex addressing modes. In some cases this is not happening because there<br>
is PHI inbetween the two GEPs:<br>
<br>
 GEP1--\<br>
    |-->PHI1-->GEP3<br>
 GEP2--/<br>
<br>
This patch checks to see if GEP1 and GEP2 are similiar enough that they can be<br>
cloned (GEP12) in GEP3's BB, allowing GEP->GEP merging (GEP123):<br>
<br>
 GEP1--\           --\              --\<br>
    |-->PHI1-->GEP3  ==>   |-->PHI2->GEP12->GEP3 == >   |-->PHI2->GEP123<br>
 GEP2--/           --/              --/<br>
<br>
This also breaks certain use chains that are preventing GEP->GEP merges that the<br>
the existing instcombine would merge otherwise.<br>
<br>
Tests included.<br>
<br>
rdar://15547484<br>
<br>
Added:<br>
  llvm/trunk/test/Transforms/InstCombine/gepphigep.ll<br>
Modified:<br>
  llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp<br>
<br>
Modified: llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp?rev=209049&r1=209048&r2=209049&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp?rev=209049&r1=209048&r2=209049&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp (original)<br>
+++ llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp Fri May 16 18:47:24 2014<br>
@@ -1220,6 +1220,65 @@ Instruction *InstCombiner::visitGetEleme<br>
   if (MadeChange) return &GEP;<br>
  }<br>
<br>
+ Â // Check to see if the inputs to the PHI node are getelementptr instructions.<br>
+ Â if (PHINode *PN = dyn_cast<PHINode>(PtrOp)) {<br>
+ Â Â GetElementPtrInst *Op1 = dyn_cast<GetElementPtrInst>(PN->getOperand(0));<br>
+ Â Â if (!Op1)<br>
+ Â Â Â return nullptr;<br>
+<br>
+ Â Â signed DI = -1;<br>
+<br>
+ Â Â for (auto I = PN->op_begin()+1, E = PN->op_end(); I !=E; ++I) {<br>
+ Â Â Â GetElementPtrInst *Op2 = dyn_cast<GetElementPtrInst>(*I);<br>
+ Â Â Â if (!Op2 || Op1->getNumOperands() != Op1->getNumOperands())</blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
+ Â Â Â Â return nullptr;<br></blockquote><div><br></div><div><div>Is this meant to be "Op1->getNumOperands() != Op2->getNumOperands()"?</div><div>"Op1->getNumOperands() != Op1->getNumOperands()" will be false.<br>
</div></div><div><br></div><div>Â </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
+<br>
+ Â Â Â for (unsigned J = 0, F = Op1->getNumOperands(); J != F; ++J) {<br>
+ Â Â Â Â if (Op1->getOperand(J) != Op2->getOperand(J)) {<br>
+ Â Â Â Â Â if (DI == -1) {<br>
+ Â Â Â Â Â Â // We have not seen any differences yet in the GEPs feeding the<br>
+ Â Â Â Â Â Â // PHI yet, so we record this one.<br>
+ Â Â Â Â Â Â DI = J;<br>
+ Â Â Â Â Â } else {<br>
+ Â Â Â Â Â Â // The GEP is different by more than one input. While this could be<br>
+ Â Â Â Â Â Â // extended to support GEPs that vary by more than one variable it<br>
+ Â Â Â Â Â Â // doesn't make sense since it greatly increases the complexity and<br>
+ Â Â Â Â Â Â // would result in an R+R+R addressing mode which no backend<br>
+ Â Â Â Â Â Â // directly supports and would need to be broken into several<br>
+ Â Â Â Â Â Â // simpler instructions anyway.<br>
+ Â Â Â Â Â Â return nullptr;<br>
+ Â Â Â Â Â }<br>
+ Â Â Â Â }<br>
+ Â Â Â }<br>
+ Â Â }<br>
+<br>
+ Â Â GetElementPtrInst *NewGEP = dyn_cast<GetElementPtrInst>(Op1->clone());<br>
+<br>
+ Â Â if (DI == -1) {<br>
+ Â Â Â // All the GEPs feeding the PHI are identical. Clone one down into our<br>
+ Â Â Â // BB so that it can be merged with the current GEP.<br>
+ Â Â Â GEP.getParent()->getInstList().insert(GEP.getParent()->getFirstNonPHI(),<br>
+ Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â NewGEP);<br>
+ Â Â } else {<br>
+ Â Â Â // All the GEPs feeding the PHI differ at a single offset. Clone a GEP<br>
+ Â Â Â // into the current block so it can be merged, and create a new PHI to<br>
+ Â Â Â // set that index.<br>
+ Â Â Â PHINode *NewPN = Builder->CreatePHI(Op1->getOperand(DI)->getType(),<br>
+ Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â PN->getNumOperands());<br>
+ Â Â Â for (auto &I : PN->operands())<br>
+ Â Â Â Â NewPN->addIncoming(dyn_cast<GEPOperator>(I)->getOperand(DI),<br>
+ Â Â Â Â Â Â Â Â Â Â Â Â Â PN->getIncomingBlock(I));<br>
+<br>
+ Â Â Â NewGEP->setOperand(DI, NewPN);<br>
+ Â Â Â GEP.getParent()->getInstList().insert(GEP.getParent()->getFirstNonPHI(),<br>
+ Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â NewGEP);<br>
+ Â Â Â NewGEP->setOperand(DI, NewPN);<br>
+ Â Â }<br>
+<br>
+ Â Â GEP.setOperand(0, NewGEP);<br>
+ Â Â PtrOp = NewGEP;<br>
+ Â }<br>
+<br>
  // Combine Indices - If the source pointer to this getelementptr instruction<br>
  // is a getelementptr instruction, combine the indices of the two<br>
  // getelementptr instructions into a single instruction.<br>
<br>
Added: llvm/trunk/test/Transforms/InstCombine/gepphigep.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/gepphigep.ll?rev=209049&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/gepphigep.ll?rev=209049&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/Transforms/InstCombine/gepphigep.ll (added)<br>
+++ llvm/trunk/test/Transforms/InstCombine/gepphigep.ll Fri May 16 18:47:24 2014<br>
@@ -0,0 +1,56 @@<br>
+; RUN: opt -instcombine -S Â < %s | FileCheck %s<br>
+<br>
+%struct1 = type { %struct2*, i32, i32, i32 }<br>
+%struct2 = type { i32, i32 }<br>
+<br>
+define i32 @test1(%struct1* %dm, i1 %tmp4, i64 %tmp9, i64 %tmp19) {<br>
+bb:<br>
+ Â %tmp = getelementptr inbounds %struct1* %dm, i64 0, i32 0<br>
+ Â %tmp1 = load %struct2** %tmp, align 8<br>
+ Â br i1 %tmp4, label %bb1, label %bb2<br>
+<br>
+bb1:<br>
+ Â %tmp10 = getelementptr inbounds %struct2* %tmp1, i64 %tmp9<br>
+ Â %tmp11 = getelementptr inbounds %struct2* %tmp10, i64 0, i32 0<br>
+ Â store i32 0, i32* %tmp11, align 4<br>
+ Â br label %bb3<br>
+<br>
+bb2:<br>
+ Â %tmp20 = getelementptr inbounds %struct2* %tmp1, i64 %tmp19<br>
+ Â %tmp21 = getelementptr inbounds %struct2* %tmp20, i64 0, i32 0<br>
+ Â store i32 0, i32* %tmp21, align 4<br>
+ Â br label %bb3<br>
+<br>
+bb3:<br>
+ Â %phi = phi %struct2* [ %tmp10, %bb1 ], [ %tmp20, %bb2 ]<br>
+ Â %tmp24 = getelementptr inbounds %struct2* %phi, i64 0, i32 1<br>
+ Â %tmp25 = load i32* %tmp24, align 4<br>
+ Â ret i32 %tmp25<br>
+<br>
+; CHECK-LABEL: @test1(<br>
+; CHECK: getelementptr inbounds %struct2* %tmp1, i64 %tmp9, i32 0<br>
+; CHECK: getelementptr inbounds %struct2* %tmp1, i64 %tmp19, i32 0<br>
+; CHECK: %[[PHI:[0-9A-Za-z]+]] = phi i64 [ %tmp9, %bb1 ], [ %tmp19, %bb2 ]<br>
+; CHECK: getelementptr inbounds %struct2* %tmp1, i64 %[[PHI]], i32 1<br>
+}<br>
+<br>
+define i32 @test2(%struct1* %dm, i1 %tmp4, i64 %tmp9, i64 %tmp19) {<br>
+bb:<br>
+ Â %tmp = getelementptr inbounds %struct1* %dm, i64 0, i32 0<br>
+ Â %tmp1 = load %struct2** %tmp, align 8<br>
+ Â %tmp10 = getelementptr inbounds %struct2* %tmp1, i64 %tmp9<br>
+ Â %tmp11 = getelementptr inbounds %struct2* %tmp10, i64 0, i32 0<br>
+ Â store i32 0, i32* %tmp11, align 4<br>
+ Â %tmp20 = getelementptr inbounds %struct2* %tmp1, i64 %tmp19<br>
+ Â %tmp21 = getelementptr inbounds %struct2* %tmp20, i64 0, i32 0<br>
+ Â store i32 0, i32* %tmp21, align 4<br>
+ Â %tmp24 = getelementptr inbounds %struct2* %tmp10, i64 0, i32 1<br>
+ Â %tmp25 = load i32* %tmp24, align 4<br>
+ Â ret i32 %tmp25<br>
+<br>
+; CHECK-LABEL: @test2(<br>
+; CHECK: getelementptr inbounds %struct2* %tmp1, i64 %tmp9, i32 0<br>
+; CHECK: getelementptr inbounds %struct2* %tmp1, i64 %tmp19, i32 0<br>
+; CHECK: getelementptr inbounds %struct2* %tmp1, i64 %tmp9, i32 1<br>
+}<br>
+<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div>