blob: a6c044364001327bf05b190472cc14a5f5a1bf2d [file] [log] [blame]
/********************************************************************
*
* BEGIN DATE: November, 2005
*
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
********************************************************************/
#include "stp/Simplifier/constantBitP/ConstantBitP_TransferFunctions.h"
#include "stp/Simplifier/constantBitP/ConstantBitP_Utility.h"
// FIXME: External library
#include "extlib-constbv/constantbv.h"
// Left shift, right shift.
// Trevor Hansen. BSD License.
// smtlib & x86 semantics differ for what happens when a value is shifted by
// greater
// than the bitWidth. On x86, in 64-bit mode, only the bottom 6 bits of the
// shift are
// used. In SMTLIB the total value is used.
namespace simplifier
{
namespace constantBitP
{
const bool debug_shift = false;
Result bvRightShiftBothWays(vector<FixedBits*>& children, FixedBits& output)
{
Result result = NO_CHANGE;
const unsigned bitWidth = output.getWidth();
assert(2 == children.size());
FixedBits& op = *children[0];
FixedBits& shift = *children[1];
FixedBits outputReverse(bitWidth, false);
FixedBits opReverse(bitWidth, false);
// Reverse the output and the input.
for (unsigned i = 0; i < bitWidth; i++)
{
if (op.isFixed(i))
{
opReverse.setFixed(bitWidth - 1 - i, true);
opReverse.setValue(bitWidth - 1 - i, op.getValue(i));
}
if (output.isFixed(i))
{
outputReverse.setFixed(bitWidth - 1 - i, true);
outputReverse.setValue(bitWidth - 1 - i, output.getValue(i));
}
}
vector<FixedBits*> args;
args.push_back(&opReverse);
args.push_back(&shift); // shift is unmodified.
result = bvLeftShiftBothWays(args, outputReverse);
if (CONFLICT == result)
return CONFLICT;
// Now write the reversed values back.
// Reverse the output and the input.
for (unsigned i = 0; i < bitWidth; i++)
{
if (opReverse.isFixed(i) && !op.isFixed(bitWidth - 1 - i))
{
op.setFixed(bitWidth - 1 - i, true);
op.setValue(bitWidth - 1 - i, opReverse.getValue(i));
}
if (outputReverse.isFixed(i) && !output.isFixed(bitWidth - 1 - i))
{
output.setFixed(bitWidth - 1 - i, true);
output.setValue(bitWidth - 1 - i, outputReverse.getValue(i));
}
}
return result;
}
// Converts the array of possible shifts into a set that represents the values.
FixedBits getPossible(unsigned bitWidth, bool possibleShift[],
unsigned numberOfPossibleShifts, const FixedBits& shift)
{
FixedBits v(bitWidth, false);
bool first = true;
for (unsigned i = 0; i < numberOfPossibleShifts - 1; i++)
{
if (possibleShift[i])
{
if (first)
{
first = false;
for (unsigned j = 0; j < (unsigned)v.getWidth(); j++)
{
v.setFixed(j, true);
if (j < sizeof(unsigned) * 8)
v.setValue(j, 0 != (i & (1 << j)));
else
v.setValue(j, false);
}
}
else
{
// join.
for (unsigned j = 0;
j < (unsigned)v.getWidth() && j < sizeof(unsigned) * 8; j++)
{
if (v.isFixed(j))
{
// union.
if (v.getValue(j) != (0 != (i & (1 << j))))
v.setFixed(j, false);
}
}
}
}
}
unsigned firstShift;
for (firstShift = 0; firstShift < numberOfPossibleShifts; firstShift++)
if (possibleShift[firstShift])
break;
// The top most entry of the shift table is special. It means all values of
// shift
// that fill it completely with zeroes /ones. We take the union of all of the
// values >bitWidth
// in this function.
if (possibleShift[numberOfPossibleShifts - 1])
{
FixedBits bitWidthFB = FixedBits::fromUnsignedInt(bitWidth, bitWidth);
FixedBits output(1, true);
output.setFixed(0, true);
output.setValue(0, true);
FixedBits working(shift);
vector<FixedBits*> args;
args.push_back(&working);
args.push_back(&bitWidthFB);
// Write into working anything that can be determined given it's >=bitWidth.
Result r = bvGreaterThanEqualsBothWays(args, output);
assert(CONFLICT != r);
// Get the union of "working" with the prior union.
for (unsigned i = 0; i < bitWidth; i++)
{
if (!working.isFixed(i) && v.isFixed(i))
v.setFixed(i, false);
if (working.isFixed(i) && v.isFixed(i) &&
(working.getValue(i) != v.getValue(i)))
v.setFixed(i, false);
if (firstShift == numberOfPossibleShifts - 1) // no less shifts possible.
{
if (working.isFixed(i))
{
v.setFixed(i, true);
v.setValue(i, working.getValue(i));
}
}
}
}
if (debug_shift)
cerr << "Set of possible shifts:" << v << endl;
return v;
}
unsigned getMaxShiftFromValueViaAlternation(const unsigned bitWidth,
const FixedBits& output)
{
unsigned maxShiftFromValue = UINT_MAX;
// The shift must be less than the position of the first alternation.
bool foundTrue = false;
bool foundFalse = false;
for (int i = bitWidth - 1; i >= 0; i--)
{
if (output.isFixed(i))
{
if (output.getValue(i) && foundFalse)
{
maxShiftFromValue = i;
break;
}
if (!output.getValue(i) && foundTrue)
{
maxShiftFromValue = i;
break;
}
if (output.getValue(i))
foundTrue = true;
else if (!output.getValue(i))
foundFalse = true;
}
}
if (maxShiftFromValue != UINT_MAX)
maxShiftFromValue = bitWidth - 2 - maxShiftFromValue;
return maxShiftFromValue;
}
Result bvArithmeticRightShiftBothWays(vector<FixedBits*>& children,
FixedBits& output)
{
const unsigned bitWidth = output.getWidth();
assert(2 == children.size());
assert(bitWidth > 0);
assert(children[0]->getWidth() == children[1]->getWidth());
const unsigned MSBIndex = bitWidth - 1;
FixedBits& op = *children[0];
FixedBits& shift = *children[1];
// If the MSB isn't set, create a copy with it set each way and take the meet.
if (!op.isFixed(MSBIndex))
{
vector<FixedBits*> children1;
vector<FixedBits*> children2;
FixedBits op1(op);
FixedBits op2(op);
FixedBits shift1(shift);
FixedBits shift2(shift);
FixedBits output1(output);
FixedBits output2(output);
children1.push_back(&op1);
children1.push_back(&shift1);
op1.setFixed(MSBIndex, true);
op1.setValue(MSBIndex, true);
children2.push_back(&op2);
children2.push_back(&shift2);
op2.setFixed(MSBIndex, true);
op2.setValue(MSBIndex, false);
Result r1 = bvArithmeticRightShiftBothWays(children1, output1);
Result r2 = bvArithmeticRightShiftBothWays(children2, output2);
if (r1 == CONFLICT && r2 == CONFLICT)
return CONFLICT;
if (r1 == CONFLICT)
{
op = op2;
shift = shift2;
output = output2;
return r2;
}
if (r2 == CONFLICT)
{
op = op1;
shift = shift1;
output = output1;
return r1;
}
op = FixedBits::meet(op1, op2);
shift = FixedBits::meet(shift1, shift2);
output = FixedBits::meet(output1, output2);
return r1;
}
assert(op.isFixed(MSBIndex));
if (debug_shift)
{
cerr << "=========" << endl;
cerr << op << " >a> ";
cerr << shift;
cerr << " = " << output << endl;
}
// The topmost number of possible shifts corresponds to all
// the values of shift that shift out everything.
// i.e. possibleShift[bitWidth+1] is the SET of all operations that shift past
// the end.
const unsigned numberOfPossibleShifts = bitWidth + 1;
bool* possibleShift = (bool*)alloca(sizeof(bool) * numberOfPossibleShifts);
for (unsigned i = 0; i < numberOfPossibleShifts; i++)
possibleShift[i] = false;
// If either of the top two bits are fixed they should be equal.
if (op.isFixed(MSBIndex) ^ output.isFixed(MSBIndex))
{
if (op.isFixed(MSBIndex))
{
output.setFixed(MSBIndex, true);
output.setValue(MSBIndex, op.getValue(MSBIndex));
}
if (output.isFixed(MSBIndex))
{
op.setFixed(MSBIndex, true);
op.setValue(MSBIndex, output.getValue(MSBIndex));
}
}
// Both the MSB of the operand and the output should be fixed now..
assert(output.isFixed(MSBIndex));
unsigned minShiftFromShift,
maxShiftFromShift; // The range of the "shift" value.
shift.getUnsignedMinMax(minShiftFromShift, maxShiftFromShift);
// The shift can't be any bigger than the topmost alternation in the output.
// For example if the output is 0.01000, then the shift can not be bigger than
// 3.
unsigned maxShiftFromOutput =
getMaxShiftFromValueViaAlternation(bitWidth, output);
maxShiftFromShift = std::min(maxShiftFromShift, (unsigned)maxShiftFromOutput);
if (debug_shift)
{
cerr << "minshift:" << minShiftFromShift << endl;
cerr << "maxshift:" << maxShiftFromShift << endl;
cerr << "total:" << maxShiftFromShift << endl;
}
for (unsigned i = minShiftFromShift;
i <= std::min(bitWidth, maxShiftFromShift); i++)
{
// if the bit-pattern of 'i' is in the set represented by the 'shift'.
if (shift.unsignedHolds(i))
possibleShift[i] = true;
}
// Complication. Given a shift like [.1] possibleShift[2] is now false.
// A shift of 2 isn't possible. But one of three is.
// possibleShift[2] means any shift >=2 is possible. So it needs to be set
// to true.
{
if (maxShiftFromShift >= bitWidth)
possibleShift[bitWidth] = true;
}
// Now check one-by-one each shifting.
// If we are shifting a zero to where a one is (say), then that shifting isn't
// possible.
for (unsigned shiftIt = minShiftFromShift; shiftIt < numberOfPossibleShifts;
shiftIt++)
{
if (possibleShift[shiftIt])
{
for (unsigned column = 0; column < bitWidth; column++)
{
// if they are fixed to different values. That's wrong.
if (column + shiftIt <= bitWidth - 1)
{
if (output.isFixed(column) && op.isFixed(column + shiftIt) &&
(output.getValue(column) != op.getValue(column + shiftIt)))
{
possibleShift[shiftIt] = false;
break;
}
}
}
}
}
int nOfPossibleShifts = 0;
for (unsigned i = 0; i < numberOfPossibleShifts; i++)
{
if (possibleShift[i])
{
nOfPossibleShifts++;
maxShiftFromShift = i;
if (debug_shift)
{
std::cerr << "Possible Shift:" << i << std::endl;
}
}
}
if (debug_shift)
{
std::cerr << "Number of possible shifts:" << nOfPossibleShifts << endl;
}
// If it's empty. It's a conflict.
if (0 == nOfPossibleShifts)
{
return CONFLICT;
}
// We have a list of all the possible shift amounts.
// We take the union of all the bits that are possible.
FixedBits setOfPossibleShifts =
getPossible(bitWidth, possibleShift, numberOfPossibleShifts, shift);
// Write in any fixed values to the shift.
for (unsigned i = 0; i < bitWidth; i++)
{
if (setOfPossibleShifts.isFixed(i))
{
if (!shift.isFixed(i))
{
shift.setFixed(i, true);
shift.setValue(i, setOfPossibleShifts.getValue(i));
}
else if (shift.isFixed(i) &&
shift.getValue(i) != setOfPossibleShifts.getValue(i))
{
return CONFLICT;
}
}
}
// If a particular input bit appears in every possible shifting,
// and if that bit is unfixed,
// and if the result it is fixed to the same value in every position.
// Then, that bit must be fixed.
// E.g. [--] << [0-] == [00]
bool* candidates = (bool*)alloca(sizeof(bool) * bitWidth);
for (unsigned i = 0; i < bitWidth; i++)
{
candidates[i] = !op.isFixed(i);
}
// candidates: So far: the bits that are unfixed in the operand.
for (unsigned i = 0; i < numberOfPossibleShifts; i++)
{
if (possibleShift[i])
{
// If this shift is possible, then some bits will be shifted out.
for (unsigned j = 0; j < i; j++)
candidates[j] = false;
}
}
// candidates: So far: + the input bits that are unfixed.
// + the input bits that are in every possible fixing.
// Check all candidates have the same output values.
for (unsigned candidate = 0; candidate < bitWidth; candidate++)
{
bool setTo = false; // value that's never read. To quieten gcc.
if (candidates[candidate])
{
bool first = true;
for (unsigned shiftIT = 0; shiftIT < bitWidth; shiftIT++)
{
// If the shift isn't possible continue.
if (!possibleShift[shiftIT])
continue;
if (shiftIT > candidate)
continue;
unsigned idx = candidate - shiftIT;
if (!output.isFixed(idx))
{
candidates[candidate] = false;
break;
}
else
{
if (first)
{
first = false;
setTo = output.getValue(idx);
}
else
{
if (setTo != output.getValue(idx))
{
candidates[candidate] = false;
break;
}
}
}
}
}
if (candidates[candidate])
{
assert(!op.isFixed(candidate));
op.setFixed(candidate, true);
op.setValue(candidate, setTo);
}
}
if (debug_shift)
{
cerr << op << " >a> ";
cerr << shift;
cerr << " = " << output << endl;
}
// Go through each of the possible shifts. If the same value is fixed
// at every location. Then it's fixed too in the result.
// Looping over the output columns.
bool MSBValue = op.getValue(MSBIndex);
for (unsigned column = 0; column < bitWidth; column++)
{
bool allFixedToSame = true;
bool allFixedTo = false; // value that's never read. To quieten gcc.
bool first = true;
for (unsigned shiftIt = 0;
(shiftIt < numberOfPossibleShifts) && allFixedToSame; shiftIt++)
{
if (possibleShift[shiftIt])
{
// Will have shifted in something..
if (shiftIt > (bitWidth - 1 - column))
{
if (first)
{
allFixedTo = MSBValue;
first = false;
}
else
{
if (allFixedTo != MSBValue)
{
allFixedToSame = false;
}
}
}
else
{
unsigned index = column + shiftIt;
if (!op.isFixed(index))
allFixedToSame = false;
else if (first && op.isFixed(index))
{
first = false;
allFixedTo = op.getValue(index);
}
if (op.isFixed(index) && allFixedTo != op.getValue(index))
allFixedToSame = false;
}
}
}
// If it can be just one possible value. Then we can fix 'em.
if (allFixedToSame)
{
if (output.isFixed(column) && (output.getValue(column) != allFixedTo))
{
return CONFLICT;
}
if (!output.isFixed(column))
{
output.setFixed(column, true);
output.setValue(column, allFixedTo);
}
}
}
return NOT_IMPLEMENTED;
}
Result bvLeftShiftBothWays(vector<FixedBits*>& children, FixedBits& output)
{
const unsigned bitWidth = output.getWidth();
assert(2 == children.size());
assert(bitWidth > 0);
FixedBits& op = *children[0];
FixedBits& shift = *children[1];
if (debug_shift)
{
cerr << "op:" << op << endl;
cerr << "shift:" << shift << endl;
cerr << "output:" << output << endl;
}
// The topmost number of possible shifts corresponds to all
// the values of shift that shift out everything.
// i.e. possibleShift[bitWidth+1] is the SET of all operations that shift past
// the end.
const unsigned numberOfPossibleShifts = bitWidth + 1;
bool* possibleShift = (bool*)alloca(sizeof(bool) * numberOfPossibleShifts);
for (unsigned i = 0; i < numberOfPossibleShifts; i++)
possibleShift[i] = false;
unsigned minShift, maxShift;
shift.getUnsignedMinMax(minShift, maxShift);
// The shift must be less than the position of the first one in the output
int positionOfFirstOne = -1;
for (unsigned i = 0; i < bitWidth; i++)
{
if (output.isFixed(i) && output.getValue(i))
{
positionOfFirstOne = i;
break;
}
}
if (positionOfFirstOne >= 0)
{
if ((unsigned)positionOfFirstOne < minShift)
return CONFLICT;
maxShift = std::min(maxShift, (unsigned)positionOfFirstOne);
}
for (unsigned i = minShift; i <= std::min(bitWidth, maxShift); i++)
{
// if the bit-pattern of 'i' is in the set represented by the 'shift'.
if (shift.unsignedHolds(i))
possibleShift[i] = true;
}
// Complication. Given a shift like [-1]. possibleShift[2] is now false.
// A shift of 2 isn't possible. But one of three is.
// possibleShift[2] means any shift >=2 is possible. So it needs to be set
// to true.
{
if (maxShift >= bitWidth)
possibleShift[bitWidth] = true;
}
// Now check one-by-one each shifting.
// If we are shifting a zero to where a one is (say), then that shifting isn't
// possible.
for (unsigned shiftIt = 0; shiftIt < numberOfPossibleShifts; shiftIt++)
{
if (possibleShift[shiftIt])
{
for (unsigned column = 0; column < bitWidth; column++)
{
if (column < shiftIt)
{
if (output.isFixed(column) &&
output.getValue(
column)) // output is one in the column. That's wrong.
{
possibleShift[shiftIt] = false;
break;
}
}
else
{
// if they are fixed to different values. That's wrong.
if (output.isFixed(column) && op.isFixed(column - shiftIt) &&
(output.getValue(column) != op.getValue(column - shiftIt)))
{
possibleShift[shiftIt] = false;
break;
}
}
}
}
}
int nOfPossibleShifts = 0;
for (unsigned i = 0; i < numberOfPossibleShifts; i++)
{
if (possibleShift[i])
{
nOfPossibleShifts++;
if (debug_shift)
{
std::cerr << "Possible:" << i << std::endl;
}
}
}
if (debug_shift)
{
std::cerr << "Number of possible shifts:" << nOfPossibleShifts << endl;
}
// If it's empty. It's a conflict.
if (0 == nOfPossibleShifts)
return CONFLICT;
// We have a list of all the possible shift amounts.
// We take the union of all the bits that are possible.
FixedBits v(bitWidth, false);
bool first = true;
for (unsigned i = 0; i < numberOfPossibleShifts - 1; i++)
{
if (possibleShift[i])
{
if (first)
{
first = false;
for (unsigned j = 0; j < (unsigned)v.getWidth(); j++)
{
v.setFixed(j, true);
if (j < sizeof(unsigned) * 8)
v.setValue(j, 0 != (i & (1 << j)));
else
v.setValue(j, false);
}
}
else
{
// join.
for (unsigned j = 0;
j < (unsigned)v.getWidth() && j < sizeof(unsigned) * 8; j++)
{
if (v.isFixed(j))
{
// union.
if (v.getValue(j) != (0 != (i & (1 << j))))
v.setFixed(j, false);
}
}
}
}
}
// The top most entry of the shift table is special. It means all values of
// shift
// that fill it completely with zeroes. We take the union of all of the values
// >bitWidth
// in this function.
if (possibleShift[numberOfPossibleShifts - 1])
{
FixedBits bitWidthFB = FixedBits::fromUnsignedInt(bitWidth, bitWidth);
FixedBits output(1, true);
output.setFixed(0, true);
output.setValue(0, true);
FixedBits working(shift);
vector<FixedBits*> args;
args.push_back(&working);
args.push_back(&bitWidthFB);
// Write into working anything that can be determined given it's >=bitWidth.
Result r = bvGreaterThanEqualsBothWays(args, output);
assert(CONFLICT != r);
// Get the union of "working" with the prior union.
for (unsigned i = 0; i < bitWidth; i++)
{
if (!working.isFixed(i) && v.isFixed(i))
v.setFixed(i, false);
if (working.isFixed(i) && v.isFixed(i) &&
(working.getValue(i) != v.getValue(i)))
v.setFixed(i, false);
if (first) // no less shifts possible.
{
if (working.isFixed(i))
{
v.setFixed(i, true);
v.setValue(i, working.getValue(i));
}
}
}
}
if (debug_shift)
{
std::cerr << "Shift Amount:" << v << std::endl;
}
for (unsigned i = 0; i < bitWidth; i++)
{
if (v.isFixed(i))
{
if (!shift.isFixed(i))
{
shift.setFixed(i, true);
shift.setValue(i, v.getValue(i));
}
else if (shift.isFixed(i) && shift.getValue(i) != v.getValue(i))
return CONFLICT;
}
}
// If a particular input bit appears in every possible shifting,
// and if that bit is unfixed,
// and if the result it is fixed to the same value in every position.
// Then, that bit must be fixed.
// E.g. [--] << [0-] == [00]
bool* candidates = (bool*)alloca(sizeof(bool) * bitWidth);
for (unsigned i = 0; i < bitWidth; i++)
{
candidates[i] = !op.isFixed(i);
}
// candidates: So far: the bits that are unfixed.
for (unsigned i = 0; i < numberOfPossibleShifts; i++)
{
if (possibleShift[i])
{
// If this shift is possible, then some bits will be shifted out.
for (unsigned j = 0; j < i; j++)
candidates[bitWidth - 1 - j] = false;
}
}
// candidates: So far: + the input bits that are unfixed.
// + the input bits that are in every possible fixing.
// Check all candidates have the same output values.
for (unsigned candidate = 0; candidate < bitWidth; candidate++)
{
bool first = true;
bool setTo = false; // value that's never read. To quieten gcc.
if (candidates[candidate])
{
for (unsigned shiftIT = 0; shiftIT < bitWidth; shiftIT++)
{
// If the shift isn't possible continue.
if (!possibleShift[shiftIT])
continue;
unsigned idx = candidate + shiftIT;
if (!output.isFixed(idx))
{
candidates[candidate] = false;
break;
}
else
{
if (first)
{
first = false;
setTo = output.getValue(idx);
}
else
{
if (setTo != output.getValue(idx))
{
candidates[candidate] = false;
break;
}
}
}
}
}
if (candidates[candidate])
{
assert(!op.isFixed(candidate));
op.setFixed(candidate, true);
op.setValue(candidate, setTo);
}
}
// done.
// Go through each of the possible shifts. If the same value is fixed
// at every location. Then it's fixed too in the result.
for (unsigned column = 0; column < bitWidth; column++)
{
bool allFixedToSame = true;
bool allFixedTo = false; // value that's never read. To quieten gcc.
bool first = true;
for (unsigned shiftIt = minShift;
(shiftIt < numberOfPossibleShifts) && allFixedToSame; shiftIt++)
{
if (possibleShift[shiftIt])
{
// Will have shifted in zeroes.
if (shiftIt > column)
{
if (first)
{
allFixedTo = false;
first = false;
}
else
{
if (allFixedTo)
{
allFixedToSame = false;
}
}
}
else
{
unsigned index = column - shiftIt;
if (!op.isFixed(index))
allFixedToSame = false;
else if (first && op.isFixed(index))
{
first = false;
allFixedTo = op.getValue(index);
}
if (op.isFixed(index) && allFixedTo != op.getValue(index))
allFixedToSame = false;
}
}
}
// If it can be just one possible value. Then we can fix 'em.
if (allFixedToSame)
{
if (output.isFixed(column) && (output.getValue(column) != allFixedTo))
return CONFLICT;
if (!output.isFixed(column))
{
output.setFixed(column, true);
output.setValue(column, allFixedTo);
}
}
}
/*
// If there is only one possible shift value. Then, we can push from the
output back.
if (1 == nOfPossibleShifts)
{
for (unsigned i = shiftIndex; i < bitWidth; i++)
{
if (!op.isFixed(i - shiftIndex) && output.isFixed(i))
{
op.setFixed(i - shiftIndex, true);
op.setValue(i - shiftIndex, output.getValue(i));
result = CHANGED;
}
}
}
*/
return NOT_IMPLEMENTED;
}
}
}