265 lines
8.0 KiB
C++
265 lines
8.0 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (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.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
|
|
#include "Fundamentals.h"
|
|
#include "prbit.h"
|
|
|
|
#include "HPPAMul.h"
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------
|
|
*
|
|
* Local data for an HPPA proc. This should be obtained by asking the
|
|
* Code Generator to fill these arrays.
|
|
*
|
|
*-----------------------------------------------------------------------
|
|
*/
|
|
|
|
static PRInt16 shiftCosts[32] =
|
|
{
|
|
0, 4, 4, 4, 4, 4, 4, 4,
|
|
4, 4, 4, 4, 4, 4, 4, 4,
|
|
4, 4, 4, 4, 4, 4, 4, 4,
|
|
4, 4, 4, 4, 4, 4, 4, 4
|
|
};
|
|
|
|
static PRInt16 shiftAddCosts[32] =
|
|
{
|
|
4, 4, 4, 4, 999, 999, 999, 999,
|
|
999, 999, 999, 999, 999, 999, 999, 999,
|
|
999, 999, 999, 999, 999, 999, 999, 999,
|
|
999, 999, 999, 999, 999, 999, 999, 999
|
|
};
|
|
|
|
static PRInt16 shiftSubCosts[32] =
|
|
{
|
|
4, 999, 999, 999, 999, 999, 999, 999,
|
|
999, 999, 999, 999, 999, 999, 999, 999,
|
|
999, 999, 999, 999, 999, 999, 999, 999,
|
|
999, 999, 999, 999, 999, 999, 999, 999
|
|
};
|
|
|
|
static PRInt16 addCost = 4;
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------
|
|
*
|
|
* getMulAlgorithm --
|
|
*
|
|
* Return the best algorithm for an immediate multiplication.
|
|
* If algorithm.cost >= maxCost or retval is false then no algorithm
|
|
* was found and a regular multiplication should be used.
|
|
*
|
|
* This algorithm does not work if the register to multiply is larger
|
|
* than an PRUint32 and the multiplicand does not fit exactely in an PRUint32.
|
|
* e.g.: long long mul by a negative value.
|
|
*
|
|
*-----------------------------------------------------------------------
|
|
*/
|
|
bool
|
|
getMulAlgorithm(MulAlgorithm* algorithm, PRUint32 multiplicand, PRInt16 maxCost)
|
|
{
|
|
PRUint32 mask;
|
|
PRUint8 currentCost;
|
|
PRInt8 shiftBy;
|
|
|
|
algorithm->cost = maxCost;
|
|
if (maxCost <= 0)
|
|
return false;
|
|
|
|
if (multiplicand == 0x1)
|
|
{
|
|
algorithm->nOperations = 1;
|
|
algorithm->cost = 0;
|
|
algorithm->operations[0] = maMultiplicand;
|
|
return true;
|
|
}
|
|
|
|
if (multiplicand == 0x0)
|
|
{
|
|
algorithm->nOperations = 1;
|
|
algorithm->cost = 0;
|
|
algorithm->operations[0] = maZero;
|
|
return true;
|
|
}
|
|
|
|
MulAlgorithm* downAlgorithm = new MulAlgorithm();
|
|
MulAlgorithm* bestAlgorithm = new MulAlgorithm();
|
|
MulAlgorithm* swapAlgorithm;
|
|
|
|
// we try to do a shift if there is a group of 0 bits.
|
|
if ((multiplicand & 0x1) == 0x0)
|
|
{
|
|
// number of low zero bits.
|
|
mask = multiplicand & -multiplicand;
|
|
PR_FLOOR_LOG2(shiftBy, mask);
|
|
|
|
currentCost = shiftCosts[shiftBy];
|
|
getMulAlgorithm(downAlgorithm, multiplicand >> shiftBy, maxCost - currentCost);
|
|
currentCost += downAlgorithm->cost;
|
|
|
|
if (currentCost < maxCost)
|
|
{
|
|
swapAlgorithm = downAlgorithm, downAlgorithm = bestAlgorithm, bestAlgorithm = swapAlgorithm;
|
|
bestAlgorithm->shiftAmount[bestAlgorithm->nOperations] = shiftBy;
|
|
bestAlgorithm->operations[bestAlgorithm->nOperations] = maShiftValue;
|
|
maxCost = currentCost;
|
|
}
|
|
}
|
|
|
|
// If this is an odd number, we can try to add one or to subtract one.
|
|
if ((multiplicand & 0x1) != 0x0)
|
|
{
|
|
for (mask = 1; (mask & multiplicand) != 0x0; mask <<= 1);
|
|
|
|
if (mask > 2 && multiplicand != 3)
|
|
{
|
|
currentCost = addCost;
|
|
getMulAlgorithm(downAlgorithm, multiplicand + 1, maxCost - currentCost);
|
|
currentCost += downAlgorithm->cost;
|
|
|
|
if (currentCost < maxCost)
|
|
{
|
|
swapAlgorithm = downAlgorithm, downAlgorithm = bestAlgorithm, bestAlgorithm = swapAlgorithm;
|
|
bestAlgorithm->shiftAmount[bestAlgorithm->nOperations] = 0;
|
|
bestAlgorithm->operations[bestAlgorithm->nOperations] = maSubShiftMultiplicandFromValue;
|
|
maxCost = currentCost;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
currentCost = addCost;
|
|
getMulAlgorithm(downAlgorithm, multiplicand - 1, maxCost - currentCost);
|
|
currentCost += downAlgorithm->cost;
|
|
|
|
if (currentCost < maxCost)
|
|
{
|
|
swapAlgorithm = downAlgorithm, downAlgorithm = bestAlgorithm, bestAlgorithm = swapAlgorithm;
|
|
bestAlgorithm->shiftAmount[bestAlgorithm->nOperations] = 0;
|
|
bestAlgorithm->operations[bestAlgorithm->nOperations] = maAddValueToShiftMultiplicand;
|
|
maxCost = currentCost;
|
|
}
|
|
}
|
|
}
|
|
|
|
mask = multiplicand - 1;
|
|
PR_FLOOR_LOG2(shiftBy, mask);
|
|
while (shiftBy >= 2)
|
|
{
|
|
PRUint32 d;
|
|
|
|
d = (0x1 << shiftBy) + 1;
|
|
if (multiplicand % d == 0 && multiplicand > d)
|
|
{
|
|
currentCost = PR_MIN(shiftAddCosts[shiftBy], addCost + shiftCosts[shiftBy]);
|
|
getMulAlgorithm(downAlgorithm, multiplicand / d, maxCost - currentCost);
|
|
currentCost += downAlgorithm->cost;
|
|
|
|
if (currentCost < maxCost)
|
|
{
|
|
swapAlgorithm = downAlgorithm, downAlgorithm = bestAlgorithm, bestAlgorithm = swapAlgorithm;
|
|
bestAlgorithm->shiftAmount[bestAlgorithm->nOperations] = shiftBy;
|
|
bestAlgorithm->operations[bestAlgorithm->nOperations] = maAddValueToShiftValue;
|
|
maxCost = currentCost;
|
|
}
|
|
break;
|
|
}
|
|
|
|
d = (0x1 << shiftBy) - 1;
|
|
if (multiplicand % d == 0 && multiplicand > d)
|
|
{
|
|
currentCost = PR_MIN(shiftSubCosts[shiftBy], addCost + shiftCosts[shiftBy]);
|
|
getMulAlgorithm(downAlgorithm, multiplicand / d, maxCost - currentCost);
|
|
currentCost += downAlgorithm->cost;
|
|
|
|
if (currentCost < maxCost)
|
|
{
|
|
swapAlgorithm = downAlgorithm, downAlgorithm = bestAlgorithm, bestAlgorithm = swapAlgorithm;
|
|
bestAlgorithm->shiftAmount[bestAlgorithm->nOperations] = shiftBy;
|
|
bestAlgorithm->operations[bestAlgorithm->nOperations] = maSubValueFromShiftValue;
|
|
maxCost = currentCost;
|
|
}
|
|
break;
|
|
}
|
|
shiftBy--;
|
|
}
|
|
|
|
if ((multiplicand & 0x1) != 0x0)
|
|
{
|
|
mask = multiplicand - 1;
|
|
mask = mask & -mask;
|
|
if (mask != 0 && (mask & (mask - 1)) == 0)
|
|
{
|
|
PR_FLOOR_LOG2(shiftBy, mask);
|
|
currentCost = shiftAddCosts[shiftBy];
|
|
getMulAlgorithm(downAlgorithm, (multiplicand - 1) >> shiftBy, maxCost - currentCost);
|
|
currentCost += downAlgorithm->cost;
|
|
|
|
if (currentCost < maxCost)
|
|
{
|
|
swapAlgorithm = downAlgorithm, downAlgorithm = bestAlgorithm, bestAlgorithm = swapAlgorithm;
|
|
bestAlgorithm->shiftAmount[bestAlgorithm->nOperations] = shiftBy;
|
|
bestAlgorithm->operations[bestAlgorithm->nOperations] = maAddMultiplicandToShiftValue;
|
|
maxCost = currentCost;
|
|
}
|
|
}
|
|
|
|
mask = multiplicand + 1;
|
|
mask = mask & -mask;
|
|
if (mask != 0 && (mask & (mask - 1)) == 0)
|
|
{
|
|
PR_FLOOR_LOG2(shiftBy, mask);
|
|
currentCost = shiftSubCosts[shiftBy];
|
|
getMulAlgorithm(downAlgorithm, (multiplicand + 1) >> shiftBy, maxCost - currentCost);
|
|
currentCost += downAlgorithm->cost;
|
|
|
|
if (currentCost < maxCost)
|
|
{
|
|
swapAlgorithm = downAlgorithm, downAlgorithm = bestAlgorithm, bestAlgorithm = swapAlgorithm;
|
|
bestAlgorithm->shiftAmount[bestAlgorithm->nOperations] = shiftBy;
|
|
bestAlgorithm->operations[bestAlgorithm->nOperations] = maSubMultiplicandFromShiftValue;
|
|
maxCost = currentCost;
|
|
}
|
|
}
|
|
}
|
|
|
|
// No algorithm found.
|
|
if (maxCost == algorithm->cost)
|
|
return false;
|
|
|
|
// Too long
|
|
if (bestAlgorithm->nOperations == 32)
|
|
return false;
|
|
|
|
algorithm->nOperations = bestAlgorithm->nOperations + 1;
|
|
algorithm->cost = maxCost;
|
|
|
|
copy(bestAlgorithm->operations, &bestAlgorithm->operations[algorithm->nOperations], algorithm->operations);
|
|
copy(bestAlgorithm->shiftAmount, &bestAlgorithm->shiftAmount[algorithm->nOperations], algorithm->shiftAmount);
|
|
|
|
// we better find a way to avoid allocating memory each time.
|
|
delete downAlgorithm;
|
|
delete bestAlgorithm;
|
|
|
|
return true;
|
|
}
|