Index: trunk/vm/jitrino/src/codegenerator/ia32/Ia32CallingConvention.h =================================================================== --- trunk/vm/jitrino/src/codegenerator/ia32/Ia32CallingConvention.h (revision 594020) +++ trunk/vm/jitrino/src/codegenerator/ia32/Ia32CallingConvention.h (working copy) @@ -111,9 +111,9 @@ virtual bool pushLastToFirst()const =0; /** - * Defines alignment of all arguments passed on the memmory stack plus return pointer. + * Defines stack pointer alignment on method enter. */ - virtual uint32 getAlignment()const { return 0; } + virtual uint32 getStackAlignment()const { return 0; } /** * Maps a string representation of CallingConvention to the @@ -162,7 +162,7 @@ public: virtual ~DRLCallingConventionIA32() {} virtual bool pushLastToFirst()const{ return false; } - virtual uint32 getAlignment()const { return STACK_ALIGNMENT; } + virtual uint32 getStackAlignment()const { return STACK_ALIGNMENT; } }; /** @@ -172,7 +172,7 @@ { public: virtual ~DRLCallingConventionEM64T() {} - virtual uint32 getAlignment()const { return STACK_ALIGN16; } + virtual uint32 getStackAlignment()const { return STACK_ALIGNMENT; } }; //======================================================================================== Index: trunk/vm/jitrino/src/codegenerator/ia32/Ia32i586InstsExpansion.cpp =================================================================== --- trunk/vm/jitrino/src/codegenerator/ia32/Ia32i586InstsExpansion.cpp (revision 594020) +++ trunk/vm/jitrino/src/codegenerator/ia32/Ia32i586InstsExpansion.cpp (working copy) @@ -191,7 +191,9 @@ //create memory operand for the XMM register if it doesn't exist if (!(*xmmMemOpsPtr)[regNum] || (*xmmMemOpsPtr)[regNum]->getSize() != op1->getSize()) { - (*xmmMemOpsPtr)[regNum] = irManager->newMemOpnd(fp0->getType(), MemOpndKind_StackAutoLayout, irManager->getRegOpnd(STACK_REG), 0); + Opnd* opnd = irManager->newMemOpnd(fp0->getType(), MemOpndKind_StackAutoLayout, irManager->getRegOpnd(STACK_REG), 0); + opnd->setMemOpndAlignment(Opnd::MemOpndAlignment_16); + (*xmmMemOpsPtr)[regNum] = opnd; } //load zero Index: trunk/vm/jitrino/src/codegenerator/ia32/Ia32Inst.cpp =================================================================== --- trunk/vm/jitrino/src/codegenerator/ia32/Ia32Inst.cpp (revision 594020) +++ trunk/vm/jitrino/src/codegenerator/ia32/Ia32Inst.cpp (working copy) @@ -826,9 +826,10 @@ if (argKind == CallingConvention::ArgKind_InArg) { // Compute stack alignment. unsigned stackOnEnterSize = stackOpndSize + sizeof(POINTER_SIZE_INT); - unsigned alignment = callingConvention->getAlignment(); + unsigned alignment = (callingConvention->getStackAlignment() == STACK_ALIGN_HALF16) + ? STACK_ALIGN16 : callingConvention->getStackAlignment(); - if (alignment != 0 && stackOnEnterSize & (alignment - 1)) { + if (alignment != 0 && (stackOnEnterSize & (alignment - 1))) { stackAlignmentSize = alignment - (stackOnEnterSize & (alignment - 1)); } } Index: trunk/vm/jitrino/src/codegenerator/ia32/Ia32Inst.h =================================================================== --- trunk/vm/jitrino/src/codegenerator/ia32/Ia32Inst.h (revision 594020) +++ trunk/vm/jitrino/src/codegenerator/ia32/Ia32Inst.h (working copy) @@ -105,6 +105,13 @@ ConstraintKind_Current }; + enum MemOpndAlignment{ + MemOpndAlignment_Any = 0, + MemOpndAlignment_4 = 4, + MemOpndAlignment_8 = 8, + MemOpndAlignment_16 = 16 + }; + //------------------------------------------------------------------------- /** class RuntimeInfo contains information allowing CG to determine operand value from the current runtime information Initially added to support AOT compiler the class is used to annotate operands with runtime info @@ -231,6 +238,24 @@ void setMemOpndKind(MemOpndKind k){ memOpndKind=k; } + /** + * Returns alignment for the operand. It makes sense to query + * alignment for memory operands that have stack auto layout kind only. + * For all other operands MemOpndAlignment_Any will be returned. + */ + MemOpndAlignment getMemOpndAlignment() { + return memOpndAlignment; + } + + /** + * Sets desirable memory operand alignment. + */ + void setMemOpndAlignment(MemOpndAlignment alignment) { + // It makes sense to specify alignment for memory operands + // which have stack auto layout kind only. + memOpndAlignment = alignment; + } + /** * Returns true if the operand IS assigned to a location defined by constraint. * The constraint can be either explicitly created or implicitly created from RegName values. @@ -347,16 +372,18 @@ //------------------------------------------------------------------------- Opnd(uint32 _id, Type * t, Constraint c) - :id(_id), firstId(_id), type(t), memOpndKind(MemOpndKind_Null), + :id(_id), firstId(_id), type(t), defScope(DefScope_Null), definingInst(NULL), refCount(0), - segReg(RegName_Null), immValue(0), runtimeInfo(NULL) - { constraints[ConstraintKind_Initial]=constraints[ConstraintKind_Calculated]=c; } + segReg(RegName_Null), memOpndKind(MemOpndKind_Null), + memOpndAlignment(MemOpndAlignment_Any), + immValue(0), runtimeInfo(NULL) { + constraints[ConstraintKind_Initial]=constraints[ConstraintKind_Calculated]=c; + } //------------------------------------------------------------------------- uint32 id; uint32 firstId; Type * type; - MemOpndKind memOpndKind; Constraint constraints[ConstraintKind_Current]; DefScope defScope; @@ -364,6 +391,10 @@ uint32 refCount; RegName segReg; + MemOpndKind memOpndKind; + // Defines alignment for memory oprands that have stack auto layout kind. + MemOpndAlignment memOpndAlignment; + union{ RegName regName; struct{ Index: trunk/vm/jitrino/src/codegenerator/ia32/Ia32IRManager.cpp =================================================================== --- trunk/vm/jitrino/src/codegenerator/ia32/Ia32IRManager.cpp (revision 594020) +++ trunk/vm/jitrino/src/codegenerator/ia32/Ia32IRManager.cpp (working copy) @@ -1147,21 +1147,26 @@ (targetKind==OpndKind_XMMReg||targetKind==OpndKind_Mem) && (sourceKind==OpndKind_XMMReg||sourceKind==OpndKind_Mem) ){ + targetOpnd->setMemOpndAlignment(Opnd::MemOpndAlignment_16); + sourceOpnd->setMemOpndAlignment(Opnd::MemOpndAlignment_16); if (sourceByteSize==4){ return newInst(Mnemonic_MOVSS,targetOpnd, sourceOpnd); }else if (sourceByteSize==8){ return newInst(Mnemonic_MOVSD,targetOpnd, sourceOpnd); } }else if (targetKind==OpndKind_FPReg && sourceKind==OpndKind_Mem){ + sourceOpnd->setMemOpndAlignment(Opnd::MemOpndAlignment_16); return newInst(Mnemonic_FLD, targetOpnd, sourceOpnd); }else if (targetKind==OpndKind_Mem && sourceKind==OpndKind_FPReg){ + targetOpnd->setMemOpndAlignment(Opnd::MemOpndAlignment_16); return newInst(Mnemonic_FSTP, targetOpnd, sourceOpnd); }else if ( (targetKind==OpndKind_FPReg && sourceKind==OpndKind_XMMReg)|| (targetKind==OpndKind_XMMReg && sourceKind==OpndKind_FPReg) ){ Inst * instList=NULL; - Opnd * tmp = newMemOpnd(targetOpnd->getType(), MemOpndKind_StackAutoLayout, getRegOpnd(STACK_REG), 0); + Opnd * tmp = newMemOpnd(targetOpnd->getType(), MemOpndKind_StackAutoLayout, getRegOpnd(STACK_REG), 0); + tmp->setMemOpndAlignment(Opnd::MemOpndAlignment_16); appendToInstList(instList, newCopySequence(tmp, sourceOpnd, regUsageMask)); appendToInstList(instList, newCopySequence(targetOpnd, tmp, regUsageMask)); return instList; Index: trunk/vm/jitrino/src/codegenerator/ia32/Ia32RegAlloc3.cpp =================================================================== --- trunk/vm/jitrino/src/codegenerator/ia32/Ia32RegAlloc3.cpp (revision 594020) +++ trunk/vm/jitrino/src/codegenerator/ia32/Ia32RegAlloc3.cpp (working copy) @@ -1312,6 +1312,10 @@ DBGOUT(" spilling " << *opndx.opnd << endl;) opnd->setCalculatedConstraint(initial); opnd->assignMemLocation(MemOpndKind_StackAutoLayout, irManager->getRegOpnd(STACK_REG), 0); + if (initial.getKind() == OpndKind_FPReg + || initial.getKind() == OpndKind_XMMReg) { + opnd->setMemOpndAlignment(Opnd::MemOpndAlignment_16); + } int inserted = 0; Index: trunk/vm/jitrino/src/codegenerator/ia32/Ia32StackLayout.cpp =================================================================== --- trunk/vm/jitrino/src/codegenerator/ia32/Ia32StackLayout.cpp (revision 594020) +++ trunk/vm/jitrino/src/codegenerator/ia32/Ia32StackLayout.cpp (working copy) @@ -137,12 +137,19 @@ StackInfo * stackInfo; MemoryManager memoryManager; - + + static const int alignmentSequenceSize = 4; + static Opnd::MemOpndAlignment const alignmentSequence[4]; }; static ActionFactory _stack("stack"); +Opnd::MemOpndAlignment const StackLayouter::alignmentSequence[] = + { Opnd::MemOpndAlignment_16, Opnd::MemOpndAlignment_8, + Opnd::MemOpndAlignment_4, Opnd::MemOpndAlignment_Any + }; + StackLayouter::StackLayouter () :localBase(0), localEnd(0), @@ -228,30 +235,28 @@ void StackLayouter::runImpl() { - IRManager & irm=getIRManager(); + stackInfo = new(irManager->getMemoryManager()) StackInfo(irManager->getMemoryManager()); + irManager->setInfo(STACK_INFO_KEY, stackInfo); - stackInfo = new(irm.getMemoryManager()) StackInfo(irm.getMemoryManager()); - irm.setInfo(STACK_INFO_KEY, stackInfo); - - irm.calculateOpndStatistics(); + irManager->calculateOpndStatistics(); #ifdef _DEBUG checkUnassignedOpnds(); #endif - irm.calculateTotalRegUsage(OpndKind_GPReg); + irManager->calculateTotalRegUsage(OpndKind_GPReg); createProlog(); createEpilog(); - uint32 maxStackDepth = irm.calculateStackDepth(); - insertSOECheck(irm, maxStackDepth); - irm.layoutAliasOpnds(); + uint32 maxStackDepth = irManager->calculateStackDepth(); + insertSOECheck(*irManager, maxStackDepth); + irManager->layoutAliasOpnds(); //fill StackInfo object stackInfo->frameSize = getFrameSize(); - stackInfo->icalleeMask = irm.getCallingConvention()->getCalleeSavedRegs(OpndKind_GPReg).getMask() & irm.getTotalRegUsage(OpndKind_GPReg); + stackInfo->icalleeMask = irManager->getCallingConvention()->getCalleeSavedRegs(OpndKind_GPReg).getMask() & irManager->getTotalRegUsage(OpndKind_GPReg); stackInfo->icalleeOffset = getIntCalleeBase(); - stackInfo->fcallee = irm.getCallingConvention()->getCalleeSavedRegs(OpndKind_FPReg).getMask(); + stackInfo->fcallee = irManager->getCallingConvention()->getCalleeSavedRegs(OpndKind_FPReg).getMask(); stackInfo->foffset = getFloatCalleeBase(); - stackInfo->acallee = 0; //VSH: TODO - get rid off appl regs irm.getCallingConvention()->getCalleeSavedRegs(OpndKind_ApplicationReg); + stackInfo->acallee = 0; //VSH: TODO - get rid off appl regs irManager->getCallingConvention()->getCalleeSavedRegs(OpndKind_ApplicationReg); stackInfo->aoffset = getApplCalleeBase(); stackInfo->localOffset = getLocalBase(); stackInfo->eipOffset = getRetEIPBase(); @@ -270,21 +275,30 @@ void StackLayouter::createProlog() { const uint32 slotSize = sizeof(POINTER_SIZE_INT); - const uint32 stackSizeAlignment = (STACK_ALIGNMENT == STACK_ALIGN_HALF16) ? STACK_ALIGN16 : STACK_ALIGNMENT; - IRManager & irm = getIRManager(); - EntryPointPseudoInst * entryPointInst = NULL; + EntryPointPseudoInst* entryPointInst = NULL; + const CallingConventionClient* cClient = NULL; + const CallingConvention* cConvention = NULL; + uint32 stackSizeAlignment = 0; int offset = 0; entryPointInst = irManager->getEntryPointInst(); assert(entryPointInst->getNode() == irManager->getFlowGraph()->getEntryNode()); + cClient = &((const EntryPointPseudoInst*)entryPointInst)->getCallingConventionClient(); + cConvention = cClient->getCallingConvention(); + // Overal size of stack frame should preserve alignment available on method enter. + stackSizeAlignment = (cConvention->getStackAlignment() == STACK_ALIGN_HALF16) + ? STACK_ALIGN16 : cConvention->getStackAlignment(); + // TODO: remove before commit + assert((stackSizeAlignment & 15) == 0); + // Create or reset displacements for stack memory operands. - for (uint32 i = 0; i < irm.getOpndCount(); i++) { - Opnd * opnd = irm.getOpnd(i); + for (uint32 i = 0; i < irManager->getOpndCount(); i++) { + Opnd * opnd = irManager->getOpnd(i); if (opnd->getRefCount() && opnd->getMemOpndKind() == MemOpndKind_StackAutoLayout) { Opnd * dispOpnd=opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); if (dispOpnd == NULL){ - dispOpnd = irm.newImmOpnd(irm.getTypeManager().getInt32Type(), 0); + dispOpnd = irManager->newImmOpnd(irManager->getTypeManager().getInt32Type(), 0); opnd->setMemOpndSubOpnd(MemOpndSubOpndKind_Displacement, dispOpnd); } dispOpnd->assignImmValue(0); @@ -300,7 +314,7 @@ // Assign displacements for input operands. if (entryPointInst) { const StlVector& stackOpndInfos = - ((const EntryPointPseudoInst*)entryPointInst)->getCallingConventionClient().getStackOpndInfos(Inst::OpndRole_Def); + cClient->getStackOpndInfos(Inst::OpndRole_Def); for (uint32 i = 0, n = (uint32)stackOpndInfos.size(); i < n; i++) { uint64 argOffset = stackOpndInfos[i].offset; @@ -312,7 +326,7 @@ inargEnd = offset; icalleeEnd = offset = 0; - uint32 calleeSavedRegs=irm.getCallingConvention()->getCalleeSavedRegs(OpndKind_GPReg).getMask(); + uint32 calleeSavedRegs = cConvention->getCalleeSavedRegs(OpndKind_GPReg).getMask(); uint32 usageRegMask = irManager->getTotalRegUsage(OpndKind_GPReg); Inst * lastPush = NULL; @@ -324,7 +338,7 @@ #endif uint32 mask = getRegMask((RegName)reg); if ((mask & calleeSavedRegs) && (usageRegMask & mask)) { - Inst * inst = irm.newInst(Mnemonic_PUSH, irm.getRegOpnd((RegName)reg)); + Inst * inst = irManager->newInst(Mnemonic_PUSH, irManager->getRegOpnd((RegName)reg)); if (!lastPush) { lastPush = inst; } @@ -333,31 +347,54 @@ } } icalleeBase = fcalleeEnd = fcalleeBase = acalleeEnd = acalleeBase = localEnd = offset; + + // Align callee save area on maximum possible value: + // - for STACK_ALIGN16 & STACK_ALIGN_HALF16 align on 16-bytes + // - for STACK_ALIGN4 align on 4-bytes + offset &= ~(stackSizeAlignment - 1); + + if (cConvention->getStackAlignment() == STACK_ALIGN_HALF16 && + (offset & ~(STACK_ALIGN16 - 1)) == 0) { + // Need to align size of callee save area on half of 16-bytes + // thus resulting stack pointer will be 16-bytes aligned. + offset -= STACK_ALIGN_HALF16; + } // Retrieve relations not earlier than all memory locations are assigned. - IRManager::AliasRelation * relations = new(irm.getMemoryManager()) IRManager::AliasRelation[irm.getOpndCount()]; - irm.getAliasRelations(relations); + IRManager::AliasRelation * relations = new(irManager->getMemoryManager()) IRManager::AliasRelation[irManager->getOpndCount()]; + irManager->getAliasRelations(relations); // Assign displacements for local variable operands. - for (uint32 i = 0; i < irm.getOpndCount(); i++) { - Opnd * opnd = irm.getOpnd(i); - if (opnd->getRefCount() == 0) - continue; - if(opnd->getMemOpndKind() == MemOpndKind_StackAutoLayout) { - Opnd * dispOpnd = opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); - if (dispOpnd->getImmValue() == 0) { - if (relations[opnd->getId()].outerOpnd == NULL) { - uint32 cb = getByteSize(opnd->getSize()); - cb=(cb + slotSize - 1) & ~(slotSize - 1); - offset -= cb; - dispOpnd->assignImmValue(offset); + for (int j = 0; j <= alignmentSequenceSize; j++) { + for (uint32 i = 0; i < irManager->getOpndCount(); i++) { + Opnd * opnd = irManager->getOpnd(i); + Opnd::MemOpndAlignment currentAlignment = alignmentSequence[j]; + if(opnd->getRefCount() != 0 + && opnd->getMemOpndKind() == MemOpndKind_StackAutoLayout + && opnd->getMemOpndAlignment() == currentAlignment) { + Opnd * dispOpnd = opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); + if (dispOpnd->getImmValue() == 0) { + if (relations[opnd->getId()].outerOpnd == NULL) { + if (currentAlignment == Opnd::MemOpndAlignment_Any) { + uint32 cb = getByteSize(opnd->getSize()); + cb = (cb + (slotSize - 1)) & ~(slotSize - 1); + offset -= cb; + } else { + // Make sure + assert((stackSizeAlignment % currentAlignment) == 0); + // It just doesn't make sense to align on less than operand size. + assert((uint32)currentAlignment >= getByteSize(opnd->getSize())); + offset -= currentAlignment; + } + dispOpnd->assignImmValue(offset); + } } } } } // Align stack pointer. Local area should preserve alignment available on function enter. - offset = offset & ~(stackSizeAlignment - 1); + offset &= ~(stackSizeAlignment - 1); // Assert local area is properly aligned. assert((offset & (STACK_ALIGNMENT - 1)) == 0); @@ -365,7 +402,7 @@ localBase = offset; if (localEnd>localBase) { - Inst* newIns = irm.newInst(Mnemonic_SUB, irm.getRegOpnd(STACK_REG), irm.newImmOpnd(irm.getTypeManager().getInt32Type(), localEnd - localBase)); + Inst* newIns = irManager->newInst(Mnemonic_SUB, irManager->getRegOpnd(STACK_REG), irManager->newImmOpnd(irManager->getTypeManager().getInt32Type(), localEnd - localBase)); newIns->insertAfter(lastPush ? lastPush : entryPointInst); } @@ -373,20 +410,19 @@ } void StackLayouter::createEpilog() -{ // Predeccessors of en and irm.isEpilog(en->pred) - IRManager & irm = getIRManager(); - uint32 calleeSavedRegs = irm.getCallingConvention()->getCalleeSavedRegs(OpndKind_GPReg).getMask(); - const Edges& inEdges = irm.getFlowGraph()->getExitNode()->getInEdges(); +{ // Predeccessors of en and irManager->isEpilog(en->pred) + uint32 calleeSavedRegs = irManager->getCallingConvention()->getCalleeSavedRegs(OpndKind_GPReg).getMask(); + const Edges& inEdges = irManager->getFlowGraph()->getExitNode()->getInEdges(); uint32 usageRegMask = irManager->getTotalRegUsage(OpndKind_GPReg); for (Edges::const_iterator ite = inEdges.begin(), ende = inEdges.end(); ite!=ende; ++ite) { Edge* edge = *ite; - if (irm.isEpilog(edge->getSourceNode())) { + if (irManager->isEpilog(edge->getSourceNode())) { Node * epilog = edge->getSourceNode(); Inst * retInst = (Inst*)epilog->getLastInst(); assert(retInst->hasKind(Inst::Kind_RetInst)); if (localEnd > localBase) { // Restore stack pointer. - Inst* newIns = irm.newInst(Mnemonic_ADD, irm.getRegOpnd(STACK_REG), irm.newImmOpnd(irm.getTypeManager().getInt32Type(), localEnd - localBase)); + Inst* newIns = irManager->newInst(Mnemonic_ADD, irManager->getRegOpnd(STACK_REG), irManager->newImmOpnd(irManager->getTypeManager().getInt32Type(), localEnd - localBase)); newIns->insertBefore(retInst); } #ifdef _EM64T_ @@ -396,7 +432,7 @@ #endif uint32 mask = getRegMask((RegName)reg); if ((mask & calleeSavedRegs) && (usageRegMask & mask)) { - Inst* newIns = irm.newInst(Mnemonic_POP, irm.getRegOpnd((RegName)reg)); + Inst* newIns = irManager->newInst(Mnemonic_POP, irManager->getRegOpnd((RegName)reg)); newIns->insertBefore(retInst); } }