Index: lib/Target/X86/X86ISelDAGToDAG.cpp =================================================================== --- lib/Target/X86/X86ISelDAGToDAG.cpp +++ lib/Target/X86/X86ISelDAGToDAG.cpp @@ -190,6 +190,7 @@ private: void Select(SDNode *N) override; + bool pruneForLEAExtraction(SDNode *N); bool foldOffsetIntoAddress(uint64_t Offset, X86ISelAddressMode &AM); bool matchLoadInAddress(LoadSDNode *N, X86ISelAddressMode &AM); bool matchWrapper(SDValue N, X86ISelAddressMode &AM); @@ -699,6 +700,47 @@ return false; } +// This is last stage before instruction selection, all the +// legalization and combining has been performed and no more +// target independent/specific DAG transformation will be done +// now ,look for pattern which could be transformed to facilitate +// addressing mode based LEA selection. +bool X86DAGToDAGISel::pruneForLEAExtraction(SDNode *N) { + SDLoc DL(N); + EVT VT = N->getValueType(0); + unsigned Opcode = N->getOpcode(); + if (Opcode == ISD::SHL) { + SDNode *Shift = N->getOperand(1).getNode(); + if (!Shift->hasOneUse()) + return false; + if (!isa(Shift) || + (cast(Shift)->getZExtValue() > 8)) + return false; + SDNode *User = *(N->use_begin()); + if (User->getOpcode() == ISD::SUB) { + if (User->getOperand(1).getNode() == N) { + SDValue OpsSUB[] = {CurDAG->getConstant(0, DL, VT), N->getOperand(0)}; + SDValue NewSub = CurDAG->getNode(ISD::SUB, DL, VT, OpsSUB); + SDValue OpsShift[] = {NewSub, N->getOperand(1)}; + SDValue NewShift = CurDAG->getNode(ISD::SHL, DL, VT, OpsShift); + SDValue OpsAdd[] = {User->getOperand(0), NewShift}; + SDValue NewAdd = CurDAG->getNode(ISD::ADD, DL, VT, OpsAdd); + CurDAG->ReplaceAllUsesOfValueWith(SDValue(User, 0), NewAdd); + } else { + SDValue OpsSUB[] = {CurDAG->getConstant(0, DL, VT), + User->getOperand(1)}; + SDValue NewSub = CurDAG->getNode(ISD::SUB, DL, VT, OpsSUB); + SDValue OpsAdd[] = {SDValue(N, 0), NewSub}; + SDValue NewAdd = CurDAG->getNode(ISD::ADD, DL, VT, OpsAdd); + CurDAG->ReplaceAllUsesOfValueWith(SDValue(User, 0), NewAdd); + } + } + return true; + } + return false; +} + + void X86DAGToDAGISel::PreprocessISelDAG() { // OptFor[Min]Size are used in pattern predicates that isel is matching. OptForSize = MF->getFunction().optForSize(); @@ -721,6 +763,9 @@ continue; } + if (OptForSize && pruneForLEAExtraction(N)) + continue; + if (OptLevel != CodeGenOpt::None && // Only do this when the target can fold the load into the call or // jmp. Index: test/CodeGen/X86/lea-opt.ll =================================================================== --- test/CodeGen/X86/lea-opt.ll +++ test/CodeGen/X86/lea-opt.ll @@ -307,3 +307,65 @@ sw.epilog: ; preds = %sw.bb.2, %sw.bb.1, %entry ret void } + +; Function Attrs: norecurse nounwind optsize readnone uwtable +define dso_local i32 @foo1(i32 %x, i32 %y) local_unnamed_addr #0 { +; CHECK-LABEL: foo1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: # kill: def $esi killed $esi def $rsi +; CHECK-NEXT: # kill: def $edi killed $edi def $rdi +; CHECK-NEXT: negl %esi +; CHECK-NEXT: leal (%rdi,%rsi,2), %eax +; CHECK-NEXT: retq +entry: + %mul = mul nsw i32 %y, -2 + %add = add nsw i32 %mul, %x + ret i32 %add +} + +; Function Attrs: norecurse nounwind optsize readnone uwtable +define dso_local i32 @foo2(i32 %x, i32 %y) local_unnamed_addr #0 { +; CHECK-LABEL: foo2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: # kill: def $esi killed $esi def $rsi +; CHECK-NEXT: leal (%rsi,%rsi,2), %eax +; CHECK-NEXT: subl %eax, %edi +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: retq +entry: + %mul = mul nsw i32 %y, -3 + %add = add nsw i32 %mul, %x + ret i32 %add +} + +; Function Attrs: norecurse nounwind optsize readnone uwtable +define dso_local i32 @foo3(i32 %x, i32 %y) local_unnamed_addr #0 { +; CHECK-LABEL: foo3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: # kill: def $esi killed $esi def $rsi +; CHECK-NEXT: # kill: def $edi killed $edi def $rdi +; CHECK-NEXT: negl %esi +; CHECK-NEXT: leal (%rdi,%rsi,4), %eax +; CHECK-NEXT: retq +entry: + %mul = mul nsw i32 %y, -4 + %add = add nsw i32 %mul, %x + ret i32 %add +} + +; Function Attrs: norecurse nounwind optsize readnone uwtable +define dso_local i32 @foo4(i32 %x, i32 %y) local_unnamed_addr #0 { +; CHECK-LABEL: foo4: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: # kill: def $esi killed $esi def $rsi +; CHECK-NEXT: # kill: def $edi killed $edi def $rdi +; CHECK-NEXT: negl %edi +; CHECK-NEXT: leal (%rdi,%rsi,4), %eax +; CHECK-NEXT: retq +entry: + %mul = shl nsw i32 %y, 2 + %sub = sub nsw i32 %mul, %x + ret i32 %sub +} + +attributes #0 = { norecurse nounwind optsize readnone uwtable}