harmony-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From var...@apache.org
Subject svn commit: r478172 - in /harmony/enhanced/drlvm/trunk/vm: jitrino/src/codegenerator/ia32/ port/src/encoder/ia32_em64t/
Date Wed, 22 Nov 2006 14:32:29 GMT
Author: varlax
Date: Wed Nov 22 06:32:28 2006
New Revision: 478172

URL: http://svn.apache.org/viewvc?view=rev&rev=478172
Log:
Applied HARMONY-2223 [drlvm][jit][performance]Inlined int64 arithmetic routines - speedup of 64 arithmetics.
Tested on SUSE9, observed ~5% gain on the microbenchmark.

Added:
    harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32CgUtils.cpp
    harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32CgUtils.h
Modified:
    harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32DCE.cpp
    harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32I8Lowerer.cpp
    harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32IRManager.cpp
    harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32IRManager.h
    harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp
    harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32Printer.cpp
    harmony/enhanced/drlvm/trunk/vm/port/src/encoder/ia32_em64t/enc_defs.h
    harmony/enhanced/drlvm/trunk/vm/port/src/encoder/ia32_em64t/enc_tabl.cpp
    harmony/enhanced/drlvm/trunk/vm/port/src/encoder/ia32_em64t/encoder.inl

Added: harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32CgUtils.cpp
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32CgUtils.cpp?view=auto&rev=478172
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32CgUtils.cpp (added)
+++ harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32CgUtils.cpp Wed Nov 22 06:32:28 2006
@@ -0,0 +1,362 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+ * @author Alexander Astapchuk
+ * @version $Revision$
+ */
+
+#include "Ia32CgUtils.h"
+
+namespace Jitrino {
+namespace Ia32 {
+
+bool OpndUtils::isReg(const Opnd* op, RegName what)
+{
+    if (!op->isPlacedIn(OpndKind_Reg)) {
+        return false;
+    }
+    if (what == RegName_Null) {
+        return true;
+    }
+    return op->getRegName() == what;
+}
+
+bool OpndUtils::isXmmReg(const Opnd* op, RegName what)
+{
+    if (!isReg(op)) {
+        return false;
+    }
+    const RegName regName = op->getRegName();
+    if (getRegKind(regName) != OpndKind_XMMReg) {
+        return false;
+    }
+    if (what == RegName_Null) {
+        return true; 
+    }
+    return regName == what;
+}
+
+bool OpndUtils::isImm(const Opnd* op)
+{
+    return op->isPlacedIn(OpndKind_Imm) && (op->getRuntimeInfo() == NULL);
+}
+
+bool OpndUtils::isImm(const Opnd* op, int iVal)
+{
+    return isImm(op) && (op->getImmValue() == iVal);
+}
+
+bool OpndUtils::isImm8(const Opnd* op)
+{
+    return isImm(op) && op->getSize() == OpndSize_8;
+}
+
+bool OpndUtils::isImm32(const Opnd* op)
+{
+    return isImm(op) && op->getSize() == OpndSize_32;
+}
+
+bool OpndUtils::fitsImm8(const Opnd* op)
+{
+    return isImm(op) && 
+           (CHAR_MIN <= op->getImmValue() && op->getImmValue() <= CHAR_MAX);
+}
+
+bool OpndUtils::isMem(const Opnd* op)
+{
+    return op->isPlacedIn(OpndKind_Mem);
+}
+
+bool OpndUtils::isZeroImm(const Opnd* op)
+{
+    return isImm(op, 0);
+}
+
+bool OpndUtils::isSingleDef(const Opnd* opnd)
+{
+    return isImm(opnd) || (opnd->getDefiningInst() != NULL);
+}
+
+
+const void* OpndUtils::extractAddrOfConst(const Opnd* op)
+{
+    if (op->getMemOpndKind() != MemOpndKind_ConstantArea) {
+        return NULL;
+    }
+    // Actually, it's currently only works for IA-32 - I expect 
+    // the address of constant completely in the displacement.
+    // On Intel64, the address already get loaded into a register, 
+    // so more complicated analysis needed to find the proper constant
+    Opnd* disp = op->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement);
+    if (disp == NULL) {
+        // Perhaps, it's IA-32?
+        return NULL;
+    }
+    
+    Opnd::RuntimeInfo* rtInfo = disp->getRuntimeInfo();
+    assert(rtInfo != NULL);
+    assert(rtInfo->getKind() == Opnd::RuntimeInfo::Kind_ConstantAreaItem);
+    ConstantAreaItem* item = (ConstantAreaItem*)rtInfo->getValue(0);
+    // At this point we must have the address...
+    assert(item->getValue()!= NULL);
+    return item->getValue();
+}
+
+bool OpndUtils::isConstAreaItem(const Opnd* op)
+{
+    return extractAddrOfConst(op) != NULL;
+}
+
+bool OpndUtils::isFPConst(const Opnd* op, double dVal)
+{
+    const void* addr = extractAddrOfConst(op);
+    return (addr == NULL) ? false : (dVal == *(const float*)addr);
+}
+
+bool OpndUtils::isFPConst(const Opnd* op, float fVal)
+{
+    const void* addr = extractAddrOfConst(op);
+    return (addr == NULL) ? false : (fVal == *(const float*)addr);
+}
+
+int OpndUtils::extractIntConst(const Opnd* op)
+{
+    assert(isConstAreaItem(op));
+    const void* addr = extractAddrOfConst(op);
+    return *(const int*)addr;
+}
+
+double OpndUtils::extractDoubleConst(const Opnd* op)
+{
+    assert(isConstAreaItem(op));
+    const void* addr = extractAddrOfConst(op);
+    return *(const double*)addr;
+}
+
+float OpndUtils::extractFloatConst(const Opnd* op)
+{
+    assert(isConstAreaItem(op));
+    const void* addr = extractAddrOfConst(op);
+    return *(const float*)addr;
+}
+
+bool OpndUtils::equals(const Opnd* a, const Opnd* b)
+{
+    //TODO:
+    return a == b;
+}
+
+Opnd* OpndUtils::convertImmToImm8(Opnd* imm)
+{
+    if (isImm8(imm)) {
+        return imm;
+    }
+    assert(fitsImm8(imm));
+    TypeManager& typeMan = m_irManager->getTypeManager();
+    Type* int8type = typeMan.getInt8Type();
+    Opnd* imm8 = m_irManager->newImmOpnd(int8type, imm->getImmValue());
+    return imm8;
+}
+
+Opnd* OpndUtils::convertToXmmReg64(Opnd* xmmReg)
+{
+    assert(isXmmReg(xmmReg));
+    RegName regName = xmmReg->getRegName();
+    OpndSize size = getRegSize(regName);
+    if (size == OpndSize_64) {
+        return xmmReg;
+    }
+    TypeManager& typeMan = m_irManager->getTypeManager();
+    Type* doubleType = typeMan.getDoubleType();
+    unsigned regIndex = getRegIndex(regName);
+    RegName regName64 = getRegName(OpndKind_XMMReg, OpndSize_64, regIndex);
+    Opnd* xmm64 = m_irManager->newRegOpnd(doubleType, regName64);
+    return xmm64;
+}
+
+Opnd* OpndUtils::getZeroConst(Type* type)
+{
+    if (type->isDouble()) {
+        return getDoubleZeroConst();
+    }
+    if (type->isSingle()) {
+        return getFloatZeroConst();
+    }
+    if (type->isInt4()) {
+        return getIntZeroConst();
+    }
+    return m_irManager->newImmOpnd(type, 0);
+}
+
+Opnd* OpndUtils::getIntZeroConst(void)
+{
+    if (m_opndIntZero == NULL) {
+        Type* type = m_irManager->getTypeFromTag(Type::Int32);
+        m_opndIntZero = m_irManager->newImmOpnd(type, 0);
+    }
+    return m_opndIntZero;
+}
+Opnd* OpndUtils::getDoubleZeroConst(void)
+{
+    if (m_opndDoubleZero == NULL) {
+        m_opndDoubleZero = m_irManager->newFPConstantMemOpnd((double)0);
+    }
+    return m_opndDoubleZero;
+}
+
+Opnd* OpndUtils::getFloatZeroConst(void)
+{
+    if (m_opndFloatZero == NULL) {
+        m_opndFloatZero = m_irManager->newFPConstantMemOpnd((float)0);
+    }
+    return m_opndFloatZero;
+}
+
+
+
+bool InstUtils::isPseudoInst(const Inst* inst)
+{
+    return inst->hasKind(Inst::Kind_PseudoInst);
+}
+
+void InstUtils::removeInst(Inst* toBeRemoved)
+{
+    toBeRemoved->unlink();
+}
+
+void InstUtils::replaceInst(Inst* toBeReplaced, Inst* brandNewInst)
+{
+    BasicBlock* bb = toBeReplaced->getBasicBlock();
+    bb->appendInst(brandNewInst, toBeReplaced);
+    removeInst(toBeReplaced);
+}
+
+
+ControlFlowGraph* SubCfgBuilderUtils::newSubGFG(bool withReturn, bool withUnwind)
+{
+    m_subCFG = m_irManager->createSubCFG(withReturn, withUnwind);
+    return m_subCFG;
+}
+
+Node* SubCfgBuilderUtils::getSubCfgEntryNode(void)
+{
+    return m_subCFG->getEntryNode();
+}
+
+Node* SubCfgBuilderUtils::getSubCfgReturnNode(void)
+{
+    return m_subCFG->getReturnNode();
+}
+
+BasicBlock* SubCfgBuilderUtils::newBB(void)
+{
+    BasicBlock* bb = (BasicBlock*)m_subCFG->createBlockNode();
+    setCurrentNode(bb);
+    return bb;
+}
+
+Node* SubCfgBuilderUtils::setCurrentNode(Node* node)
+{
+    Node* old = m_currNode;
+    m_currNode = node;
+    return old;
+}
+
+Node* SubCfgBuilderUtils::getCurrentNode(void) const
+{
+    return m_currNode;
+}
+
+Inst* SubCfgBuilderUtils::newInst(
+    Mnemonic mn, 
+    unsigned defsCount, 
+    Opnd* op0, Opnd* op1, Opnd* op2, 
+    Opnd* op3, Opnd* op4, Opnd* op5)
+{
+    Inst* inst = NULL;
+    if (mn == Mnemonic_MOV) {
+        assert(op0 != NULL && op1 != NULL);
+        assert(op2==NULL && op3 == NULL);
+        assert(op4 == NULL && op5 == NULL);
+        inst = m_irManager->newCopyPseudoInst(mn, op0, op1);
+    }
+    else {
+        inst = m_irManager->newInstEx(mn, defsCount, op0, op1, op2, op3, op4, op5);
+    }
+    m_currNode->appendInst(inst);
+    return inst;
+}
+
+Inst* SubCfgBuilderUtils::newInst(
+    Mnemonic mn, Opnd* op0, Opnd* op1, Opnd*op2)
+{
+    if (mn == Mnemonic_MOV) {
+        // special handling in another newInst()
+        return newInst(mn, 0, op0, op1, op2);
+        
+    }
+    Inst* inst = m_irManager->newInst(mn, op0, op1, op2);
+    m_currNode->appendInst(inst);
+    return inst;
+}
+
+Inst* SubCfgBuilderUtils::newBranch(
+    Mnemonic mn, 
+    Node* trueTarget, Node* falseTarget,
+    double trueProbability, double falseProbability)
+{
+    Inst* branch = m_irManager->newBranchInst(mn, trueTarget, falseTarget);
+    m_currNode->appendInst(branch);
+    m_subCFG->addEdge(m_currNode, trueTarget, trueProbability);
+    m_subCFG->addEdge(m_currNode, falseTarget, falseProbability);
+    return branch;
+}
+
+void SubCfgBuilderUtils::connectNodes(Node* from, Node* to)
+{
+    m_subCFG->addEdge(from, to);
+}
+
+void SubCfgBuilderUtils::connectNodeTo(Node* to)
+{
+    connectNodes(m_currNode, to);
+}
+
+ControlFlowGraph* SubCfgBuilderUtils::getSubCFG(void)
+{
+    return m_subCFG;
+}
+
+ControlFlowGraph* SubCfgBuilderUtils::setSubCFG(ControlFlowGraph* subCFG)
+{
+    ControlFlowGraph* old = m_subCFG;
+    m_subCFG = subCFG;
+    return old;
+}
+
+void SubCfgBuilderUtils::propagateSubCFG(Inst* inst, bool purgeEmptyNodes)
+{
+    ControlFlowGraph* mainCFG = m_irManager->getFlowGraph();
+    mainCFG->spliceFlowGraphInline(inst, *m_subCFG);
+    InstUtils::removeInst(inst);
+    if (purgeEmptyNodes) {
+        mainCFG->purgeEmptyNodes(true, false);
+    }
+    m_subCFG = NULL;
+}
+
+}}; // ~namespace Jitrino::Ia32

Added: harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32CgUtils.h
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32CgUtils.h?view=auto&rev=478172
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32CgUtils.h (added)
+++ harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32CgUtils.h Wed Nov 22 06:32:28 2006
@@ -0,0 +1,292 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+ * @author Alexander Astapchuk
+ * @version $Revision$
+ */
+
+#if !defined(__IA32_CGUTILS_INCLUDED__)
+#define __IA32_CGUTILS_INCLUDED__
+
+#include "Ia32IRManager.h"
+
+namespace Jitrino {
+namespace Ia32 {
+
+class IRManagerHolder {
+public:
+    IRManagerHolder()
+    {
+        m_irManager = NULL;
+    }
+    
+    void setIRManager(IRManager* irm)
+    {
+        m_irManager = irm;
+    }
+    IRManager* getIRManager(void)
+    {
+        return m_irManager;
+    }
+protected:
+    IRManager*  m_irManager;
+};
+
+/**
+ * A mix-in that provides various Opnd manipulations IRManager.
+ */
+class OpndUtils : virtual protected IRManagerHolder {
+public:
+    OpndUtils()
+    {
+        m_opndIntZero = NULL;
+        m_opndDoubleZero = NULL;
+        m_opndFloatZero = NULL;
+    }
+    
+    /**
+     * Tests whether the Opnd has only one def.
+     */
+    static bool isSingleDef(const Opnd* opnd);
+    
+    /**
+     * Tests whether the given operand is placed on (any) register and 
+     * optionally test against the specified RegName (\c what).
+     */
+    static bool isReg(const Opnd* op, RegName what = RegName_Null);
+    
+    /**
+     * Tests whether the given operand is placed on XMM register and
+     * optionally test against the specified RegName (\c what).
+     */
+    static bool isXmmReg(const Opnd* op, RegName what = RegName_Null);
+    
+    /**
+     * Tests whether the given operand is placed on memory.
+     */
+    static bool isMem(const Opnd* op);
+    
+    /**
+     * Tests whether the operand is immediate.
+     * 
+     * @note The method only returns \n true for immediate-s without 
+     * RuntimeInfo. This is because the real value of immediate with 
+     * RuntimeInfo is unknown until very last - they get resolved only 
+     * in CodeEmitter.
+     */
+    static bool isImm(const Opnd* op);
+    
+    /**
+     * Tests whether the Opnd is immediate and has the provided value.
+     * 
+     * @note See note at isImm(const Opnd* op).
+     */
+    static bool isImm(const Opnd* op, int iVal);
+    
+    /**
+     * Tests whether the Opnd is immediate of the zero value.
+     * 
+     * No more than a named shortcut for isImm(op, 0).
+     */
+    static bool isZeroImm(const Opnd* op);
+    
+    /**
+     * Tests whether the Opnd is Type::Int8 immediate.
+     * 
+     * @note See note at isImm(const Opnd* op).
+     */
+    static bool isImm8(const Opnd* op);
+    
+    /**
+     * Tests whether the Opnd is Type::Int32 immediate.
+     * 
+     * @note See note at isImm(const Opnd* op).
+     */
+    static bool isImm32(const Opnd* op);
+    
+    /**
+     * Tests whether the Opnd is an immediate (note: of \b any type)
+     * and whether it is equal to the provided value.
+     * 
+     * @note See note at isImm(const Opnd* op).
+     */
+    static bool isFPConst(const Opnd* op, double d);
+    
+    /**
+     * Tests whether the Opnd is an immediate (note: of \b any type)
+     * and whether it is equal to the provided value.
+     * 
+     * @note See note at isImm(const Opnd* op).
+     */
+    static bool isFPConst(const Opnd* op, float f);
+    
+    /**
+     * Tests whether the Opnd is a constant area item.
+     */
+    static bool isConstAreaItem(const Opnd* op);
+    
+    /**
+     * Extracts address of constant area item.
+     *
+     * @return NULL if \c op is not a constant area item.
+     */
+    static const void* extractAddrOfConst(const Opnd* op);
+    
+    /**
+     * Extracts integer constant from constant area item.
+     *
+     * @note The \c op must be the constant item.
+     */
+    static int    extractIntConst(const Opnd* op);
+    
+    /**
+     * Extracts double constant from constant area item.
+     *
+     * @note The \c op must be the constant item.
+     */
+    static double extractDoubleConst(const Opnd* op);
+    
+    /**
+     * Extracts float constant from constant area item.
+     *
+     * @note The \c op must be the constant item.
+     */
+    static float  extractFloatConst(const Opnd* op);
+    
+    /**
+     * Tests whether the provided Opnd is immediate and its value may be 
+     * placed in a single byte.
+     */
+    static bool fitsImm8(const Opnd* op);
+    
+    /**
+     * Tests 2 operands for equality.
+     */
+    static bool equals(const Opnd* a, const Opnd* b);
+    //
+    // The following are not static and require IRManager
+    //
+    Opnd* convertImmToImm8(Opnd* imm);
+    Opnd* convertToXmmReg64(Opnd* xmmReg);
+    
+    Opnd* getIntZeroConst(void);
+    Opnd* getDoubleZeroConst(void);
+    Opnd* getFloatZeroConst(void);
+    Opnd* getZeroConst(Type* type);
+    
+private:
+    Opnd* m_opndIntZero;
+    Opnd* m_opndDoubleZero;
+    Opnd* m_opndFloatZero;
+};
+
+class InstUtils : virtual protected IRManagerHolder {
+public:
+    static bool isPseudoInst(const Inst*);
+    static void removeInst(Inst* toBeRemoved);
+    static void replaceInst(Inst* old, Inst* brandNewInst);
+};
+
+class SubCfgBuilderUtils : virtual protected IRManagerHolder {
+public:
+    SubCfgBuilderUtils()
+    {
+        m_subCFG = NULL;
+        m_currNode = NULL;
+    }
+    /**
+     * Creates new sub CFG and makes it current.
+     */
+    ControlFlowGraph* newSubGFG(bool withReturn=true, bool withUnwind=false);
+    /**
+     * Creates new basic block and makes it current.
+     */
+    BasicBlock* newBB(void);
+    /**
+     * Sets current node to operate on.
+     */
+    Node* setCurrentNode(Node* node);
+    /**
+     * Returns current node.
+     */
+    Node* getCurrentNode(void) const;
+    /**
+     * Returns entry node of current subCFG.
+     */
+    Node* getSubCfgEntryNode(void);
+    /**
+     * Returns return node of current subCFG.
+     */
+    Node* getSubCfgReturnNode(void);
+    /**
+     * Sets current subCFG to operate on.
+     */
+    ControlFlowGraph* setSubCFG(ControlFlowGraph* subCFG);
+    /**
+     * Returns current subCFG.
+     */
+    ControlFlowGraph* getSubCFG(void);
+    /**
+     * Replaces the given Inst with the subCFG just built, and clears 
+     * current subCFG.
+     *
+     * Also invokes minor cleanup on CFG when \c purgeEmptyNodes == \c true.
+     */
+    void propagateSubCFG(Inst* inst, bool purgeEmptyNodes = true);
+    /**
+     * Creates an instruction with the given mnemonic and arguments and 
+     * adds it to the end of current node.
+     *
+     * Special handling for Mnemonic_MOV: CopyPseudoInstruction 
+     * is generated.
+     */
+    Inst* newInst(Mnemonic mn, unsigned defsCount,
+        Opnd* op0 = NULL, Opnd* op1 = NULL, Opnd* op2 = NULL,
+        Opnd* op3 = NULL, Opnd* op4 = NULL, Opnd* op5 = NULL);
+    /**
+     * Creates an instruction with the given mnemonic and arguments and 
+     * adds it to the end of current node.
+     *
+     * Special handling for Mnemonic_MOV: CopyPseudoInstruction 
+     * is generated.
+     */
+    Inst* newInst(Mnemonic mn, 
+        Opnd* op0 = NULL, Opnd* op1 = NULL, Opnd*op2 = NULL);
+    /**
+     * Generates branch instruction with the given mnemonic and given target
+     * nodes, adds it to the end of current node, and also adds edges 
+     * from current to provided nodes.
+     */
+    Inst* newBranch(Mnemonic mn, Node* trueTarget, Node* falseTarget,
+        double trueProbability=0.5, double falseProbability=0.5);
+    /**
+     * Creates an edge from the current node to the specified node.
+     */
+    void connectNodeTo(Node* to);
+    /**
+     * Creates an edge from \c from node, to the \c to node.
+     */
+    void connectNodes(Node* from, Node* to);
+private:
+    ControlFlowGraph * m_subCFG;
+    Node* m_currNode;
+};
+
+
+}}; // ~namespace Jitrino::Ia32
+
+#endif  // ~ifndef __IA32_CGUTILS_INCLUDED__

Modified: harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32DCE.cpp
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32DCE.cpp?view=diff&rev=478172&r1=478171&r2=478172
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32DCE.cpp (original)
+++ harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32DCE.cpp Wed Nov 22 06:32:28 2006
@@ -62,7 +62,9 @@
             irManager->getLiveAtExit(node, ls);
             for (Inst * inst=(Inst*)node->getLastInst(), * prevInst=NULL; inst!=NULL; inst=prevInst){
                 prevInst=inst->getPrevInst();
-                bool deadInst=!inst->hasSideEffect();
+                // Prevent debug traps or instructions with side effects
+                // like (MOVS) from being removed.
+                bool deadInst=!inst->hasSideEffect() && (inst->getMnemonic() != Mnemonic_INT3);
                 if (deadInst){
                     if (inst->hasKind(Inst::Kind_CopyPseudoInst)){
                         Opnd * opnd=inst->getOpnd(1);

Modified: harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32I8Lowerer.cpp
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32I8Lowerer.cpp?view=diff&rev=478172&r1=478171&r2=478172
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32I8Lowerer.cpp (original)
+++ harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32I8Lowerer.cpp Wed Nov 22 06:32:28 2006
@@ -16,34 +16,173 @@
  */
 /**
  * @author Nikolay A. Sidelnikov
- * @version $Revision: 1.12.6.2.4.3 $
+ * @version $Revision$
  */
 
 #include "Ia32IRManager.h"
 #include "Ia32Inst.h"
+#include "Dominator.h"
+#include "Ia32CgUtils.h"
 
-namespace Jitrino
-{
+namespace Jitrino {
 namespace Ia32 {
 
-class I8Lowerer : public SessionAction {
-    void runImpl();
+/**
+ * Replaces operations with 64 bits integer values with a set of operations
+ * supported by IA-32 ISA.
+ *
+ * I8PseudoInstruction-s, normally generated by InstCodeSelector.
+ */
+class I8Lowerer : 
+    public SessionAction, 
+    protected OpndUtils, 
+    protected SubCfgBuilderUtils 
+{
+    /**
+     * Main entry point of this Action.
+     */
+    void runImpl(void);
+private:
+    typedef StlMap<Opnd *,Opnd **>  OPND_PAIRS_MAP;
+    typedef StlVector<Inst*>        INST_ARRAY;
+    typedef StlMap<Inst*, Node*>    INST_TO_NODE_MAP;
+    //
+    // virtuals
+    //
+    uint32 getNeedInfo(void) const
+    {
+        return NeedInfo_LoopInfo;
+    }
+    uint32 getSideEffects(void) const
+    {
+        // Simplest presumption - if we found at least one I8PseudoInst
+        // we might affect everything, including liveness, loop info 
+        // and dominator tree
+        return foundI8Opnds;
+    }
 protected:
-    void processOpnds(Inst * inst, StlMap<Opnd *,Opnd **>& pairs);
-    void prepareNewOpnds(Opnd * longOpnd, StlMap<Opnd *,Opnd **>& pairs, Opnd*& newOp1, Opnd*& newOp2);
-    bool isI8Type(Type * t){ return t->tag==Type::Int64 || t->tag==Type::UInt64; }
-    uint32 getNeedInfo () const     {return 0;}
-    virtual uint32 getSideEffects()const {return foundI8Opnds;}
+    /**
+     * Dispatches instruction processing, basing on its Mnemonic.
+     */
+    void processOpnds(Inst * inst);
+    /**
+     * Splits the long operand up to the 2 32bits operands.
+     */
+    void prepareNewOpnds(Opnd * longOpnd, Opnd*& lowPartOpnd, Opnd*& hiPartOpnd);
 
     void buildShiftSubGraph(Inst * inst, Opnd * src1_1, Opnd * src1_2, Opnd * src2, Opnd * dst_1, Opnd * dst_2, Mnemonic mnem, Mnemonic opMnem);
     void buildComplexSubGraph(Inst * inst, Opnd * src1_1,Opnd * src1_2,Opnd * src2_1,Opnd * src2_2, Inst * condInst = NULL);
     void buildSetSubGraph(Inst * inst, Opnd * src1_1,Opnd * src1_2,Opnd * src2_1,Opnd * src2_2, Inst * condInst = NULL);
     void buildJumpSubGraph(Inst * inst, Opnd * src1_1,Opnd * src1_2,Opnd * src2_1,Opnd * src2_2, Inst * condInst = NULL);
+    /**
+     * Processes I8 IMUL instruction.
+     *
+     * Depending on a flag, generates either call to internal helper, 
+     * or generates and inserts sub-graph.
+     *
+     * @see inlineMul64
+     */
+    void lowerMul64(Inst* inst);
+    /**
+     * Processes I8 IDIV instruction.
+     *
+     * Depending on a flag, generates either call to internal helper, 
+     * or generates and inserts sub-graph.
+     */
+    void lowerDiv64(Inst* inst);
+    /**
+     * Processes I8 remainder instruction.
+     *
+     * Depending on a flag, generates either call to internal helper, 
+     * or generates and inserts sub-graph.
+     */
+    void lowerRem64(Inst* inst);
+    /**
+     * Generates sub-graph for multiplication of 2 64-bits long values.
+     */
+    void inlineMul64(Inst* inst);
+    /**
+     * Generates sub-graph for calculating quotient and remainder of 2 
+     * 64 bits integer values, using integer instructions.
+     */
+    void inlineDivRem64(bool wantReminder, Inst* inst);
+    /**
+     * Tries to propagate and reuse results of inlined Div64 or Rem64 
+     * instruction, to reduce code size and complex operations in the 
+     * resulting CFG.
+     */
+    void propagateDivRemResults(Inst* originalInst, Node* originalInstNode, 
+        Opnd* quot_lo, Opnd* quot_hi, Opnd* rem_lo, Opnd* rem_hi);
 
     uint32 foundI8Opnds;
+private:
+    /**
+     * Tests whether the type is subject for lowering.
+     */
+    static bool isI8Type(Type * t)
+    {
+        return t->tag==Type::Int64 || t->tag==Type::UInt64;
+    }
+    /**
+     * Tests whether the given Inst represents I8PseudoInstruction of 
+     * remainder calculation.
+     */
+    static bool isI8RemInst(const Inst* inst) 
+    {
+        if (!inst->hasKind(Inst::Kind_I8PseudoInst)) {
+            return false;
+        }
+        if (inst->getMnemonic() != Mnemonic_IDIV) {
+            return false;
+        }
+        if (inst->getOpndCount()<=3) {
+            return false;
+        }
+        // The additional fake parameter shows that in fact 
+        // we need REMinder, not DIV. See InstCodeSelector
+#ifdef _DEBUG
+        Opnd* fakeFlag = inst->getOpnd(3);
+        // Hard - coded values as they're hard coded in CodeSelector
+        // Just to check no one started to use the I8PseudoInst with 
+        // IDIV mnemonic for anything else.
+        assert(isImm(fakeFlag) && fakeFlag->getImmValue()==12345678);
+#endif
+        return true;
+    }
+    /**
+     * Points to the list of instructions to process.
+     *
+     * The pointer points to the local variable in runImpl();
+     */
+    INST_ARRAY*         m_pI8Insts;
+    /**
+     * Points to map of pairs 64 bits operand => two 32 bit operands.
+     *
+     * The pointer points to the local variable in runImpl();
+     */
+    OPND_PAIRS_MAP*     m_pairs;
+    /**
+     * Points to a map of Inst => header of the loop it belongs to.
+     *
+     * The pointer points to the local variable in runImpl();
+     */
+    INST_TO_NODE_MAP*   m_pLoopInfos;
 };
 
-static ActionFactory <I8Lowerer> _i8l("i8l");
+static const char* help = 
+"inline_mul64=true/false\n"
+"   default=true. Inlines multiplication of 64 bits longs, instead of generating call to helper.\n"
+"inline_mul64_checks=true/false\n"
+"   default=false. Adds additional checks whether multipliers are indeed int32 for simpler operation.\n"
+"inline_div64=true/false\n"
+"   default=true. Inlines division of 64 bits longs, instead of generating call to helper.\n"
+"inline_rem64=true/false\n"
+"   default=true. Inlines calculation of remainder of 64 bits longs, instead of generating call to helper.\n"
+"propagate_div_rem=true/false\n"
+"   default=true. Tries to match pairs 'A/B, A%B' and inline only single code sequence.\n"
+"";
+
+static ActionFactory <I8Lowerer> _i8l("i8l", help);
 
 //_______________________________________________________________________________________________________________
 // I8 operation internal helpers
@@ -55,90 +194,143 @@
 int64 __stdcall idiv64(const int64 src1, const int64 src2)
 {   return src1/src2;   }
 
-//_______________________________________________________________________________________________________________
+int64 __stdcall irem64(const int64 src1, const int64 src2)  stdcall__;
+int64 __stdcall irem64(const int64 src1, const int64 src2)
+{   return src1%src2;   }
+
+
 void I8Lowerer::runImpl() 
 {
-
-// I8 operation internal helpers
+    // I8 operation internal helpers
     irManager->registerInternalHelperInfo("imul64", IRManager::InternalHelperInfo((void*)&imul64,&CallingConvention_STDCALL));
     irManager->registerInternalHelperInfo("idiv64", IRManager::InternalHelperInfo((void*)&idiv64,&CallingConvention_STDCALL));
-
-    StlMap<Opnd *,Opnd **> pairs(irManager->getMemoryManager());
-    StlVector<Inst *> i8Insts(irManager->getMemoryManager());
+    irManager->registerInternalHelperInfo("irem64", IRManager::InternalHelperInfo((void*)&irem64,&CallingConvention_STDCALL));
+    
+    // Initialize various xxUtils
+    setIRManager(irManager);
 
     ControlFlowGraph* fg = irManager->getFlowGraph();
+
+    const unsigned totalI8InstCountEstimate = fg->getNodeCount()*5;
+    unsigned memSizeEstimate = 
+            // for i8Insts
+            sizeof(Inst*)*totalI8InstCountEstimate +
+            // for loopInfo
+            sizeof(unsigned)*totalI8InstCountEstimate + 
+            // for pairs
+            (sizeof(Opnd*)+sizeof(Opnd**)*2)*totalI8InstCountEstimate;
+
+    memSizeEstimate = (unsigned)(memSizeEstimate*0.1);
+    MemoryManager memMgr(memSizeEstimate, "i8lowerer");
+
+    StlMap<Opnd *,Opnd **> pairs(memMgr);
+    m_pairs = &pairs;
+
+    INST_ARRAY  i8Insts(memMgr);
+    m_pI8Insts = &i8Insts;
+
+    INST_TO_NODE_MAP loopInfos(memMgr);
+    m_pLoopInfos = &loopInfos;
+
+    irManager->calculateOpndStatistics();
+
     const Nodes* postOrder = &fg->getNodesPostOrder();
+    const LoopTree* loopTree = fg->getLoopTree();
+
+    //
+    // 1. Walk the CFG, collect Inst-s to be processed. 
+    // Also, count the defs [for I8] operands
+    //
     for (Nodes::const_reverse_iterator it = postOrder->rbegin(), end = postOrder->rend(); it!=end; ++it) {
         Node* node = *it;
-        if (node->isBlockNode()) {
-            for (Inst* inst = (Inst*)node->getFirstInst(); inst!=NULL; inst = inst->getNextInst()) {
-                if (inst->hasKind(Inst::Kind_I8PseudoInst) || (inst->getMnemonic()==Mnemonic_CALL 
-                        || inst->getMnemonic()==Mnemonic_RET ||inst->hasKind(Inst::Kind_EntryPointPseudoInst)) 
-                        || inst->hasKind(Inst::Kind_AliasPseudoInst)){
-                    i8Insts.push_back(inst);
-                    foundI8Opnds = ~(uint32)0;
-                }
+        if (!node->isBlockNode()) {
+            continue;
+        }
+        for (Inst* inst = (Inst*)node->getFirstInst(); inst!=NULL; inst = inst->getNextInst()) {
+            bool doProcess = 
+                    inst->hasKind(Inst::Kind_I8PseudoInst) || 
+                    inst->getMnemonic()==Mnemonic_CALL || 
+                    inst->getMnemonic()==Mnemonic_RET ||
+                    inst->hasKind(Inst::Kind_EntryPointPseudoInst) || 
+                    inst->hasKind(Inst::Kind_AliasPseudoInst);
+            if (doProcess) {
+                i8Insts.push_back(inst);
+                Node* loopHeader = loopTree->getLoopHeader(node, false);
+                loopInfos[inst] = loopHeader;
             }
         }
     }
 
+    // Will be used in propagateDivRem()
+    computeDominators();
+
     for(StlVector<Inst *>::iterator it = i8Insts.begin(); it != i8Insts.end(); it++) {
-        processOpnds(*it, pairs);
+        Inst* inst = *it;
+        // Processes instructions get replaced with NULL
+        if (inst != NULL) {
+            processOpnds(inst);
+            *it = NULL;
+        }
     }
-    
+
     fg->purgeEmptyNodes();
+    fg->purgeUnreachableNodes();
 
     postOrder = &fg->getNodesPostOrder();
     for (Nodes::const_reverse_iterator it = postOrder->rbegin(), end = postOrder->rend(); it!=end; ++it) {
         Node * node= *it;
-        if (node->isBlockNode()) {
-            Inst *  cdq = NULL;
-            for (Inst* inst = (Inst*)node->getFirstInst(),*nextInst=NULL; inst!=NULL; inst = nextInst) {
-                nextInst = inst->getNextInst();
-                uint32  defCount = inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Def);
-                if(inst->getMnemonic() == Mnemonic_CDQ) {
-                    if (inst->getNextInst()!=NULL && inst->getNextInst()->getMnemonic() == Mnemonic_IDIV) {
-                        continue;
-                    }
-                    cdq = inst;
-                } else if ( cdq && inst->getMnemonic() == Mnemonic_AND &&
-                    inst->getOpnd(defCount+1)->isPlacedIn(OpndKind_Imm) && 
-                    inst->getOpnd(defCount+1)->getImmValue() == 0 &&
-                    cdq->getOpnd(0)==inst->getOpnd(defCount)) {
-                        Inst * tmpInst = irManager->newCopyPseudoInst(Mnemonic_MOV,inst->getOpnd(0), irManager->newImmOpnd(inst->getOpnd(0)->getType(),0));
-                        tmpInst->insertAfter(inst);
-                        inst->unlink();
-                        inst = tmpInst;
-                        cdq->unlink();
-                        cdq = NULL;
-                } else if ( inst->getMnemonic() == Mnemonic_AND &&
-                            inst->getOpnd(defCount+1)->isPlacedIn(OpndKind_Imm) && 
-                            inst->getOpnd(defCount+1)->getImmValue() == 0xFFFFFFFF) {
-                    Inst * tmpInst = irManager->newCopyPseudoInst(Mnemonic_MOV,inst->getOpnd(0), inst->getOpnd(defCount));
+        if (!node->isBlockNode()) {
+            continue;
+        }
+        Inst *  cdq = NULL;
+        for (Inst* inst = (Inst*)node->getFirstInst(),*nextInst=NULL; inst!=NULL; inst = nextInst) {
+            nextInst = inst->getNextInst();
+            uint32  defCount = inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Def);
+            if(inst->getMnemonic() == Mnemonic_CDQ) {
+                if (inst->getNextInst()!=NULL && inst->getNextInst()->getMnemonic() == Mnemonic_IDIV) {
+                    continue;
+                }
+                cdq = inst;
+            } else if ( cdq && inst->getMnemonic() == Mnemonic_AND &&
+                isZeroImm(inst->getOpnd(defCount+1)) && 
+                cdq->getOpnd(0)==inst->getOpnd(defCount)) {
+                    Inst * tmpInst = irManager->newCopyPseudoInst(Mnemonic_MOV,inst->getOpnd(0), irManager->newImmOpnd(inst->getOpnd(0)->getType(),0));
                     tmpInst->insertAfter(inst);
                     inst->unlink();
                     inst = tmpInst;
-                }
+                    cdq->unlink();
+                    cdq = NULL;
+            } else if ( inst->getMnemonic() == Mnemonic_AND &&
+                        isImm(inst->getOpnd(defCount+1)) && 
+                        inst->getOpnd(defCount+1)->getImmValue() == 0xFFFFFFFF) {
+                Inst * tmpInst = irManager->newCopyPseudoInst(Mnemonic_MOV,inst->getOpnd(0), inst->getOpnd(defCount));
+                tmpInst->insertAfter(inst);
+                inst->unlink();
+                inst = tmpInst;
             }
         }
     }
 }
 
-void I8Lowerer::processOpnds(Inst * inst, StlMap<Opnd *,Opnd **>& pairs)
+void I8Lowerer::processOpnds(Inst * inst)
 {
     Opnd * newOp1 = NULL, *newOp2 = NULL;
     Opnd * dst_1 = NULL, * dst_2 = NULL, * src1_1 = NULL, * src1_2 = NULL, * src2_1 = NULL, * src2_2 = NULL;
     Mnemonic mn = inst->getMnemonic();
-    if (mn==Mnemonic_CALL || mn==Mnemonic_RET ||inst->hasKind(Inst::Kind_EntryPointPseudoInst) 
-            || inst->hasKind(Inst::Kind_AliasPseudoInst)) {
+    if (mn==Mnemonic_CALL || 
+        mn==Mnemonic_RET ||
+        inst->hasKind(Inst::Kind_EntryPointPseudoInst) || 
+        inst->hasKind(Inst::Kind_AliasPseudoInst)) {
         for(uint32 i = 0; i < inst->getOpndCount(); i++) {
             Opnd * opnd = inst->getOpnd(i);
-            if (!isI8Type(opnd->getType()))
+            if (!isI8Type(opnd->getType())) {
                 continue;
+            }
+            foundI8Opnds = ~(uint32)0;
             uint32 roles = inst->getOpndRoles(i);
             if (inst->hasKind(Inst::Kind_AliasPseudoInst)) {
                 if (roles & Inst::OpndRole_Use) {
-                    prepareNewOpnds(opnd,pairs,newOp1,newOp2);
+                    prepareNewOpnds(opnd,newOp1,newOp2);
                     inst->setOpnd(i, newOp1);
                     inst->insertOpnd(i+1, newOp2, roles);
                     inst->setConstraint(i, Constraint(OpndKind_Mem, OpndSize_32));
@@ -146,10 +338,10 @@
                     i++;
                 }
             } else {
-                prepareNewOpnds(opnd,pairs,newOp1,newOp2);
-            inst->setOpnd(i++, newOp1);
-            inst->insertOpnd(i, newOp2, roles);
-        }
+                prepareNewOpnds(opnd,newOp1,newOp2);
+                inst->setOpnd(i++, newOp1);
+                inst->insertOpnd(i, newOp2, roles);
+            }
         }
     } else if (inst->hasKind(Inst::Kind_I8PseudoInst)){
         uint32  defCount = inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Def),
@@ -160,11 +352,11 @@
 
         if (mn!=Mnemonic_IDIV && mn!=Mnemonic_IMUL) {
             if (dst)
-                prepareNewOpnds(dst,pairs,dst_1,dst_2);
+                prepareNewOpnds(dst, dst_1,dst_2);
             if (src1)
-                prepareNewOpnds(src1,pairs,src1_1,src1_2);
+                prepareNewOpnds(src1, src1_1,src1_2);
             if (src2)
-                prepareNewOpnds(src2,pairs,src2_1,src2_2);
+                prepareNewOpnds(src2, src2_1,src2_2);
         }
 
         switch(mn) {
@@ -213,12 +405,17 @@
                     irManager->newInstEx(Mnemonic_MOV, 1, dst_1, src1_1)->insertBefore(inst);
                 }
                 if (mn==Mnemonic_MOVSX){
+                    // It's possible to substitute complex CDQ with a tight
+                    // constraints to the set of simpler instructions
+                    // with a wider constraints to let more freedom 
+                    // to regalloc and constraint resolver.
+                    // However, this seems does not change anything currently,
+                    // so leaving as-is.
+                    //test 	    low, low
+                    //setns 	hi		; if lo is positive, then load 1 into hi
+                    //sub		hi, 1	; if lo is positive, then hi is now '0'. otherwise, it's -1
                     irManager->newInstEx(Mnemonic_CDQ, 1, dst_2, dst_1)->insertBefore(inst);
                     inst->unlink();
-                } else {
-                    Opnd* zero = irManager->newImmOpnd(irManager->getTypeManager().getInt32Type(), 0);
-                    irManager->newInstEx(Mnemonic_MOV, 1, dst_2, zero)->insertBefore(inst);
-                    inst->unlink();
                 }
                 break;
             case Mnemonic_PUSH  :
@@ -271,26 +468,17 @@
                 inst->unlink();
                 break;
             }
-            case Mnemonic_IMUL  :
-            {
-                assert(dst && src1 && src2);
-                Opnd * args[2]={ src1, src2 };
-                CallInst * callInst = irManager->newInternalRuntimeHelperCallInst("imul64", 2, args, dst);
-                callInst->insertBefore(inst);
-                processOpnds(callInst, pairs);
-                inst->unlink();
+            case Mnemonic_IMUL:
+                lowerMul64(inst);
                 break;
-            }
-            case Mnemonic_IDIV  :
-            {
-                assert(dst && src1 && src2);
-                Opnd * args[2]={ src1, src2 };
-                CallInst * callInst = irManager->newInternalRuntimeHelperCallInst("idiv64", 2, args, dst);
-                callInst->insertBefore(inst);
-                processOpnds(callInst, pairs);
-                inst->unlink();
+            case Mnemonic_IDIV:
+                if (isI8RemInst(inst)) {
+                    lowerRem64(inst);
+                }
+                else {
+                    lowerDiv64(inst);
+                }
                 break;
-            }
             default :   
                 assert(0);
         }//end switch by mnemonics
@@ -378,16 +566,14 @@
     
     ControlFlowGraph* subCFG = irManager->createSubCFG(true, false);
     Node* bbHMain = subCFG->getEntryNode();
-    Node* bbHCmp = subCFG->createBlockNode();
     Node* bbLMain = subCFG->createBlockNode();
     Node* sinkNode =  subCFG->getReturnNode();
     
     bbHMain->appendInst(irManager->newInst(Mnemonic_CMP, src1_2, src2_2));
-    bbHMain->appendInst(irManager->newBranchInst(Mnemonic_JNZ, bbHCmp, bbLMain));
+    bbHMain->appendInst(irManager->newBranchInst(Mnemonic_JNZ, sinkNode, bbLMain));
     
     bbLMain->appendInst(irManager->newInst(Mnemonic_CMP, src1_1, src2_1));
     
-    bbHCmp->appendInst(irManager->newInst(Mnemonic_CMP, src1_2, src2_2));
     
     Node* bbFT = bb->getFalseEdgeTarget();
     Node* bbDB = bb->getTrueEdgeTarget();
@@ -402,8 +588,7 @@
     }
     bbLMain->appendInst(irManager->newBranchInst(mnem, bbDB, bbFT));
     
-    subCFG->addEdge(bbHMain, bbHCmp, 0.1);
-    subCFG->addEdge(bbHCmp, sinkNode, 1);
+    subCFG->addEdge(bbHMain, sinkNode, 0.1);
     subCFG->addEdge(bbHMain, bbLMain, 0.9);
     subCFG->addEdge(bbLMain, bbFT, 0.1);
     subCFG->addEdge(bbLMain, bbDB, 0.9);
@@ -507,7 +692,7 @@
     irManager->getFlowGraph()->spliceFlowGraphInline(inst, *subCFG);
 }
 
-void I8Lowerer::prepareNewOpnds(Opnd * longOpnd, StlMap<Opnd *,Opnd **>& pairs, Opnd*& newOp1, Opnd*& newOp2)
+void I8Lowerer::prepareNewOpnds(Opnd * longOpnd, Opnd*& newOp1, Opnd*& newOp2)
 {
     if (!isI8Type(longOpnd->getType())){
         newOp1=longOpnd;
@@ -515,9 +700,9 @@
         return;
     }
 
-    if(pairs.find(longOpnd)!=pairs.end()) {
-        newOp1 = pairs[longOpnd][0];
-        newOp2 = pairs[longOpnd][1];
+    if(m_pairs->find(longOpnd)!=m_pairs->end()) {
+        newOp1 = (*m_pairs)[longOpnd][0];
+        newOp2 = (*m_pairs)[longOpnd][1];
     } else {
         if(longOpnd->isPlacedIn(OpndKind_Memory)) {
             newOp1 = irManager->newOpnd(irManager->getTypeManager().getUInt32Type());
@@ -531,10 +716,641 @@
             newOp1 = irManager->newOpnd(irManager->getTypeManager().getUInt32Type());
             newOp2 = irManager->newOpnd(irManager->getTypeManager().getInt32Type());
         }
-        pairs[longOpnd] = new(irManager->getMemoryManager()) Opnd*[2];
-        pairs[longOpnd][0]=newOp1;
-        pairs[longOpnd][1]=newOp2;
+        (*m_pairs)[longOpnd] = new(irManager->getMemoryManager()) Opnd*[2];
+        (*m_pairs)[longOpnd][0]=newOp1;
+        (*m_pairs)[longOpnd][1]=newOp2;
+    }
+}
+
+void I8Lowerer::lowerMul64(Inst* inst)
+{
+    assert(inst->getOpndRoles(0) & Inst::OpndRole_Def);
+    assert(inst->getOpndRoles(1) & Inst::OpndRole_Use);
+    assert(inst->getOpndRoles(2) & Inst::OpndRole_Use);
+    Opnd* dst = inst->getOpnd(0);
+    Opnd* src1 = inst->getOpnd(1);
+    Opnd* src2 = inst->getOpnd(2);
+    assert(dst && src1 && src2);
+
+    if ( isZeroImm(src1) || isZeroImm(src2)) {
+        // Multiplue by zero - noop.
+        inst->unlink();
+        return;
+    }
+
+    bool inline_mul64 = true;
+    getArg("inline_mul64", inline_mul64);
+
+    if (!inline_mul64) {
+        Opnd * args[2]={ src1, src2 };
+        CallInst * callInst = irManager->newInternalRuntimeHelperCallInst("imul64", 2, args, dst);
+        callInst->insertBefore(inst);
+        processOpnds(callInst);
+        inst->unlink();
+        return;
+    }
+
+    inlineMul64(inst);
+}
+
+void I8Lowerer::inlineMul64(Inst* inst)
+{
+    assert(inst->getOpndRoles(0) & Inst::OpndRole_Def);
+    assert(inst->getOpndRoles(1) & Inst::OpndRole_Use);
+    assert(inst->getOpndRoles(2) & Inst::OpndRole_Use);
+    Opnd* dst = inst->getOpnd(0);
+    Opnd* src1 = inst->getOpnd(1);
+    Opnd* src2 = inst->getOpnd(2);
+
+    bool inline_mul64_checks = false;
+    getArg("inline_mul64_checks", inline_mul64_checks);
+
+    Opnd * dst_1 = NULL, * dst_2 = NULL;
+    Opnd * src1_1 = NULL, * src1_2 = NULL;
+    Opnd * src2_1 = NULL, * src2_2 = NULL;
+
+    prepareNewOpnds(dst, dst_1, dst_2);
+    prepareNewOpnds(src1, src1_1, src1_2);
+    prepareNewOpnds(src2, src2_1, src2_2);
+
+    TypeManager& tm = irManager->getTypeManager();
+    Type* int32type = tm.getInt32Type();
+    // Name them eax, ecx, edx here, in code only, to refer same regs as in 
+    // the comments, but let the register allocator to decide the proper 
+    // ones.
+    Opnd*eax;
+    Opnd*edx;
+    Opnd*ecx;
+
+    eax = irManager->newOpnd(int32type);
+    edx = irManager->newOpnd(int32type);
+    ecx = irManager->newOpnd(int32type);
+
+    Opnd* zero = irManager->newImmOpnd(int32type, 0);
+    
+    //
+    Opnd* a_lo = src1_1;
+    Opnd* a_hi = src1_2;
+    Opnd* b_lo = src2_1;
+    Opnd* b_hi = src2_2;
+    Opnd* res_lo = dst_1;
+    Opnd* res_hi = dst_2;
+    
+    /*
+    Strategy:
+    result = a*b ; 
+        a = a_lo + a_hi*(1<<32)
+        b = b_lo + b_hi*(1<<32)
+    - a*b = (a_lo + a_hi*(1<<32))*(b_lo + b_hi*(1<<32)) = 
+          a_lo*b_lo + a_hi*(1<<32)*b_lo + a_lo*b_hi*(1<<32) + a_hi*(1<<32)*b_hi*(1<<32)
+    
+    - a_hi*(1<<32)*b_hi*(1<<32) - can be dropped off, it's overflow
+    - with any of `a_hi*b_lo*(1<<32)` + `a_lo*b_hi*(1<<32)` we can ignore high 32 bits 
+        of result (EDX) - these are overflow again 
+    So, we're getting:
+
+    a_lo*b_lo + a_hi*b_lo*(1<<32) + a_lo*b_hi*(1<<32)
+    (1)         (2)             (3)
+    */
+    //
+    newSubGFG();
+    Node* entryNode = getSubCfgEntryNode();
+    
+    Node* longMulNode = newBB();
+    Node* storeResultNode = newBB();
+    setCurrentNode(NULL); 
+    if (!inline_mul64_checks) {
+        connectNodes(entryNode, longMulNode);
+    }
+    else {
+        Node* test_A_Node = newBB();
+        Node* test_B_Node = newBB();
+        Node* simpleMulNode = newBB();
+        setCurrentNode(NULL);
+        
+        connectNodes(entryNode, test_A_Node);
+        setCurrentNode(test_A_Node);
+        //
+        // test_A_Node:
+        //
+        /* cmp a_hi, 0*/    newInst(Mnemonic_CMP, a_hi, zero);
+        /* jnz  longMul */  newBranch(Mnemonic_JNZ, longMulNode, test_B_Node);
+        setCurrentNode(NULL);
+        test_A_Node = (Node*)0xDEADBEEF;
+        
+        //
+        // test_B_Node:
+        //
+        setCurrentNode(test_B_Node);
+        /* cmp b_hi, 0*/    newInst(Mnemonic_CMP, b_hi, zero);
+        /* jnz  longMul */  newBranch(Mnemonic_JNZ, longMulNode, simpleMulNode);
+        setCurrentNode(NULL);
+        test_B_Node = (Node*)0xDEADBEEF;
+        
+        //
+        // simpleMulNode:
+        //
+        setCurrentNode(simpleMulNode);
+        /* mov eax, a_lo */ newInst(Mnemonic_MOV, eax, a_lo);
+        /* imul b_lo */     newInst(Mnemonic_MUL, 2, edx, eax, eax, b_lo);
+        connectNodeTo(storeResultNode);
+        setCurrentNode(NULL);
+        simpleMulNode = (Node*)0xDEADBEEF;
+    }
+    entryNode = (Node*)0xDEADBEEF;
+    
+    setCurrentNode(longMulNode);
+    /* mov eax, a_lo*/  newInst(Mnemonic_MOV, eax, a_lo);
+    /* mul     b_hi */  newInst(Mnemonic_MUL, 2, edx, eax, eax, b_hi);
+    //
+    // Now, EAX=a_lo*b_hi, EDX content is dropped
+    //
+                        // save a_lo*b_hi(EAX) 
+    /* mov ecx, eax */  newInst(Mnemonic_MOV, ecx, eax);
+    /* mov eax, a_hi*/  newInst(Mnemonic_MOV, eax, a_hi);
+    /* mul b_lo     */  newInst(Mnemonic_MUL, 2, edx, eax, eax, b_lo);
+    /* add ecx, eax */  newInst(Mnemonic_ADD, 1, ecx, ecx, eax);
+
+    /* mov eax, a_lo */ newInst(Mnemonic_MOV, eax, a_lo);
+    /* mul b_lo      */ newInst(Mnemonic_MUL, 2, edx, eax, eax, b_lo);
+    /* add edx, ecx */  newInst(Mnemonic_ADD, 1, edx, edx, ecx);
+    connectNodes(longMulNode, storeResultNode);
+    setCurrentNode(NULL);
+    longMulNode = (Node*)0xDEADBEEF;
+    
+    //
+    // storeResultNode:
+    //
+    setCurrentNode(storeResultNode);
+    /* mov res_lo, eax*/    newInst(Mnemonic_MOV, res_lo, eax);
+    /* mov res_hi, edx*/    newInst(Mnemonic_MOV, res_hi, edx);
+    setCurrentNode(NULL);
+    connectNodes(storeResultNode, getSubCfgReturnNode());
+
+    propagateSubCFG(inst);
+}
+
+void I8Lowerer::lowerDiv64(Inst* inst)
+{
+    assert(inst->getOpndRoles(0) & Inst::OpndRole_Def);
+    assert(inst->getOpndRoles(1) & Inst::OpndRole_Use);
+    assert(inst->getOpndRoles(2) & Inst::OpndRole_Use);
+    Opnd* dst = inst->getOpnd(0);
+    Opnd* src1 = inst->getOpnd(1);
+    Opnd* src2 = inst->getOpnd(2);
+    assert(dst && src1 && src2);
+    
+    bool inline_div64 = true;
+    getArg("inline_div64", inline_div64);
+
+    if (!inline_div64) {
+        Opnd * args[2]={ src1, src2 };
+        CallInst * callInst = irManager->newInternalRuntimeHelperCallInst("idiv64", 2, args, dst);
+        callInst->insertBefore(inst);
+        processOpnds(callInst);
+        inst->unlink();
+        return;
+    }
+    inlineDivRem64(false, inst);
+}
+
+void I8Lowerer::lowerRem64(Inst* inst)
+{
+    assert(inst->getOpndRoles(0) & Inst::OpndRole_Def);
+    assert(inst->getOpndRoles(1) & Inst::OpndRole_Use);
+    assert(inst->getOpndRoles(2) & Inst::OpndRole_Use);
+    Opnd* dst = inst->getOpnd(0);
+    Opnd* src1 = inst->getOpnd(1);
+    Opnd* src2 = inst->getOpnd(2);
+    assert(dst && src1 && src2);
+
+    bool inline_rem64 = true;
+    getArg("inline_rem64", inline_rem64);
+
+    if (!inline_rem64) {
+        Opnd * args[2]={ src1, src2 };
+        CallInst * callInst = irManager->newInternalRuntimeHelperCallInst("irem64", 2, args, dst);
+        callInst->insertBefore(inst);
+        processOpnds(callInst);
+        inst->unlink();
+        return;
+    }
+    inlineDivRem64(true, inst);
+}
+
+void I8Lowerer::inlineDivRem64(bool wantReminder, Inst* inst)
+{
+    assert(inst->getOpndRoles(0) & Inst::OpndRole_Def);
+    assert(inst->getOpndRoles(1) & Inst::OpndRole_Use);
+    assert(inst->getOpndRoles(2) & Inst::OpndRole_Use);
+    Opnd* dst = inst->getOpnd(0);
+    Opnd* src1 = inst->getOpnd(1);
+    Opnd* src2 = inst->getOpnd(2);
+    
+    Opnd * res_lo = NULL, * res_hi = NULL;
+    Opnd * a_lo = NULL, * a_hi = NULL;
+    Opnd * b_lo = NULL, * b_hi = NULL;
+
+    prepareNewOpnds(dst,  res_lo, res_hi);
+    prepareNewOpnds(src1, a_lo, a_hi);
+    prepareNewOpnds(src2, b_lo, b_hi);
+
+    //
+    TypeManager& tm = irManager->getTypeManager();
+    Type* int32type = tm.getInt32Type();
+    
+    Opnd* edx = irManager->newOpnd(int32type);
+    Opnd* eax = irManager->newOpnd(int32type);
+    Opnd* ecx = irManager->newOpnd(int32type);
+    Opnd* ebx = irManager->newOpnd(int32type);
+    Opnd* edi = irManager->newOpnd(int32type);
+    Opnd* esi = irManager->newOpnd(int32type);
+
+    Opnd* temp_lo = irManager->newOpnd(int32type);
+    Opnd* temp_hi = irManager->newOpnd(int32type);
+    Opnd* zero = irManager->newImmOpnd(int32type, 0);
+    Opnd* one = irManager->newImmOpnd(int32type, 1);
+    //
+
+    newSubGFG();
+    
+    Node* entryNode = getSubCfgEntryNode();
+    Node* check_A_SignNode = newBB();
+    Node* neg_A_Node = newBB();
+    Node* check_B_SignNode = newBB();
+    Node* neg_B_Node = newBB();
+    
+    Node* testBigDvsrNode = newBB();
+    Node* testOneDivNode = newBB();
+    Node* simpleDivNode = newBB();
+    Node* oneDivNode = newBB();
+    Node* bigDivisorNode = newBB();
+    Node* storeResultNode = newBB();
+    
+    //
+    // Here we go.
+    // The algorithm is based on unsigned div algo from assembly gems page
+    // http://www.df.lth.se/~john_e/gems/gem002a.html (also published in AMD 
+    // optimization manual)  and modified for signed arithmetics and for 
+    // the Jitrino CG specifics.
+    //
+
+    //
+    // entryNode:
+    //
+    // Preparation - load all into 'registers'
+    //
+
+    Opnd* fixQuotSign = irManager->newOpnd(int32type);
+    Opnd* fixRemSign = irManager->newOpnd(int32type);
+                        // Sign presumed positive
+    setCurrentNode(entryNode);
+    /* mov fixQuotSign, 0*/ newInst(Mnemonic_MOV, fixQuotSign, zero);
+    /* mov fixRemSign, 0*/  newInst(Mnemonic_MOV, fixRemSign, zero);
+    
+    /* mov edx, a_hi*/  newInst(Mnemonic_MOV, edx, a_hi);
+    /* mov eax, a_lo*/  newInst(Mnemonic_MOV, eax, a_lo);
+    /* mov ecx, b_hi*/  newInst(Mnemonic_MOV, ecx, b_hi);
+    /* mov ebx, b_lo*/  newInst(Mnemonic_MOV, ebx, b_lo);
+    connectNodeTo(check_A_SignNode);
+    setCurrentNode(NULL);
+    entryNode = (Node*)0xDEADBEEF;
+
+    //
+    // check_A_SignNode:
+    //
+    // Test for signs and convert to unsigned when needed
+    // 
+
+    setCurrentNode(check_A_SignNode);
+    /* test edx, edx*/ newInst(Mnemonic_TEST, edx, edx);
+    /* jns  check_B_Sign*/ newBranch(Mnemonic_JNS, check_B_SignNode, neg_A_Node);
+    setCurrentNode(NULL);
+    check_A_SignNode = (Node*)0xDEADBEEF;
+
+    //
+    // neg_A:
+    //
+    //
+
+    setCurrentNode(neg_A_Node);
+    /* mov fixQuotSign, 1*/ newInst(Mnemonic_MOV, fixQuotSign, one);
+    /* mov fixRemSign, 1*/  newInst(Mnemonic_MOV, fixRemSign, one);
+    /* neg eax      */  newInst(Mnemonic_NEG, 1, eax, eax);
+    /* adc edx, 0   */  newInst(Mnemonic_ADC, 1, edx, edx, zero);
+    /* neg edx      */  newInst(Mnemonic_NEG, 1, edx, edx);
+    connectNodeTo(check_B_SignNode);
+    setCurrentNode(NULL);
+    neg_A_Node = (Node*)0xDEADBEEF;
+
+    //
+    // check_B_Sign_Node:
+    //
+    setCurrentNode(check_B_SignNode);
+    /* test ecx, ecx*/  newInst(Mnemonic_TEST, ecx, ecx);
+    /* jns  testBigDvsrNode*/ newBranch(Mnemonic_JNS, testBigDvsrNode, neg_B_Node);
+    setCurrentNode(NULL);
+    check_B_SignNode = (Node*)0xDEADBEEF;
+
+    //
+    // neg_B_Node:
+    //
+    // When doing REM, the result's sing only depends on 
+    // dividend's sign no need to change fixRemSign
+    
+    setCurrentNode(neg_B_Node);
+    /* XOR fixQuotSign, 1*/  newInst(Mnemonic_XOR, 1, fixQuotSign, fixQuotSign, one);
+    /* neg ebx      */  newInst(Mnemonic_NEG, 1, ebx, ebx);
+    /* adc ecx, 0   */  newInst(Mnemonic_ADC, 1, ecx, ecx, zero);
+    /* neg ecx      */  newInst(Mnemonic_NEG, 1, ecx, ecx);
+    connectNodeTo(testBigDvsrNode);
+    setCurrentNode(NULL);
+    neg_B_Node = (Node*)0xDEADBEEF;
+
+    //
+    // testBigDvsr:
+    //
+                        // divisor > 2^32-1 ?
+    setCurrentNode(testBigDvsrNode);
+    /* cmp ecx, 0   */  newInst(Mnemonic_CMP, ecx, zero); 
+                        // YES - proceed to the hard way.
+                        // NO - fall to the simpler path
+    /* jnz BIG_DVSOR*/  newBranch(Mnemonic_JNZ, bigDivisorNode, testOneDivNode);
+    setCurrentNode(NULL);
+    testBigDvsrNode = (Node*)0xDEADBEEF;
+
+    //
+    // testOneDivNode:
+    //
+    //
+                        //only one division needed ? (ecx = 0)
+    setCurrentNode(testOneDivNode);
+    /* cmp edx, ebx */  newInst(Mnemonic_CMP, edx, ebx);
+                        // YES - one division sufficient
+    /* jb ONE_DIV  */   newBranch(Mnemonic_JB, oneDivNode, simpleDivNode);
+    setCurrentNode(NULL);
+    testOneDivNode = (Node*)0xDEADBEEF;
+    
+    //
+    // simpleDivNode:
+    //
+
+    setCurrentNode(simpleDivNode);
+    /* mov ecx, eax */  newInst(Mnemonic_MOV, ecx, eax);     // save dividend-lo in ecx
+    /* mov eax, edx */  newInst(Mnemonic_MOV, eax, edx);     // get dividend-hi
+    /* xor edx, edx */  newInst(Mnemonic_MOV, edx, zero);    // zero extend it into edx:eax
+    /* div ebx      */  newInst(Mnemonic_DIV, 2, edx, eax, edx, eax, ebx); // quotient-hi in eax
+    /* xchg eax, ecx*/  newInst(Mnemonic_XCHG, eax, ecx);    //ecx = quotient-hi, eax =dividend-lo
+    connectNodeTo(oneDivNode);
+    setCurrentNode(NULL);
+    simpleDivNode = (Node*)0xDEADBEEF;
+
+    // 
+    // oneDivNode:
+    //
+
+    setCurrentNode(oneDivNode);
+    /* div ebx */       newInst(Mnemonic_DIV, 2, edx, eax, edx, eax, ebx);  // eax = quotient-lo
+    /* mov ebx, edx */  newInst(Mnemonic_MOV, ebx, edx);    // ebx = remainder-lo
+    /* mov edx, ecx */  newInst(Mnemonic_MOV, edx, ecx);    // edx = quotient-hi(quotient in edx:eax)
+    /* xor ecx, ecx */  newInst(Mnemonic_MOV, ecx, zero);   // ecx = remainder-hi (rem. in ecx:ebx)
+    /* jmp saveResult*/
+    connectNodeTo(storeResultNode);
+    setCurrentNode(NULL);
+    oneDivNode = (Node*)0xDEADBEEF;
+
+    //
+    // bigDivisorNode:
+    //
+    setCurrentNode(bigDivisorNode);
+    /* mov temp_hi, edx */  newInst(Mnemonic_MOV, temp_hi, edx);
+    /* mov temp_lo, eax */  newInst(Mnemonic_MOV, temp_lo, eax);    // save dividend
+    /* mov esi, ebx     */  newInst(Mnemonic_MOV, esi, ebx);
+    /* mov edi, ecx     */  newInst(Mnemonic_MOV, edi, ecx);
+                            // ^^^divisor now in edi:ebx and ecx:esi
+
+                            // shift both divisor and dividend right on 1 bit
+    /* shr edx, 1       */  newInst(Mnemonic_SHR, edx, one);
+    /* rcr eax, 1       */  newInst(Mnemonic_RCR, eax, one);
+    /* ror edi, 1       */  newInst(Mnemonic_ROR, edi, one);
+    /* rcr ebx, 1       */  newInst(Mnemonic_RCR, ebx, one);
+
+    //
+    // FIXME: workarounding WebMaker problem, which does not like 
+    // both DEF and USE of the same arg in the same instruction.
+    // Replace, 'reg = BSR reg, 0' with 
+    // temp = reg ; reg = BSR temp, 0
+    // Funny thing is that this only happens with BSR.
+    // 
+#if 0 // _FIXME_
+    /* bsr ecx, ecx  */     newInst(Mnemonic_BSR, 1, ecx, ecx);
+#else
+    Opnd* tmp = irManager->newOpnd(ecx->getType());
+    /* mov tmp, ecx  */     newInst(Mnemonic_MOV, 1, tmp, ecx);
+    /* bsr ecx, tmp  */     newInst(Mnemonic_BSR, 1, ecx, tmp);
+#endif
+                            // ecx = number of remaining shifts
+
+                            // scale divisor and dividend down, so divisor fits
+                            // into EBX (<2^32)
+    // FIXME: Currently, constraint resolver fails to assign 'ecx' operand to the 
+    // real ECX, and this causes SpillGen failure.
+    // Forcing the ECX right here:
+#if 0 //_FIXME_
+    /* shrd ebx, edi, CL*/  newInst(Mnemonic_SHRD, ebx, edi, ecx);
+    /* shrd eax, edx, CL*/  newInst(Mnemonic_SHRD, eax, edx, ecx);
+    /* shr  edx, CL   */    newInst(Mnemonic_SHR, edx, ecx);
+#else
+    Opnd* trueECX = irManager->getRegOpnd(RegName_ECX);
+    newInst(Mnemonic_MOV, trueECX, ecx);
+    //~FIXME
+    /* shrd ebx, edi, CL*/  newInst(Mnemonic_SHRD, ebx, edi, trueECX);
+    /* shrd eax, edx, CL*/  newInst(Mnemonic_SHRD, eax, edx, trueECX);
+    /* shr  edx, CL   */    newInst(Mnemonic_SHR, edx, trueECX);
+#endif
+    /* rol  edi, 1    */    newInst(Mnemonic_ROL, edi, one);
+                            // get quotient
+    /* div    ebx     */    newInst(Mnemonic_DIV, 2, edx, eax, edx, eax, ebx, NULL);
+    /* mov ebx, temp_lo*/   newInst(Mnemonic_MOV, ebx, temp_lo);
+    /* mov ecx, eax    */   newInst(Mnemonic_MOV, ecx, eax);
+    /* imul edi, eax   */   newInst(Mnemonic_IMUL, edi, eax);
+    /* mul  esi        */   newInst(Mnemonic_MUL, 2, edx, eax, eax, esi, NULL);
+    /* add edx, edi    */   newInst(Mnemonic_ADD, 1, edx, edx, edi);    // edx:eax = quotient * divisor
+    /* sub ebx, eax    */   newInst(Mnemonic_SUB, 1, ebx, ebx, eax);    // dividend-lo - (quot.*divisor)-lo
+    /* mov eax, ecx    */   newInst(Mnemonic_MOV, eax, ecx);
+    /* mov ecx, temp_hi*/   newInst(Mnemonic_MOV, ecx, temp_hi);        // restore dividend hi-word
+    /* sbb ecx, edx    */   newInst(Mnemonic_SBB, 1, ecx, ecx, edx);    // subtract divisor * quot. from dividend
+    /* sbb edx, edx    */   newInst(Mnemonic_SBB, 1, edx, edx, edx);    // 0 if remainder > 0, else FFFFFFFFh
+    /* and esi, edx    */   newInst(Mnemonic_AND, 1, esi, esi, edx);    // nothing to add
+    /* and edi, edx    */   newInst(Mnemonic_AND, 1, edi, edi, edx);    // back if remainder positive
+    /* add ebx, esi    */   newInst(Mnemonic_ADD, 1, ebx, ebx, esi);    // correct remainder
+    /* adc ecx, edi    */   newInst(Mnemonic_ADC, 1, ecx, ecx, edi);    // and quotient if
+    /* add eax, edx    */   newInst(Mnemonic_ADD, 1, eax, eax, edx);    // necessary
+    /* xor edx, edx    */   newInst(Mnemonic_MOV, edx, zero);           // clear hi-word of quot (eax<=FFFFFFFFh)
+    
+    connectNodeTo(storeResultNode);
+    setCurrentNode(NULL);
+    bigDivisorNode = (Node*)0xDEADBEEF;
+
+    Node* testFixQuotSignNode = newBB();
+    Node* fixQuotSignNode = newBB();
+    Node* testFixRemSignNode = newBB();
+    Node* fixRemSignNode = newBB();
+    Node* finitaNode = newBB();
+
+    //
+    // storeResultNode:
+    // 
+    Opnd* quot_lo = irManager->newOpnd(int32type);
+    Opnd* quot_hi = irManager->newOpnd(int32type);
+    Opnd* rem_lo = irManager->newOpnd(int32type);
+    Opnd* rem_hi = irManager->newOpnd(int32type);
+    
+    setCurrentNode(storeResultNode);
+    /* mov rem_lo, ebx*/    newInst(Mnemonic_MOV, rem_lo, ebx);
+    /* mov rem_hi, ecx*/    newInst(Mnemonic_MOV, rem_hi, ecx);
+    /* mov quot_lo, eax*/   newInst(Mnemonic_MOV, quot_lo, eax);
+    /* mov quot_hi, edx*/   newInst(Mnemonic_MOV, quot_hi, edx);
+    connectNodeTo(testFixQuotSignNode);
+    setCurrentNode(NULL);
+    storeResultNode = (Node*)0xDEADBEEF;
+
+    //
+    // testFixQuotSignNode:
+    //
+    //
+    setCurrentNode(testFixQuotSignNode);
+    /* cmp fixQuotSign, 0  */   newInst(Mnemonic_CMP, fixQuotSign, zero);
+    /* jz testFixRemSignNode */ newBranch(Mnemonic_JZ, testFixRemSignNode, fixQuotSignNode);
+    setCurrentNode(NULL);
+    testFixQuotSignNode = (Node*)0xDEADBEEF;
+
+    //
+    // fixQuotSignNode:
+    //
+    setCurrentNode(fixQuotSignNode);
+    /* neg res_lo      */  newInst(Mnemonic_NEG, 1, quot_lo, quot_lo);
+    /* adc res_hi, 0   */  newInst(Mnemonic_ADC, 1, quot_hi, quot_hi, zero);
+    /* neg res_lo      */  newInst(Mnemonic_NEG, 1, quot_hi, quot_hi);
+    connectNodeTo(testFixRemSignNode);
+    setCurrentNode(NULL);
+    fixQuotSignNode = (Node*)0xDEADBEEF;
+
+    //
+    // testFixRemSignNode:
+    //
+    //
+    setCurrentNode(testFixRemSignNode);
+    /* cmp fixRemSign, 0  */    newInst(Mnemonic_CMP, fixRemSign, zero);
+    /* jz finitaNode */         newBranch(Mnemonic_JZ, finitaNode, fixRemSignNode);
+    setCurrentNode(NULL);
+    testFixQuotSignNode = (Node*)0xDEADBEEF;
+
+    //
+    // fixRemSignNode:
+    //
+    setCurrentNode(fixRemSignNode);
+    /* neg res_lo      */  newInst(Mnemonic_NEG, 1, rem_lo, rem_lo);
+    /* adc res_hi, 0   */  newInst(Mnemonic_ADC, 1, rem_hi, rem_hi, zero);
+    /* neg res_lo      */  newInst(Mnemonic_NEG, 1, rem_hi, rem_hi);
+    connectNodeTo(finitaNode);
+    setCurrentNode(NULL);
+    fixQuotSignNode = (Node*)0xDEADBEEF;
+
+    //
+    // finitaNode:
+    //
+    setCurrentNode(finitaNode);
+    if (wantReminder) {
+        /* mov res_lo, rem_lo*/  newInst(Mnemonic_MOV, res_lo, rem_lo);
+        /* mov res_hi, rem_hi*/  newInst(Mnemonic_MOV, res_hi, rem_hi);
+    }
+    else {
+        /* mov res_lo, quot_lo*/  newInst(Mnemonic_MOV, res_lo, quot_lo);
+        /* mov res_hi, quot_hi*/  newInst(Mnemonic_MOV, res_hi, quot_hi);
+    }
+    connectNodes(finitaNode, getSubCfgReturnNode());
+    setCurrentNode(NULL);
+    finitaNode = (Node*)0xDEADBEEF;
+
+    Node* originalInstNode = inst->getNode();
+    propagateSubCFG(inst);
+    propagateDivRemResults(inst, originalInstNode, quot_lo, quot_hi, rem_lo, rem_hi);
+}
+
+void I8Lowerer::propagateDivRemResults(
+    Inst* origInst, Node* originalInstNode,
+    Opnd* quot_lo, Opnd* quot_hi,
+    Opnd* rem_lo, Opnd* rem_hi)
+{
+
+    bool propagate_div_rem = false; //FIXME: somehow crashes on Linux/IA-32 in dominators - need to fix.
+    getArg("propagate_div_rem", propagate_div_rem);
+    if (!propagate_div_rem) {
+        return;
+    }
+
+    assert(origInst->getOpndRoles(0) & Inst::OpndRole_Def);
+    assert(origInst->getOpndRoles(1) & Inst::OpndRole_Use);
+    assert(origInst->getOpndRoles(2) & Inst::OpndRole_Use);
+    Opnd* src1 = origInst->getOpnd(1);
+    Opnd* src2 = origInst->getOpnd(2);
+    if (!isSingleDef(src1) || !isSingleDef(src2)) {
+        // Not a single def operands - can't propagate with current 
+        // trivial implementation, need more sophisticated routine.
+        return;
+    }
+
+    ControlFlowGraph* cfg = irManager->getFlowGraph();
+    DominatorTree* dt = cfg->getDominatorTree();
+
+    INST_ARRAY& i8insts = *m_pI8Insts;
+    for (INST_ARRAY::iterator i=i8insts.begin(); i != i8insts.end(); i++) {
+        Inst* inst = *i;
+        if (inst == origInst || inst == NULL) {
+            continue;
+        }
+        if (!inst->hasKind(Inst::Kind_I8PseudoInst) || 
+            inst->getMnemonic() != Mnemonic_IDIV) {
+            continue;
+        }
+        assert(inst->getOpndRoles(0) & Inst::OpndRole_Def);
+        assert(inst->getOpndRoles(1) & Inst::OpndRole_Use);
+        assert(inst->getOpndRoles(2) & Inst::OpndRole_Use);
+        Opnd* otherSrc1 = origInst->getOpnd(1);
+        Opnd* otherSrc2 = origInst->getOpnd(2);
+        if (otherSrc1 != src1 || otherSrc2 != src2) {
+            continue;
+        }
+        //
+        // Test whether both instructions belong to the same loop
+        //
+        Node* origNodeLoopHdr = (*m_pLoopInfos)[origInst];
+        Node* instLoopHdr = (*m_pLoopInfos)[inst];
+        if (origNodeLoopHdr != instLoopHdr)  {
+            continue;
+        }
+        //
+        // Test whether one instruction dominates another
+        // 
+        Node* instNode = inst->getNode();
+        if (!dt->dominates(originalInstNode, instNode)) {
+            continue;
+        }
+        Log::out() << "Propagating: I" << origInst->getId() << " => I" << inst->getId() << std::endl;
+        Opnd* otherDst = inst->getOpnd(0);
+        Opnd* otherDst_hi, *otherDst_lo;
+        prepareNewOpnds(otherDst, otherDst_lo, otherDst_hi);
+        const bool isRem = isI8RemInst(inst);
+        Inst* ii;
+        ii = irManager->newCopyPseudoInst(Mnemonic_MOV, otherDst_lo, isRem ? rem_lo : quot_lo);
+        ii->insertBefore(inst);
+        ii = irManager->newCopyPseudoInst(Mnemonic_MOV, otherDst_hi, isRem ? rem_hi : quot_hi);
+        ii->insertBefore(inst);
+        inst->unlink();
+        *i = NULL;
     }
 }
 
 }}
+

Modified: harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32IRManager.cpp
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32IRManager.cpp?view=diff&rev=478172&r1=478171&r2=478172
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32IRManager.cpp (original)
+++ harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32IRManager.cpp Wed Nov 22 06:32:28 2006
@@ -25,6 +25,7 @@
 #include "Log.h"
 #include "Ia32Printer.h"
 #include "Ia32CodeGenerator.h"
+#include "Dominator.h"
 #include "float.h"
 #include <math.h>
 
@@ -422,7 +423,7 @@
     if (opnd0!=NULL){       opnds[i] = opnd0; i++;
     if (opnd1!=NULL){       opnds[i] = opnd1; i++;
     if (opnd2!=NULL){       opnds[i] = opnd2; i++;
-    if (opnd3!=NULL){       opnds[i] = opnd3; i++;      assert(opnd3->getSize()==OpndSize_64);
+    if (opnd3!=NULL){       opnds[i] = opnd3; i++;
     }}}};   
     inst->defOpndCount=defCount;
     inst->opndCount = i;
@@ -2204,6 +2205,21 @@
         printDot(subKind);
         printDot(subKind, "liveness");
     }
+}
+
+void SessionAction::computeDominators(void)
+{
+    ControlFlowGraph* cfg = irManager->getFlowGraph();
+    DominatorTree* dominatorTree = cfg->getDominatorTree();
+    if(dominatorTree != NULL && dominatorTree->isValid()) {
+        // Already valid.
+        return;
+    }
+    static CountTime computeDominatorsTimer("ia32::helper::computeDominators");
+    AutoTimer tm(computeDominatorsTimer);
+    DominatorBuilder db;
+    dominatorTree = db.computeDominators(irManager->getMemoryManager(), cfg,false,true);
+    cfg->setDominatorTree(dominatorTree);
 }
 
 

Modified: harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32IRManager.h
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32IRManager.h?view=diff&rev=478172&r1=478171&r2=478172
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32IRManager.h (original)
+++ harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32IRManager.h Wed Nov 22 06:32:28 2006
@@ -617,7 +617,10 @@
 
     Optional, defaults to all possible side effects */
     virtual uint32 getSideEffects()const;
-
+    /**
+     * Forces dominator tree to be valid
+     */
+    void computeDominators(void);
     virtual bool verify(bool force=false);
 
     virtual void debugOutput(const char * subKind);

Modified: harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp?view=diff&rev=478172&r1=478171&r2=478172
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp (original)
+++ harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp Wed Nov 22 06:32:28 2006
@@ -804,13 +804,22 @@
             srcOpnd2=(Opnd*)convert(src2, dstType);
 
 #ifndef _EM64T_
+            //
+            // NOTE: as we don't have IREM mnemonic, then generate I8Inst 
+            // with IDIV mnemonic. The 4th fake non-zero argument means 
+            // what we really need REM, not DIV.
+            // This is handled specially in I8Lowerer. 
+            // The scheme with the fake arg looks ugly, might need to 
+            // reconsider.
+            //
+            Opnd* fakeReminderFlag = NULL;
             if (rem) {
-                Opnd * args[]={ srcOpnd1, srcOpnd2 };
-                CallInst * callInst=irManager.newRuntimeHelperCallInst(CompilationInterface::Helper_RemI64, 2, args, dst);
-                appendInsts(callInst);
-            } else {
-                appendInsts(irManager.newI8PseudoInst(Mnemonic_IDIV, 1, dst,srcOpnd1,srcOpnd2));
+                Type* int32type = irManager.getTypeFromTag(Type::Int32);
+                fakeReminderFlag = irManager.newImmOpnd(int32type, 12345678);
             }
+            Inst* ii = irManager.newI8PseudoInst(Mnemonic_IDIV, 1, dst, srcOpnd1, srcOpnd2, fakeReminderFlag);
+            appendInsts(ii);
+            
 #else
             Opnd * dstOpnd0=irManager.newOpnd(dstType);
             Opnd * dstOpnd1=irManager.newOpnd(dstType);

Modified: harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32Printer.cpp
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32Printer.cpp?view=diff&rev=478172&r1=478171&r2=478172
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32Printer.cpp (original)
+++ harmony/enhanced/drlvm/trunk/vm/jitrino/src/codegenerator/ia32/Ia32Printer.cpp Wed Nov 22 06:32:28 2006
@@ -324,6 +324,9 @@
 
     if (inst->hasKind(Inst::Kind_PseudoInst)){
         os<<getPseudoInstPrintName(inst->getKind());
+        if (inst->getMnemonic() != Mnemonic_Null) {
+            os<< "/" << Encoder::getMnemonicString(inst->getMnemonic());
+        }
     }else{
         if( inst->getMnemonic() != Mnemonic_Null )
             os<< Encoder::getMnemonicString( inst->getMnemonic() );

Modified: harmony/enhanced/drlvm/trunk/vm/port/src/encoder/ia32_em64t/enc_defs.h
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/port/src/encoder/ia32_em64t/enc_defs.h?view=diff&rev=478172&r1=478171&r2=478172
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/port/src/encoder/ia32_em64t/enc_defs.h (original)
+++ harmony/enhanced/drlvm/trunk/vm/port/src/encoder/ia32_em64t/enc_defs.h Wed Nov 22 06:32:28 2006
@@ -407,6 +407,9 @@
 Mnemonic_ADDSD,                         // Add Scalar Double-Precision Floating-Point Values
 Mnemonic_ADDSS,                         // Add Scalar Single-Precision Floating-Point Values
 Mnemonic_AND,                           // Logical AND
+
+Mnemonic_BSR,                           // Bit scan reverse
+
 Mnemonic_CALL,                          // Call Procedure
 Mnemonic_CWD, Mnemonic_CDQ=Mnemonic_CWD,// Convert Word to Doubleword/Convert Doubleword to Qua T dword
 Mnemonic_CMOVcc,                        // Conditional Move
@@ -484,6 +487,7 @@
 Mnemonic_FSTP,                          // Store Floating Point Value and pop the FP stack
 
 Mnemonic_XCHG,
+Mnemonic_DIV,                           // Unsigned Divide
 Mnemonic_IDIV,                          // Signed Divide
 Mnemonic_MUL,                           // Unsigned Multiply
 Mnemonic_IMUL,                          // Signed Multiply
@@ -513,8 +517,12 @@
 Mnemonic_LOOPNE, Mnemonic_LOOPNZ = Mnemonic_LOOPNE, // Loop according to ECX 
 Mnemonic_LAHF,                          // Load Flags into AH
 Mnemonic_MOV,                           // Move
-Mnemonic_MOVQ,                          // Move Quadword
 Mnemonic_MOVD,                          // Move Double word
+Mnemonic_MOVQ,                          // Move Quadword
+/*Mnemonic_MOVS,                          // Move Data from String to String*/
+// MOVS is a special case: see encodign table for more details,
+Mnemonic_MOVS8, Mnemonic_MOVS16, Mnemonic_MOVS32,
+//
 Mnemonic_MOVSD,                         // Move Scalar Double-Precision Floating-Point Value
 Mnemonic_MOVSS,                         // Move Scalar Single-Precision Floating-Point Values
 Mnemonic_MOVSX,                         // Move with Sign-Extension
@@ -562,6 +570,9 @@
 Mnemonic_SAL, Mnemonic_SHL=Mnemonic_SAL,// Shift left
 Mnemonic_SAR,                           // Unsigned shift right
 Mnemonic_ROR,                           // Rotate right
+Mnemonic_RCR,                           // Rotate right through CARRY flag
+Mnemonic_ROL,                           // Rotate left
+Mnemonic_RCL,                           // Rotate left through CARRY flag
 Mnemonic_SHR,                           // Signed shift right
 Mnemonic_SHRD,                          // Double Precision Shift Right
 Mnemonic_SHLD,                          // Double Precision Shift Left

Modified: harmony/enhanced/drlvm/trunk/vm/port/src/encoder/ia32_em64t/enc_tabl.cpp
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/port/src/encoder/ia32_em64t/enc_tabl.cpp?view=diff&rev=478172&r1=478171&r2=478172
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/port/src/encoder/ia32_em64t/enc_tabl.cpp (original)
+++ harmony/enhanced/drlvm/trunk/vm/port/src/encoder/ia32_em64t/enc_tabl.cpp Wed Nov 22 06:32:28 2006
@@ -276,20 +276,29 @@
     unsigned short hash = 0;
     // The hash computation, uses fast way - table selection instead of if-s.
     if (odesc->roles.count > 0) {
-        hash = kind_hash[odesc->opnds[0].kind] | 
-               size_hash[odesc->opnds[0].size];
+        OpndKind kind = odesc->opnds[0].kind;
+        OpndSize size = odesc->opnds[0].size;
+        assert(kind<COUNTOF(kind_hash));
+        assert(size<COUNTOF(size_hash));
+        hash = kind_hash[kind] | size_hash[size];
     }
 
     if (odesc->roles.count > 1) {
+        OpndKind kind = odesc->opnds[1].kind;
+        OpndSize size = odesc->opnds[1].size;
+        assert(kind<COUNTOF(kind_hash));
+        assert(size<COUNTOF(size_hash));
         hash = (hash<<HASH_BITS_PER_OPERAND) | 
-               (kind_hash[odesc->opnds[1].kind] | 
-                size_hash[odesc->opnds[1].size]);
+               (kind_hash[kind] | size_hash[size]);
     }
 
     if (odesc->roles.count > 2) {
+        OpndKind kind = odesc->opnds[2].kind;
+        OpndSize size = odesc->opnds[2].size;
+        assert(kind<COUNTOF(kind_hash));
+        assert(size<COUNTOF(size_hash));
         hash = (hash<<HASH_BITS_PER_OPERAND) | 
-               (kind_hash[odesc->opnds[2].kind] | 
-                size_hash[odesc->opnds[2].size]);
+               (kind_hash[kind] | size_hash[size]);
     }
     assert(hash <= HASH_MAX);
     return hash;
@@ -411,12 +420,12 @@
 END_OPCODES()
 END_MNEMONIC()
 
-BEGIN_MNEMONIC(CMPXCHG, MF_AFFECTS_FLAGS, N)
+BEGIN_MNEMONIC(CMPXCHG, MF_NONE, DU_DU )
 BEGIN_OPCODES()
-    {OpcodeInfo::all, {0x0F, 0xB0, _r},         {r_m8, r8, AL},     DU_DU_DU },
-    {OpcodeInfo::all, {Size16, 0x0F, 0xB1, _r}, {r_m16, r16, AX},   DU_DU_DU },
-    {OpcodeInfo::all, {0x0F, 0xB1, _r},         {r_m32, r32, EAX},   DU_DU_DU},
-    {OpcodeInfo::em64t, {REX_W, 0x0F, 0xB1, _r},{r_m64, r64, RAX},   DU_DU_DU },
+    {OpcodeInfo::all, {0x0F, 0xB0, _r},         {r_m8, r8},     DU_DU },
+    {OpcodeInfo::all, {Size16, 0x0F, 0xB1, _r}, {r_m16, r16},   DU_DU },
+    {OpcodeInfo::all, {0x0F, 0xB1, _r},         {r_m32, r32},   DU_DU },
+    {OpcodeInfo::em64t, {REX_W, 0x0F, 0xB1, _r},{r_m64, r64},   DU_DU },
 END_OPCODES()
 END_MNEMONIC()
 
@@ -436,6 +445,14 @@
 END_OPCODES()
 END_MNEMONIC()
 
+
+BEGIN_MNEMONIC(BSR, MF_AFFECTS_FLAGS, N)
+BEGIN_OPCODES()
+    {OpcodeInfo::all, {0x0F, 0xBD},   {r32, r_m32},   D_U},
+END_OPCODES()
+END_MNEMONIC()
+
+
 BEGIN_MNEMONIC(CALL, MF_NONE, U )
 BEGIN_OPCODES()
     {OpcodeInfo::all,     {0xE8, cd},        {rel32},     U },
@@ -703,6 +720,12 @@
 // ~ FPU
 //
 
+BEGIN_MNEMONIC(DIV, MF_AFFECTS_FLAGS, DU_DU_U)
+BEGIN_OPCODES()
+    {OpcodeInfo::all,   {0xF7, _6},         {EDX, EAX, r_m32},  DU_DU_U },
+END_OPCODES()
+END_MNEMONIC()
+
 BEGIN_MNEMONIC(IDIV, MF_AFFECTS_FLAGS, DU_DU_U)
 BEGIN_OPCODES()
 #if !defined(_EM64T_)
@@ -711,15 +734,19 @@
 #endif
     {OpcodeInfo::all,   {0xF7, _7},         {EDX, EAX, r_m32},  DU_DU_U },
     {OpcodeInfo::em64t, {REX_W, 0xF7, _7},  {RDX, RAX, r_m64},  DU_DU_U },
-END_OPCODES()
+    END_OPCODES()
 END_MNEMONIC()
 
+
 BEGIN_MNEMONIC(IMUL, MF_AFFECTS_FLAGS, D_DU_U)
 BEGIN_OPCODES()
     /*{OpcodeInfo::all,   {0xF6, _5},               {AH, AL,        r_m8},  D_DU_U },
     {OpcodeInfo::all,     {Size16, 0xF7, _5},       {DX, AX,        r_m16}, D_DU_U },
-    {OpcodeInfo::all,     {0xF7, _5},               {EDX, EAX,      r_m32}, D_DU_U },
-    {OpcodeInfo::em64t,   {REX_W, 0xF7, _5},        {RDX, RAX,      r_m64}, D_DU_U },*/
+    */
+    //
+    {OpcodeInfo::all,     {0xF7, _5},               {EDX, EAX, r_m32},  D_DU_U },
+    {OpcodeInfo::em64t,   {REX_W, 0xF7, _5},        {RDX, RAX, r_m64},  D_DU_U },
+    //
     {OpcodeInfo::all,     {Size16, 0x0F, 0xAF, _r}, {r16,r_m16},        DU_U },
     {OpcodeInfo::all,     {0x0F, 0xAF, _r},         {r32,r_m32},        DU_U },
     {OpcodeInfo::em64t,   {REX_W, 0x0F, 0xAF, _r},  {r64,r_m64},        DU_U },
@@ -737,10 +764,10 @@
 
 BEGIN_MNEMONIC(MUL, MF_AFFECTS_FLAGS, U )
 BEGIN_OPCODES()
-    {OpcodeInfo::all,     {0xF6, _4},           {r_m8},            U },
-    {OpcodeInfo::all,     {Size16, 0xF7, _4},   {r_m16},           U },
-    {OpcodeInfo::all,     {0xF7, _4},           {r_m32},           U },
-    {OpcodeInfo::em64t,   {REX_W, 0xF7, _4},    {r_m64},           U },
+    {OpcodeInfo::all,     {0xF6, _4},           {AX, AL, r_m8},     D_DU_U },
+    {OpcodeInfo::all,     {Size16, 0xF7, _4},   {DX, AX, r_m16},    D_DU_U },
+    {OpcodeInfo::all,     {0xF7, _4},           {EDX, EAX, r_m32},  D_DU_U },
+    {OpcodeInfo::em64t,   {REX_W, 0xF7, _4},    {RDX, RAX, r_m64},  D_DU_U },
 END_OPCODES()
 END_MNEMONIC()
 
@@ -1097,8 +1124,8 @@
 
 #undef DEFINE_SETcc_MNEMONIC
 
-#define DEFINE_SHIFT_MNEMONIC( nam, slash_num ) \
-BEGIN_MNEMONIC(nam, MF_AFFECTS_FLAGS, DU_U) \
+#define DEFINE_SHIFT_MNEMONIC(nam, slash_num, flags) \
+BEGIN_MNEMONIC(nam, flags, DU_U) \
 BEGIN_OPCODES()\
 /*  {OpcodeInfo::all,   {0xD0, slash_num},              {r_m8,  const_1},   DU_U },*/\
     {OpcodeInfo::all,   {0xD2, slash_num},              {r_m8,  CL},        DU_U },\
@@ -1119,23 +1146,28 @@
 END_OPCODES()\
 END_MNEMONIC()
 
-DEFINE_SHIFT_MNEMONIC(SAL, _4)
-DEFINE_SHIFT_MNEMONIC(SAR, _7)
-DEFINE_SHIFT_MNEMONIC(SHR, _5)
-DEFINE_SHIFT_MNEMONIC(ROR, _1)
+
+DEFINE_SHIFT_MNEMONIC(ROL, _0, MF_AFFECTS_FLAGS)
+DEFINE_SHIFT_MNEMONIC(ROR, _1, MF_AFFECTS_FLAGS)
+DEFINE_SHIFT_MNEMONIC(RCL, _2, MF_AFFECTS_FLAGS|MF_USES_FLAGS)
+DEFINE_SHIFT_MNEMONIC(RCR, _3, MF_AFFECTS_FLAGS|MF_USES_FLAGS)
+
+DEFINE_SHIFT_MNEMONIC(SAL, _4, MF_AFFECTS_FLAGS)
+DEFINE_SHIFT_MNEMONIC(SHR, _5, MF_AFFECTS_FLAGS)
+DEFINE_SHIFT_MNEMONIC(SAR, _7, MF_AFFECTS_FLAGS)
 
 #undef DEFINE_SHIFT_MNEMONIC
+
 BEGIN_MNEMONIC(SHLD, MF_AFFECTS_FLAGS, N)
-// TODO: the def/use info is worng
 BEGIN_OPCODES()
-    {OpcodeInfo::all,     {0x0F, 0xA5},   {r_m32, r32, CL}, DU_DU_U },
+    {OpcodeInfo::all,     {0x0F, 0xA5},   {r_m32, r32, ECX}, DU_DU_U },
 END_OPCODES()
 END_MNEMONIC()
 
 BEGIN_MNEMONIC(SHRD, MF_AFFECTS_FLAGS, N)
 // TODO: the def/use info is wrong
 BEGIN_OPCODES()
-    {OpcodeInfo::all,     {0x0F, 0xAD},   {r_m32, r32, CL}, DU_DU_U },
+    {OpcodeInfo::all,     {0x0F, 0xAD},   {r_m32, r32, ECX}, DU_DU_U },
 END_OPCODES()
 END_MNEMONIC()
 
@@ -1272,6 +1304,34 @@
 END_OPCODES()
 END_MNEMONIC()
 
+/*
+MOVS is a special case. 
+Most the code in both CG and Encoder do not expect 2 memory operands. 
+Also, they are not supposed to setup constrains on which register the 
+memory reference must reside - m8,m8 or m32,m32 is not the choice.
+We can't use r8,r8 either - will have problem with 8bit EDI, ESI.
+So, as the workaround we do r32,r32 and specify size of the operand through
+the specific mnemonic - the same is in the codegen.
+*/
+BEGIN_MNEMONIC(MOVS8, MF_NONE, DU_DU_DU)
+BEGIN_OPCODES()
+    {OpcodeInfo::ia32,  {0xA4},         {r32,r32,ECX},    DU_DU_DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(MOVS16, MF_NONE, DU_DU_DU)
+BEGIN_OPCODES()
+    {OpcodeInfo::ia32,  {Size16, 0xA5}, {r32,r32,ECX},  DU_DU_DU },
+END_OPCODES()
+END_MNEMONIC()
+
+BEGIN_MNEMONIC(MOVS32, MF_NONE, DU_DU_DU)
+BEGIN_OPCODES()
+    {OpcodeInfo::ia32,  {0xA5},         {r32,r32,ECX},  DU_DU_DU },
+END_OPCODES()
+END_MNEMONIC()
+
+
 BEGIN_MNEMONIC(WAIT, MF_AFFECTS_FLAGS, N)
 BEGIN_OPCODES()
     {OpcodeInfo::all,     {0x9B},         {},       N },
@@ -1353,7 +1413,7 @@
             unsigned opcod = oinfo.opcode[j];
             unsigned kind = opcod&OpcodeByteKind_KindMask;
             if (kind == OpcodeByteKind_REX_W) {
-              odesc.opcode[odesc.opcode_len++] = (unsigned char)0x48;
+                odesc.opcode[odesc.opcode_len++] = (unsigned char)0x48;
                 continue;
             }
             else if(kind != 0 && kind != OpcodeByteKind_ZeroOpcodeByte) {
@@ -1373,12 +1433,13 @@
                 assert((odesc.aux1 & OpcodeByteKind_KindMask) != 0);
             }
         }
-        else if (oinfo.roles.count==2) {
+        else if (oinfo.roles.count>=2) {
             if (((oinfo.opnds[0].kind&OpndKind_Mem) && 
                  (isRegKind(oinfo.opnds[1].kind))) ||
                 ((oinfo.opnds[1].kind&OpndKind_Mem) && 
                  (isRegKind(oinfo.opnds[0].kind)))) {
                  // Example: MOVQ xmm1, xmm/m64 has only opcodes
+                 // same with SHRD
                  // Adding fake /r
                  odesc.aux0 = _r;
             }
@@ -1430,7 +1491,8 @@
        
         //
         // check whether the operand info is a mask (i.e. r_m*).
-        // in this case, split the info to have separate entries for 'r' and for 'm'. 
+        // in this case, split the info to have separate entries for 'r' 
+        // and for 'm'.
         // the good news is that there can be only one such operand.
         // 
         int opnd2split = -1;

Modified: harmony/enhanced/drlvm/trunk/vm/port/src/encoder/ia32_em64t/encoder.inl
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/port/src/encoder/ia32_em64t/encoder.inl?view=diff&rev=478172&r1=478171&r2=478172
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/port/src/encoder/ia32_em64t/encoder.inl (original)
+++ harmony/enhanced/drlvm/trunk/vm/port/src/encoder/ia32_em64t/encoder.inl Wed Nov 22 06:32:28 2006
@@ -129,8 +129,6 @@
     EncoderBase::Operands args;
     add_rm(args, rm, sz);
     add_r(args, r, sz);
-    RegName implicitReg = getAliasReg(RegName_EAX, map_size(sz));
-    args.add(implicitReg);
     return (char*)EncoderBase::encode(stream, Mnemonic_CMPXCHG, args);
 }
 
@@ -252,6 +250,8 @@
 // multiply instructions: mul, imul
 ENCODER_DECLARE_EXPORT char * mul(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
     EncoderBase::Operands args;
+    args.add(RegName_EDX);
+    args.add(RegName_EAX);
     add_rm(args, rm, sz);
     return (char*)EncoderBase::encode(stream, Mnemonic_MUL, args);
 }



Mime
View raw message