Added custom lowering for load->dec->store sequence in x86 when the EFLAGS registers is used

by later instructions.

Only done for DEC64m right now.

Fixes <rdar://problem/6172640>


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@144705 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Pete Cooper 2011-11-15 21:57:53 +00:00
parent 5c984e451d
commit 2d49689793
4 changed files with 95 additions and 2 deletions

View File

@ -948,6 +948,11 @@ SUnit *ScheduleDAGRRList::CopyAndMoveSuccessors(SUnit *SU) {
if (!TII->unfoldMemoryOperand(*DAG, N, NewNodes))
return NULL;
// unfolding an x86 DEC64m operation results in store, dec, load which
// can't be handled here so quit
if (NewNodes.size() == 3)
return NULL;
DEBUG(dbgs() << "Unfolding SU #" << SU->NodeNum << "\n");
assert(NewNodes.size() == 2 && "Expected a load folding node!");

View File

@ -2216,6 +2216,63 @@ SDNode *X86DAGToDAGISel::Select(SDNode *Node) {
}
break;
}
case ISD::STORE: {
StoreSDNode *StoreNode = cast<StoreSDNode>(Node);
SDValue Chain = StoreNode->getOperand(0);
SDValue StoredVal = StoreNode->getOperand(1);
SDValue Address = StoreNode->getOperand(2);
SDValue Undef = StoreNode->getOperand(3);
if (StoreNode->getMemOperand()->getSize() != 8 ||
Undef->getOpcode() != ISD::UNDEF ||
Chain->getOpcode() != ISD::LOAD ||
StoredVal->getOpcode() != X86ISD::DEC ||
StoredVal.getResNo() != 0 ||
StoredVal->getOperand(0).getNode() != Chain.getNode())
break;
//OPC_CheckPredicate, 1, // Predicate_nontemporalstore
if (StoreNode->isNonTemporal())
break;
LoadSDNode *LoadNode = cast<LoadSDNode>(Chain.getNode());
if (LoadNode->getOperand(1) != Address ||
LoadNode->getOperand(2) != Undef)
break;
if (!ISD::isNormalLoad(LoadNode))
break;
if (!ISD::isNormalStore(StoreNode))
break;
// check load chain has only one use (from the store)
if (!Chain.hasOneUse())
break;
// Merge the input chains if they are not intra-pattern references.
SDValue InputChain = LoadNode->getOperand(0);
SDValue Base, Scale, Index, Disp, Segment;
if (!SelectAddr(LoadNode, LoadNode->getBasePtr(),
Base, Scale, Index, Disp, Segment))
break;
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(2);
MemOp[0] = StoreNode->getMemOperand();
MemOp[1] = LoadNode->getMemOperand();
const SDValue Ops[] = { Base, Scale, Index, Disp, Segment, InputChain };
MachineSDNode *Result = CurDAG->getMachineNode(X86::DEC64m,
Node->getDebugLoc(),
MVT::i32, MVT::Other, Ops,
array_lengthof(Ops));
Result->setMemRefs(MemOp, MemOp + 2);
ReplaceUses(SDValue(StoreNode, 0), SDValue(Result, 1));
ReplaceUses(SDValue(StoredVal.getNode(), 1), SDValue(Result, 0));
return Result;
}
}
SDNode *ResNode = SelectCode(Node);

View File

@ -8263,8 +8263,10 @@ SDValue X86TargetLowering::EmitTest(SDValue Op, unsigned X86CC,
// climbing the DAG back to the root, and it doesn't seem to be worth the
// effort.
for (SDNode::use_iterator UI = Op.getNode()->use_begin(),
UE = Op.getNode()->use_end(); UI != UE; ++UI)
if (UI->getOpcode() != ISD::CopyToReg && UI->getOpcode() != ISD::SETCC)
UE = Op.getNode()->use_end(); UI != UE; ++UI)
if (UI->getOpcode() != ISD::CopyToReg &&
UI->getOpcode() != ISD::SETCC &&
UI->getOpcode() != ISD::STORE)
goto default_case;
if (ConstantSDNode *C =

View File

@ -0,0 +1,29 @@
; RUN: llc < %s -march=x86-64 | FileCheck %s
%struct.obj = type { i64 }
define void @_Z7releaseP3obj(%struct.obj* nocapture %o) nounwind uwtable ssp {
entry:
; CHECK: decq (%rdi)
; CHECK-NEXT: je
%refcnt = getelementptr inbounds %struct.obj* %o, i64 0, i32 0
%0 = load i64* %refcnt, align 8, !tbaa !0
%dec = add i64 %0, -1
store i64 %dec, i64* %refcnt, align 8, !tbaa !0
%tobool = icmp eq i64 %dec, 0
br i1 %tobool, label %if.end, label %return
if.end: ; preds = %entry
%1 = bitcast %struct.obj* %o to i8*
tail call void @free(i8* %1)
br label %return
return: ; preds = %entry, %if.end
ret void
}
declare void @free(i8* nocapture) nounwind
!0 = metadata !{metadata !"long", metadata !1}
!1 = metadata !{metadata !"omnipotent char", metadata !2}
!2 = metadata !{metadata !"Simple C/C++ TBAA", null}