From 8b9ce486ec64e5ddd63202c4616f795bfff59ee1 Mon Sep 17 00:00:00 2001 From: Slava Shakin Date: Fri, 12 Jan 2007 12:50:35 +0600 Subject: [PATCH] [drlvm][jit]Improved constraints handling --- .../src/codegenerator/ia32/Ia32Constraint.cpp | 2 +- .../codegenerator/ia32/Ia32ConstraintsResolver.cpp | 142 ++++++++++++++++++-- 2 files changed, 129 insertions(+), 15 deletions(-) diff --git a/vm/jitrino/src/codegenerator/ia32/Ia32Constraint.cpp b/vm/jitrino/src/codegenerator/ia32/Ia32Constraint.cpp index 567a199..3b9192c 100644 --- a/vm/jitrino/src/codegenerator/ia32/Ia32Constraint.cpp +++ b/vm/jitrino/src/codegenerator/ia32/Ia32Constraint.cpp @@ -114,7 +114,7 @@ Constraint Constraint::getAliasConstrain uint32 newKind=kind, newMask=0; uint32 newRegKind=newKind & OpndKind_Reg; - if (newRegKind==OpndKind_GPReg){ + if (newRegKind == OpndKind_GPReg || ( (newRegKind & OpndKind_GPReg) && sz <= OpndSize_16) ){ #ifndef _EM64T_ if (sz==OpndSize_8 && (s==OpndSize_16 || s==OpndSize_32)) newMask=((mask>>4)|mask)&0xf; diff --git a/vm/jitrino/src/codegenerator/ia32/Ia32ConstraintsResolver.cpp b/vm/jitrino/src/codegenerator/ia32/Ia32ConstraintsResolver.cpp index 17dedf2..3921fa2 100644 --- a/vm/jitrino/src/codegenerator/ia32/Ia32ConstraintsResolver.cpp +++ b/vm/jitrino/src/codegenerator/ia32/Ia32ConstraintsResolver.cpp @@ -86,15 +86,49 @@ namespace Ia32{ * */ +static const char* help = +" The 'constraints' action accepts 3 sets of 3 parameters which \n" +" define profile-guided operand splitting for operand\n" +" uses, defs, and crossing call sites if these factors make\n" +" operand constraints worse (permitting less registers).\n" +" Each parameter defines a threshold enabling the splitting.\n" +" The threshold is applied to basic block execution count divided \n" +" by method entry execution count.\n" +" Thus, the threshold being 0 means never, and being 1000000000 means always.\n" +" Parameters:\n" +" callSplitThresholdForNoRegs=\n" +" Applied if crossing a call site narrows an operand constraint to NO regs.\n" +" Default value is 'always'.\n" +" callSplitThresholdFor1Reg=\n" +" Applied if crossing a call site narrows an operand constraint to <=1 reg.\n" +" Default value is 1 (very cold code).\n" +" callSplitThresholdFor4Regs=\n" +" Applied if crossing a call site narrows an operand constraint to <=4 regs.\n" +" Default value is 4 (very cold code).\n" +" defSplitThresholdForNoRegs=\n" +" Default value is 0 ('never').\n" +" defSplitThresholdFor1Reg=\n" +" Default value is 0 ('never').\n" +" defSplitThresholdFor4Regs=\n" +" Default value is 0 ('never').\n" +" useSplitThresholdForNoRegs=\n" +" Default value is 0 ('never').\n" +" useSplitThresholdFor1Reg=\n" +" Default value is 0 ('never').\n" +" useSplitThresholdFor4Regs=\n" +" Default value is 0 ('never').\n" +; + class ConstraintsResolver : public SessionAction { /** runImpl is required override, calls ConstraintsResolverImpl.runImpl */ void runImpl(); /** This transformer requires up-to-date liveness info */ uint32 getNeedInfo()const{ return NeedInfo_LivenessInfo; } uint32 getSideEffects()const{ return 0; } + }; -static ActionFactory _constraints("constraints"); +static ActionFactory _constraints("constraints", help); //======================================================================================== // class ConstraintsResolverImpl @@ -184,7 +218,8 @@ public: liveAtDispatchBlockEntry(memoryManager,0), needsOriginalOpnd(memoryManager,0), hoveringOpnds(memoryManager,0), - opndReplaceWorkset(memoryManager,0) + opndReplaceWorkset(memoryManager,0), + opndUsage(memoryManager,0) { } @@ -215,6 +250,11 @@ private: /** returns constraint describing safe locations for operands live at dispatch node entries */ Constraint getDispatchEntryConstraint(Opnd * opnd); + static bool constraintIsWorse(Constraint cnew, Constraint cold, unsigned normedBBExecCount, + unsigned splitThresholdForNoRegs, unsigned splitThresholdFor1Reg, unsigned splitThresholdFor4Regs + ); + + /** Reference to IRManager */ IRManager& irManager; @@ -249,6 +289,23 @@ private: * Reset for each basic blocks (all replacements are local within basic blocks) */ StlVector opndReplaceWorkset; + + + StlVector opndUsage; + + unsigned callSplitThresholdForNoRegs; + unsigned callSplitThresholdFor1Reg; + unsigned callSplitThresholdFor4Regs; + + unsigned defSplitThresholdForNoRegs; + unsigned defSplitThresholdFor1Reg; + unsigned defSplitThresholdFor4Regs; + + unsigned useSplitThresholdForNoRegs; + unsigned useSplitThresholdFor1Reg; + unsigned useSplitThresholdFor4Regs; + + friend class ConstraintsResolver; }; @@ -285,6 +342,11 @@ void ConstraintsResolverImpl::run() for (uint32 i=0; igetMnemonic()==Mnemonic_CALL) hoveringOpnds.copyFrom(liveOpnds); + double dblExecCount = 1000. * inst->getBasicBlock()->getExecCount() / irManager.getFlowGraph()->getEntryNode()->getExecCount(); + if (dblExecCount > 100000000.) + dblExecCount = 100000000.; + unsigned execCount = (unsigned)dblExecCount; + // first handle all defs {Inst::Opnds opnds(inst, Inst::OpndRole_AllDefs); for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){ @@ -390,8 +475,10 @@ void ConstraintsResolverImpl::resolveCon // currentOpnd is either the current replacement or the original operand Opnd * currentOpnd=opndReplaceWorkset[originalOpnd->getId()]; - if (currentOpnd==NULL) + if (currentOpnd==NULL){ currentOpnd=originalOpnd; + opndUsage[originalOpnd->getId()]+=execCount; + } // get what is already collected Constraint cc=currentOpnd->getConstraint(Opnd::ConstraintKind_Calculated); assert(!cc.isNull()); @@ -401,7 +488,7 @@ void ConstraintsResolverImpl::resolveCon // & the result Constraint cr=cc & ci; Opnd * opndToSet=currentOpnd; - if (!cr.isNull()){ + if (!constraintIsWorse(cr, cc, execCount, defSplitThresholdForNoRegs, defSplitThresholdFor1Reg, defSplitThresholdFor4Regs)){ // can substitute currentReplacementOpnd into this position currentOpnd->setCalculatedConstraint(cr); }else{ @@ -421,6 +508,7 @@ void ConstraintsResolverImpl::resolveCon Inst * copySequence=irManager.newCopyPseudoInst(Mnemonic_MOV, opndToSet, originalOpnd); // split above the instruction copySequence->insertBefore(inst); + opndUsage[originalOpnd->getId()]+=execCount; } } } @@ -446,8 +534,10 @@ void ConstraintsResolverImpl::resolveCon assert(!needsOriginalOpnd.getBit(originalOpnd->getId())||opndReplaceWorkset[originalOpnd->getId()]==NULL); // currentOpnd is either the current replacement or the original operand Opnd * currentOpnd=opndReplaceWorkset[originalOpnd->getId()]; - if (currentOpnd==NULL) + if (currentOpnd==NULL){ currentOpnd=originalOpnd; + opndUsage[originalOpnd->getId()]+=execCount; + } Opnd * opndToSet=NULL; // was live and is not redefined by this inst if (liveOpnds.getBit(originalOpnd->getId())){ @@ -460,7 +550,7 @@ void ConstraintsResolverImpl::resolveCon // & the result Constraint cr=cc & ci; opndToSet=currentOpnd; - if ((cr.getMask()!=0 || cc.getMask()==0) && !cr.isNull()){ + if (!constraintIsWorse(cr, cc, execCount, callSplitThresholdForNoRegs, callSplitThresholdFor1Reg, callSplitThresholdFor4Regs)){ // can substitute currentReplacementOpnd into this position opndToSet->setCalculatedConstraint(cr); }else{ @@ -468,7 +558,7 @@ void ConstraintsResolverImpl::resolveCon // Try to use originalOpnd over this instruction and for the instructions above Constraint co=originalOpnd->getConstraint(Opnd::ConstraintKind_Calculated); Constraint cr=co & ci; - if ((cr.getMask()!=0 || co.getMask()==0)&& !cr.isNull()){ + if (!constraintIsWorse(cr, cc, execCount, callSplitThresholdForNoRegs, callSplitThresholdFor1Reg, callSplitThresholdFor4Regs)){ opndToSet=originalOpnd; opndToSet->setCalculatedConstraint(cr); }else{ @@ -483,7 +573,6 @@ void ConstraintsResolverImpl::resolveCon // an operand different to the current replacement // is required to be over this call site, append splitting below the call site // this is like restoring from a call-safe location under a call - assert(currentOpnd->getType() == opndToSet->getType()); Inst * copySequence=irManager.newCopyPseudoInst(Mnemonic_MOV, currentOpnd, opndToSet); copySequence->insertAfter(inst); } @@ -495,6 +584,7 @@ void ConstraintsResolverImpl::resolveCon assert(currentOpnd==originalOpnd); Inst * copySequence=irManager.newCopyPseudoInst(Mnemonic_MOV, opndToSet, originalOpnd); copySequence->insertBefore(inst); + opndUsage[originalOpnd->getId()]+=execCount; } } } @@ -510,8 +600,10 @@ void ConstraintsResolverImpl::resolveCon assert(!needsOriginalOpnd.getBit(originalOpnd->getId())||opndReplaceWorkset[originalOpnd->getId()]==NULL); // currentOpnd is either the current replacement or the original operand Opnd * currentOpnd=opndReplaceWorkset[originalOpnd->getId()]; - if (currentOpnd==NULL) + if (currentOpnd==NULL){ currentOpnd=originalOpnd; + opndUsage[originalOpnd->getId()]+=execCount; + } // get what is already collected Constraint cc=currentOpnd->getConstraint(Opnd::ConstraintKind_Calculated); assert(!cc.isNull()); @@ -522,7 +614,7 @@ void ConstraintsResolverImpl::resolveCon Opnd * opndToSet=currentOpnd; - if (!cr.isNull()){ + if (!constraintIsWorse(cr, cc, execCount, useSplitThresholdForNoRegs, useSplitThresholdFor1Reg, useSplitThresholdFor4Regs)){ // can substitute currentReplacementOpnd into this position currentOpnd->setCalculatedConstraint(cr); }else{ @@ -556,6 +648,7 @@ void ConstraintsResolverImpl::resolveCon // if we come to bb entry with some replacement for an operand and the operand is live at the entry // insert copying from the original operand to the replacement operand + uint32 execCount = (uint32)bb->getExecCount(); BitSet * ls = irManager.getLiveAtEntry(bb); BitSet::IterB ib(*ls); for (int i = ib.getNext(); i != -1; i = ib.getNext()){ @@ -565,9 +658,9 @@ void ConstraintsResolverImpl::resolveCon if (currentOpnd!=NULL){ if (currentOpnd!=originalOpnd){ // assert(irManager.getLiveAtEntry(bb)->isLive(originalOpnd)); - assert(currentOpnd->getType() == originalOpnd->getType()); Inst * copySequence=irManager.newCopyPseudoInst(Mnemonic_MOV, currentOpnd, originalOpnd); bb->prependInst(copySequence); + opndUsage[originalOpnd->getId()]+=execCount; } opndReplaceWorkset[originalOpnd->getId()]=NULL; } @@ -587,13 +680,34 @@ void ConstraintsResolverImpl::resolveCon void ConstraintsResolver::runImpl() { // call the private implementation of the algorithm - ConstraintsResolverImpl(*irManager).run(); + ConstraintsResolverImpl impl(*irManager); + + impl.callSplitThresholdForNoRegs = (unsigned)-1; // always + getArg("callSplitThresholdForNoRegs", impl.callSplitThresholdForNoRegs); + impl.callSplitThresholdFor1Reg = 1; // for very cold code + getArg("callSplitThresholdFor1Reg", impl.callSplitThresholdFor1Reg); + impl.callSplitThresholdFor4Regs = 1; // for very cold code + getArg("callSplitThresholdFor4Regs", impl.callSplitThresholdFor4Regs); + + impl.defSplitThresholdForNoRegs = 0; // never + getArg("defSplitThresholdForNoRegs", impl.defSplitThresholdForNoRegs); + impl.defSplitThresholdFor1Reg = 0; // never + getArg("defSplitThresholdFor1Reg", impl.defSplitThresholdFor1Reg); + impl.defSplitThresholdFor4Regs = 0; // never + getArg("defSplitThresholdFor4Regs", impl.defSplitThresholdFor4Regs); + + impl.useSplitThresholdForNoRegs = 0; // never + getArg("useSplitThresholdForNoRegs", impl.useSplitThresholdForNoRegs); + impl.useSplitThresholdFor1Reg = 0; // never + getArg("useSplitThresholdFor1Reg", impl.useSplitThresholdFor1Reg); + impl.useSplitThresholdFor4Regs = 0; // never + getArg("useSplitThresholdFor4Regs", impl.useSplitThresholdFor4Regs); + + impl.run(); } //_________________________________________________________________________________________________ - - }}; //namespace Ia32 -- 1.4.4