/* ** Copyright (C) 2018 Martin Brain ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /* ** simpleExecutable.cpp ** ** Martin Brain ** martin.brain@cs.ox.ac.uk ** 07/08/14 ** ** The most simple executable implementation of bit-vectors. ** Limited in the ranges it supports but fast and suitable for reasoning. ** */ #include "symfpu/baseTypes/simpleExecutable.h" #include #include #include namespace symfpu { namespace simpleExecutable { // This would all be much easier if C++ allowed partial specialisation of member templates... template <> bool bitVector::isRepresentable (const bitWidthType w, const int64_t v) { uint64_t shiftSafe = *((uint64_t *)(&v)); uint64_t top = (shiftSafe >> w); uint64_t signbit = shiftSafe & 0x8000000000000000; int64_t stop = *((int64_t *)(&top)); return (signbit) ? (stop == bitVector::nOnes(bitVector::maxWidth() - w)) : (stop == 0LL); } template <> bool bitVector::isRepresentable (const bitWidthType w, const uint64_t v) { uint64_t top = (v >> w); return (top == 0); } template <> uint64_t bitVector::makeRepresentable (const bitWidthType w, const uint64_t v) { return v & bitVector::nOnes(w); } template <> int64_t bitVector::makeRepresentable (const bitWidthType w, const int64_t v) { if (v <= ((1LL << (w - 1)) - 1) && (-(1LL << (w - 1)) <= v)) { return v; } else { return 0; } } template <> bitVector bitVector::maxValue (const bitWidthType &w) { PRECONDITION(w != 1); return bitVector(w, (1ULL << (w - 1)) - 1); } template <> bitVector bitVector::maxValue (const bitWidthType &w) { PRECONDITION(w != 1); return bitVector(w, (1ULL << w) - 1); } template <> bitVector bitVector::minValue (const bitWidthType &w) { PRECONDITION(w != 1); return bitVector(w, -(1ULL << (w - 1))); } template <> bitVector bitVector::minValue (const bitWidthType &w) { return bitVector(w, 0); } template <> bitVector bitVector::operator- (void) const { return bitVector(this->width, -this->value); } // Used in addition template <> bitVector bitVector::operator- (void) const { return bitVector(this->width, bitVector::makeRepresentable(this->width, (~this->value) + 1)); } template <> bitVector bitVector::operator~ (void) const { return bitVector(this->width, bitVector::makeRepresentable(this->width, ~this->value)); } // This is wrong in the signed case as the sign bit it tracks and the sign bit in int64_t are in different places! static uint64_t stickyRightShift(const bool value, const bitWidthType width, const uint64_t left, const uint64_t right) { //uint64_t bitsInWord = bitVector::maxWidth(); uint64_t newValue = left; uint64_t stickyBit = 0; uint64_t signBit = left & (1ULL << (width - 1)); if (right <= width) { for (uint64_t i = 1; i <= width; i <<= 1) { if (right & i) { uint64_t iOnes = ((1ULL << i) - 1); stickyBit |= ((newValue & iOnes) ? 1 : 0); // Sign extending shift if (signBit) { newValue = (newValue >> i) | (iOnes << (width - i)); } else { newValue = (newValue >> i); } } } } else { newValue = (signBit) ? 0xFFFFFFFFFFFFFFFFULL : 0x0; stickyBit = (left) ? 0x1 : 0x0; } return (value) ? newValue : stickyBit; } template <> bitVector bitVector::signExtendRightShift (const bitVector &op) const { PRECONDITION(this->width == op.width); return bitVector(this->width, bitVector::makeRepresentable(this->width, stickyRightShift(true, this->width, this->value, op.value))); } template <> bitVector bitVector::signExtendRightShift (const bitVector &op) const { PRECONDITION(this->width == op.width); PRECONDITION(this->width < CHAR_BIT*sizeof(int64_t)); int64_t newValue; if (this->value < 0) { newValue = -(-(this->value) >> op.value) + ((this->value & 0x1) ? -1 : 0); // Rounds away } else { newValue = this->value >> op.value; } return bitVector(this->width, bitVector::makeRepresentable(this->width, newValue)); } template<> bitVector bitVector::modularLeftShift (const bitVector &op) const { PRECONDITION(this->width == op.width); return bitVector(this->width, bitVector::makeRepresentable(this->width, (op.value >= this->width) ? 0ULL : this->value << op.value)); } template<> bitVector bitVector::modularRightShift (const bitVector &op) const { PRECONDITION(this->width == op.width); return bitVector(this->width, bitVector::makeRepresentable(this->width, (op.value >= this->width) ? 0ULL : this->value >> op.value)); } template <> bitVector bitVector::modularNegate (void) const { return bitVector(this->width, bitVector::makeRepresentable(this->width, ~this->value + 1)); } template <> bitVector bitVector::modularNegate (void) const { return bitVector(this->width, bitVector::makeRepresentable(this->width, -this->value)); } // Only instantiated for unsigned template <> bitVector bitVector::extract(bitWidthType upper, bitWidthType lower) const { PRECONDITION(this->width > upper); PRECONDITION(upper >= lower); bitWidthType newLength = (upper - lower) + 1; return bitVector(newLength, bitVector::makeRepresentable(newLength, (this->value >> lower))); } template <> bitVector bitVector::append(const bitVector &op) const { PRECONDITION(this->width + op.width <= bitVector::maxWidth()); return bitVector(this->width + op.width, this->value << op.width | op.value); } template <> bitVector::signedVersion> bitVector::toSigned (void) const { return bitVector(this->width, *((int64_t *)&this->value)); } template <> bitVector::unsignedVersion> bitVector::toUnsigned (void) const { // Note we need to mask out the (sign extensions) of the negative part. return bitVector(this->width, (*((uint64_t *)&this->value)) & bitVector::nOnes(this->width)); } roundingMode traits::RNE (void) { return roundingMode(FE_TONEAREST); } roundingMode traits::RNA (void) { return roundingMode(23); } // Could be better... roundingMode traits::RTP (void) { return roundingMode(FE_UPWARD); } roundingMode traits::RTN (void) { return roundingMode(FE_DOWNWARD); } roundingMode traits::RTZ (void) { return roundingMode(FE_TOWARDZERO); } } #if 0 template <> simpleExecutable::traits::ubv orderEncode (const simpleExecutable::traits::ubv &b) { return orderEncodeBitwise(b); } #endif }