<commit_before>/*
 * Copyright (C) 2007 Tommi Maekitalo
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <tntdb/oracle/value.h>
#include <tntdb/oracle/statement.h>
#include <tntdb/error.h>
#include <tntdb/decimal.h>
#include <sstream>
#include <cxxtools/log.h>

log_define("tntdb.oracle.value")

namespace tntdb
{
  namespace oracle
  {
    namespace
    {
      template <typename T>
      T getValue(const std::string& s, const char* tname)
      {
        std::istringstream in(s);
        T ret;
        in >> ret;
        if (!in)
        {
          std::ostringstream msg;
          msg << "can't convert \"" << s << "\" to " << tname;
          throw TypeError(msg.str());
        }
        return ret;
      }

      template <typename T>
      std::string toString(T v)
      {
        std::ostringstream ret;
        ret << v;
        return ret.str();
      }

      template <>
      std::string toString(float v)
      {
        std::ostringstream ret;
        ret.precision(24);
        ret << v;
        return ret.str();
      }

      template <>
      std::string toString(double v)
      {
        std::ostringstream ret;
        ret.precision(24);
        ret << v;
        return ret.str();
      }

      template <>
      std::string toString(Decimal v)
      {
        std::ostringstream ret;
        ret.precision(24);
        ret << v;
        return ret.str();
      }
    }

    Value::Value(Statement* stmt, ub4 pos)
    {
      sword ret;

      /* get parameter-info */
      ret = OCIParamGet(stmt->getHandle(), OCI_HTYPE_STMT,
        stmt->getErrorHandle(),
        reinterpret_cast<void**>(&paramp), pos + 1);
      stmt->checkError(ret, "OCIParamGet");

      init(stmt, paramp, pos);

      OCIDescriptorFree(paramp, OCI_DTYPE_PARAM);
      paramp = 0;
    }

    Value::Value(Statement* stmt, OCIParam* paramp, ub4 pos)
    {
      init(stmt, paramp, pos);
    }

    void Value::init(Statement* stmt, OCIParam* paramp, ub4 pos)
    {
      sword ret;

      /* retrieve column name */
      ub4 col_name_len = 0;
      text* col_name = 0;
      ret = OCIAttrGet(paramp, OCI_DTYPE_PARAM, &col_name, &col_name_len,
        OCI_ATTR_NAME, stmt->getErrorHandle());

      stmt->checkError(ret, "OCIAttrGet(OCI_ATTR_NAME)");
      colName.assign(reinterpret_cast<const char*>(col_name), col_name_len);

      log_debug("column name=\"" << col_name << '"');

      /* retrieve the data type attribute */
      ret = OCIAttrGet(paramp, OCI_DTYPE_PARAM, &type, 0, OCI_ATTR_DATA_TYPE,
        stmt->getErrorHandle());
      stmt->checkError(ret, "OCIAttrGet(OCI_ATTR_DATA_TYPE)");

      ret = OCIAttrGet(paramp, OCI_DTYPE_PARAM, &len, 0, OCI_ATTR_DATA_SIZE,
        stmt->getErrorHandle());
      stmt->checkError(ret, "OCIAttrGet(OCI_ATTR_DATA_SIZE)");

      /* define outputvariable */
      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          log_debug("OCIDefineByPos(SQLT_TIMESTAMP)");
          ret = OCIDefineByPos(stmt->getHandle(), &defp,
            stmt->getErrorHandle(), pos + 1, &datetime.getReference(stmt->getConnection()),
            sizeof(OCIDateTime*), SQLT_TIMESTAMP, &nullind, &len, 0, OCI_DEFAULT);
          break;

        case SQLT_INT:
          log_debug("OCIDefineByPos(SQLT_INT)");
          ret = OCIDefineByPos(stmt->getHandle(), &defp,
            stmt->getErrorHandle(), pos + 1, &longValue,
            sizeof(longValue), SQLT_INT, &nullind, &len, 0, OCI_DEFAULT);
          break;

        case SQLT_UIN:
          log_debug("OCIDefineByPos(SQLT_UIN)");
          ret = OCIDefineByPos(stmt->getHandle(), &defp,
            stmt->getErrorHandle(), pos + 1, &uint32Value,
            sizeof(uint32Value), SQLT_UIN, &nullind, &len, 0, OCI_DEFAULT);
          break;

        case SQLT_FLT:
          log_debug("OCIDefineByPos(SQLT_FLT)");
          ret = OCIDefineByPos(stmt->getHandle(), &defp,
            stmt->getErrorHandle(), pos + 1, &doubleValue,
            sizeof(doubleValue), SQLT_FLT, &nullind, &len, 0, OCI_DEFAULT);
          break;

        case SQLT_NUM:
        case SQLT_VNU:
          log_debug("OCIDefineByPos(SQLT_VNU)");
          ret = OCIDefineByPos(stmt->getHandle(), &defp,
            stmt->getErrorHandle(), pos + 1, number.getHandle(),
            OCI_NUMBER_SIZE, SQLT_VNU, &nullind, &len, 0, OCI_DEFAULT);
          break;

        default:
          log_debug("OCIDefineByPos(SQLT_AVC)");
          data.reserve(len + 16);
          ret = OCIDefineByPos(stmt->getHandle(), &defp,
            stmt->getErrorHandle(), pos + 1, data.data(),
            len + 16, SQLT_AVC, &nullind, &len, 0, OCI_DEFAULT);
          break;
      }
      stmt->checkError(ret, "OCIDefineByPos");
    }

    Value::~Value()
    {
      if (defp)
        OCIHandleFree(defp, OCI_HTYPE_DEFINE);
      if (paramp)
        OCIDescriptorFree(paramp, OCI_DTYPE_PARAM);
    }

    bool Value::isNull() const
    {
      return nullind != 0;
    }

    bool Value::getBool() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          throw TypeError();

        case SQLT_INT:
          return longValue != 0;

        case SQLT_UIN:
          return uint32Value != 0;

        case SQLT_FLT:
          return doubleValue != 0;

        case SQLT_NUM:
        case SQLT_VNU:
          return !number.getDecimal().isZero();

        default:
          return data[0] == 't' || data[0] == 'T'
              || data[0] == 'y' || data[0] == 'Y'
              || data[0] == '1';

      }
    }

    int Value::getInt() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          throw TypeError();

        case SQLT_INT:
        case SQLT_UIN:
          return static_cast<int>(longValue);

        case SQLT_FLT:
          return static_cast<int>(doubleValue);

        case SQLT_NUM:
        case SQLT_VNU:
          return number.getDecimal().getInt();

        default:
          return getValue<int>(data.data(), "int");
      }
    }

    int32_t Value::getInt32() const
    {
      return getInt();
    }

    unsigned Value::getUnsigned() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          throw TypeError();

        case SQLT_INT:
        case SQLT_UIN:
          return static_cast<unsigned>(longValue);

        case SQLT_FLT:
          return static_cast<unsigned>(doubleValue);

        case SQLT_NUM:
        case SQLT_VNU:
          return number.getDecimal().getUnsigned();

        default:
          return getValue<unsigned>(data.data(), "unsigned");
      }
    }

    uint32_t Value::getUnsigned32() const
    {
      return getUnsigned();
    }

    int64_t Value::getInt64() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          throw TypeError();

        case SQLT_INT:
        case SQLT_UIN:
          return static_cast<int64_t>(longValue);

        case SQLT_FLT:
          return static_cast<int64_t>(doubleValue);

        case SQLT_NUM:
        case SQLT_VNU:
          return number.getDecimal().getInt64();

        default:
          return getValue<int64_t>(data.data(), "int");
      }
    }

    uint64_t Value::getUnsigned64() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          throw TypeError();

        case SQLT_INT:
        case SQLT_UIN:
          return static_cast<uint64_t>(longValue);

        case SQLT_FLT:
          return static_cast<uint64_t>(doubleValue);

        case SQLT_NUM:
        case SQLT_VNU:
          return number.getDecimal().getUnsigned64();

        default:
          return getValue<uint64_t>(data.data(), "int");
      }
    }

    Decimal Value::getDecimal() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          throw TypeError();

        case SQLT_INT:
        case SQLT_UIN:
        {
          Decimal decimal;
          decimal.setInt(longValue);
          return decimal;
        }

        case SQLT_FLT:
        {
          Decimal decimal;
          decimal.setDouble(doubleValue);
          return decimal;
        }

        case SQLT_NUM:
        case SQLT_VNU:
          return number.getDecimal();

        default:
          return getValue<Decimal>(data.data(), "Decimal");
      }
    }

    float Value::getFloat() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          throw TypeError();

        case SQLT_INT:
        case SQLT_UIN:
          return static_cast<float>(longValue);

        case SQLT_FLT:
          return static_cast<float>(doubleValue);

        case SQLT_NUM:
        case SQLT_VNU:
          return number.getDecimal().getFloat();

        default:
          return getValue<float>(data.data(), "float");
      }
    }

    double Value::getDouble() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          throw TypeError();

        case SQLT_INT:
        case SQLT_UIN:
          return static_cast<double>(longValue);

        case SQLT_FLT:
          return static_cast<double>(doubleValue);

        case SQLT_NUM:
        case SQLT_VNU:
          return number.getDecimal().getDouble();

        default:
          return getValue<double>(data.data(), "double");
      }
    }

    char Value::getChar() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          throw TypeError();

        case SQLT_INT:
        case SQLT_UIN:
          return static_cast<char>(longValue);

        case SQLT_FLT:
          return static_cast<char>(doubleValue);

        case SQLT_NUM:
        case SQLT_VNU:
          return static_cast<char>(number.getDecimal().getInt());

        default:
          return *data.data();
      }
    }

    void Value::getString(std::string& ret) const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          ret = datetime.getDatetime().getIso();
          break;

        case SQLT_INT:
        case SQLT_UIN:
          ret = toString(longValue);
          break;

        case SQLT_FLT:
          ret = toString(doubleValue);
          break;

        case SQLT_NUM:
        case SQLT_VNU:
          ret = number.getDecimal().toString();
          break;

        default:
          ret.assign(data.data(), len > 0 ? len - 1 : 0);
      }
    }

    void Value::getBlob(Blob& ret) const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
        case SQLT_INT:
        case SQLT_UIN:
        case SQLT_FLT:
        case SQLT_NUM:
        case SQLT_VNU:
          throw TypeError();

        default:
          ret.assign(data.data(), len > 0 ? len - 1 : 0);
      }
    }

    Date Value::getDate() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          return datetime.getDate();

        default:
          throw TypeError();
      }
    }

    Time Value::getTime() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          return datetime.getTime();

        default:
          throw TypeError();
      }
    }

    tntdb::Datetime Value::getDatetime() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          return datetime.getDatetime();

        default:
          throw TypeError();
      }
    }

  }
}
<commit_msg>fix debug output<commit_after>/*
 * Copyright (C) 2007 Tommi Maekitalo
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <tntdb/oracle/value.h>
#include <tntdb/oracle/statement.h>
#include <tntdb/error.h>
#include <tntdb/decimal.h>
#include <sstream>
#include <cxxtools/log.h>

log_define("tntdb.oracle.value")

namespace tntdb
{
  namespace oracle
  {
    namespace
    {
      template <typename T>
      T getValue(const std::string& s, const char* tname)
      {
        std::istringstream in(s);
        T ret;
        in >> ret;
        if (!in)
        {
          std::ostringstream msg;
          msg << "can't convert \"" << s << "\" to " << tname;
          throw TypeError(msg.str());
        }
        return ret;
      }

      template <typename T>
      std::string toString(T v)
      {
        std::ostringstream ret;
        ret << v;
        return ret.str();
      }

      template <>
      std::string toString(float v)
      {
        std::ostringstream ret;
        ret.precision(24);
        ret << v;
        return ret.str();
      }

      template <>
      std::string toString(double v)
      {
        std::ostringstream ret;
        ret.precision(24);
        ret << v;
        return ret.str();
      }

      template <>
      std::string toString(Decimal v)
      {
        std::ostringstream ret;
        ret.precision(24);
        ret << v;
        return ret.str();
      }
    }

    Value::Value(Statement* stmt, ub4 pos)
    {
      sword ret;

      /* get parameter-info */
      ret = OCIParamGet(stmt->getHandle(), OCI_HTYPE_STMT,
        stmt->getErrorHandle(),
        reinterpret_cast<void**>(&paramp), pos + 1);
      stmt->checkError(ret, "OCIParamGet");

      init(stmt, paramp, pos);

      OCIDescriptorFree(paramp, OCI_DTYPE_PARAM);
      paramp = 0;
    }

    Value::Value(Statement* stmt, OCIParam* paramp, ub4 pos)
    {
      init(stmt, paramp, pos);
    }

    void Value::init(Statement* stmt, OCIParam* paramp, ub4 pos)
    {
      sword ret;

      /* retrieve column name */
      ub4 col_name_len = 0;
      text* col_name = 0;
      ret = OCIAttrGet(paramp, OCI_DTYPE_PARAM, &col_name, &col_name_len,
        OCI_ATTR_NAME, stmt->getErrorHandle());

      stmt->checkError(ret, "OCIAttrGet(OCI_ATTR_NAME)");
      colName.assign(reinterpret_cast<const char*>(col_name), col_name_len);

      log_debug("column name=\"" << colName << '"');

      /* retrieve the data type attribute */
      ret = OCIAttrGet(paramp, OCI_DTYPE_PARAM, &type, 0, OCI_ATTR_DATA_TYPE,
        stmt->getErrorHandle());
      stmt->checkError(ret, "OCIAttrGet(OCI_ATTR_DATA_TYPE)");

      ret = OCIAttrGet(paramp, OCI_DTYPE_PARAM, &len, 0, OCI_ATTR_DATA_SIZE,
        stmt->getErrorHandle());
      stmt->checkError(ret, "OCIAttrGet(OCI_ATTR_DATA_SIZE)");

      /* define outputvariable */
      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          log_debug("OCIDefineByPos(SQLT_TIMESTAMP)");
          ret = OCIDefineByPos(stmt->getHandle(), &defp,
            stmt->getErrorHandle(), pos + 1, &datetime.getReference(stmt->getConnection()),
            sizeof(OCIDateTime*), SQLT_TIMESTAMP, &nullind, &len, 0, OCI_DEFAULT);
          break;

        case SQLT_INT:
          log_debug("OCIDefineByPos(SQLT_INT)");
          ret = OCIDefineByPos(stmt->getHandle(), &defp,
            stmt->getErrorHandle(), pos + 1, &longValue,
            sizeof(longValue), SQLT_INT, &nullind, &len, 0, OCI_DEFAULT);
          break;

        case SQLT_UIN:
          log_debug("OCIDefineByPos(SQLT_UIN)");
          ret = OCIDefineByPos(stmt->getHandle(), &defp,
            stmt->getErrorHandle(), pos + 1, &uint32Value,
            sizeof(uint32Value), SQLT_UIN, &nullind, &len, 0, OCI_DEFAULT);
          break;

        case SQLT_FLT:
          log_debug("OCIDefineByPos(SQLT_FLT)");
          ret = OCIDefineByPos(stmt->getHandle(), &defp,
            stmt->getErrorHandle(), pos + 1, &doubleValue,
            sizeof(doubleValue), SQLT_FLT, &nullind, &len, 0, OCI_DEFAULT);
          break;

        case SQLT_NUM:
        case SQLT_VNU:
          log_debug("OCIDefineByPos(SQLT_VNU)");
          ret = OCIDefineByPos(stmt->getHandle(), &defp,
            stmt->getErrorHandle(), pos + 1, number.getHandle(),
            OCI_NUMBER_SIZE, SQLT_VNU, &nullind, &len, 0, OCI_DEFAULT);
          break;

        default:
          log_debug("OCIDefineByPos(SQLT_AVC)");
          data.reserve(len + 16);
          ret = OCIDefineByPos(stmt->getHandle(), &defp,
            stmt->getErrorHandle(), pos + 1, data.data(),
            len + 16, SQLT_AVC, &nullind, &len, 0, OCI_DEFAULT);
          break;
      }
      stmt->checkError(ret, "OCIDefineByPos");
    }

    Value::~Value()
    {
      if (defp)
        OCIHandleFree(defp, OCI_HTYPE_DEFINE);
      if (paramp)
        OCIDescriptorFree(paramp, OCI_DTYPE_PARAM);
    }

    bool Value::isNull() const
    {
      return nullind != 0;
    }

    bool Value::getBool() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          throw TypeError();

        case SQLT_INT:
          return longValue != 0;

        case SQLT_UIN:
          return uint32Value != 0;

        case SQLT_FLT:
          return doubleValue != 0;

        case SQLT_NUM:
        case SQLT_VNU:
          return !number.getDecimal().isZero();

        default:
          return data[0] == 't' || data[0] == 'T'
              || data[0] == 'y' || data[0] == 'Y'
              || data[0] == '1';

      }
    }

    int Value::getInt() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          throw TypeError();

        case SQLT_INT:
        case SQLT_UIN:
          return static_cast<int>(longValue);

        case SQLT_FLT:
          return static_cast<int>(doubleValue);

        case SQLT_NUM:
        case SQLT_VNU:
          return number.getDecimal().getInt();

        default:
          return getValue<int>(data.data(), "int");
      }
    }

    int32_t Value::getInt32() const
    {
      return getInt();
    }

    unsigned Value::getUnsigned() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          throw TypeError();

        case SQLT_INT:
        case SQLT_UIN:
          return static_cast<unsigned>(longValue);

        case SQLT_FLT:
          return static_cast<unsigned>(doubleValue);

        case SQLT_NUM:
        case SQLT_VNU:
          return number.getDecimal().getUnsigned();

        default:
          return getValue<unsigned>(data.data(), "unsigned");
      }
    }

    uint32_t Value::getUnsigned32() const
    {
      return getUnsigned();
    }

    int64_t Value::getInt64() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          throw TypeError();

        case SQLT_INT:
        case SQLT_UIN:
          return static_cast<int64_t>(longValue);

        case SQLT_FLT:
          return static_cast<int64_t>(doubleValue);

        case SQLT_NUM:
        case SQLT_VNU:
          return number.getDecimal().getInt64();

        default:
          return getValue<int64_t>(data.data(), "int");
      }
    }

    uint64_t Value::getUnsigned64() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          throw TypeError();

        case SQLT_INT:
        case SQLT_UIN:
          return static_cast<uint64_t>(longValue);

        case SQLT_FLT:
          return static_cast<uint64_t>(doubleValue);

        case SQLT_NUM:
        case SQLT_VNU:
          return number.getDecimal().getUnsigned64();

        default:
          return getValue<uint64_t>(data.data(), "int");
      }
    }

    Decimal Value::getDecimal() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          throw TypeError();

        case SQLT_INT:
        case SQLT_UIN:
        {
          Decimal decimal;
          decimal.setInt(longValue);
          return decimal;
        }

        case SQLT_FLT:
        {
          Decimal decimal;
          decimal.setDouble(doubleValue);
          return decimal;
        }

        case SQLT_NUM:
        case SQLT_VNU:
          return number.getDecimal();

        default:
          return getValue<Decimal>(data.data(), "Decimal");
      }
    }

    float Value::getFloat() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          throw TypeError();

        case SQLT_INT:
        case SQLT_UIN:
          return static_cast<float>(longValue);

        case SQLT_FLT:
          return static_cast<float>(doubleValue);

        case SQLT_NUM:
        case SQLT_VNU:
          return number.getDecimal().getFloat();

        default:
          return getValue<float>(data.data(), "float");
      }
    }

    double Value::getDouble() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          throw TypeError();

        case SQLT_INT:
        case SQLT_UIN:
          return static_cast<double>(longValue);

        case SQLT_FLT:
          return static_cast<double>(doubleValue);

        case SQLT_NUM:
        case SQLT_VNU:
          return number.getDecimal().getDouble();

        default:
          return getValue<double>(data.data(), "double");
      }
    }

    char Value::getChar() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          throw TypeError();

        case SQLT_INT:
        case SQLT_UIN:
          return static_cast<char>(longValue);

        case SQLT_FLT:
          return static_cast<char>(doubleValue);

        case SQLT_NUM:
        case SQLT_VNU:
          return static_cast<char>(number.getDecimal().getInt());

        default:
          return *data.data();
      }
    }

    void Value::getString(std::string& ret) const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          ret = datetime.getDatetime().getIso();
          break;

        case SQLT_INT:
        case SQLT_UIN:
          ret = toString(longValue);
          break;

        case SQLT_FLT:
          ret = toString(doubleValue);
          break;

        case SQLT_NUM:
        case SQLT_VNU:
          ret = number.getDecimal().toString();
          break;

        default:
          ret.assign(data.data(), len > 0 ? len - 1 : 0);
      }
    }

    void Value::getBlob(Blob& ret) const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
        case SQLT_INT:
        case SQLT_UIN:
        case SQLT_FLT:
        case SQLT_NUM:
        case SQLT_VNU:
          throw TypeError();

        default:
          ret.assign(data.data(), len > 0 ? len - 1 : 0);
      }
    }

    Date Value::getDate() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          return datetime.getDate();

        default:
          throw TypeError();
      }
    }

    Time Value::getTime() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          return datetime.getTime();

        default:
          throw TypeError();
      }
    }

    tntdb::Datetime Value::getDatetime() const
    {
      if (isNull())
        throw NullValue();

      switch (type)
      {
        case SQLT_DAT:
        case SQLT_TIMESTAMP:
        case SQLT_TIMESTAMP_TZ:
        case SQLT_TIMESTAMP_LTZ:
          return datetime.getDatetime();

        default:
          throw TypeError();
      }
    }

  }
}
<|endoftext|>


<commit_before>//===-- ARMJITInfo.cpp - Implement the JIT interfaces for the ARM target --===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the JIT interfaces for the ARM target.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "jit"
#include "ARMJITInfo.h"
#include "ARMInstrInfo.h"
#include "ARMConstantPoolValue.h"
#include "ARMRelocations.h"
#include "ARMSubtarget.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/JITCodeEmitter.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Memory.h"
#include <cstdlib>
using namespace llvm;

void ARMJITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
  llvm_report_error("ARMJITInfo::replaceMachineCodeForFunction");
}

/// JITCompilerFunction - This contains the address of the JIT function used to
/// compile a function lazily.
static TargetJITInfo::JITCompilerFn JITCompilerFunction;

// Get the ASMPREFIX for the current host.  This is often '_'.
#ifndef __USER_LABEL_PREFIX__
#define __USER_LABEL_PREFIX__
#endif
#define GETASMPREFIX2(X) #X
#define GETASMPREFIX(X) GETASMPREFIX2(X)
#define ASMPREFIX GETASMPREFIX(__USER_LABEL_PREFIX__)

// CompilationCallback stub - We can't use a C function with inline assembly in
// it, because we the prolog/epilog inserted by GCC won't work for us (we need
// to preserve more context and manipulate the stack directly).  Instead,
// write our own wrapper, which does things our way, so we have complete
// control over register saving and restoring.
extern "C" {
#if defined(__arm__)
  void ARMCompilationCallback();
  asm(
    ".text\n"
    ".align 2\n"
    ".globl " ASMPREFIX "ARMCompilationCallback\n"
    ASMPREFIX "ARMCompilationCallback:\n"
    // Save caller saved registers since they may contain stuff
    // for the real target function right now. We have to act as if this
    // whole compilation callback doesn't exist as far as the caller is
    // concerned, so we can't just preserve the callee saved regs.
    "stmdb sp!, {r0, r1, r2, r3, lr}\n"
#if defined(__VFP_FP__) && !defined(__SOFTFP__))
    "fstmfdd sp!, {d0, d1, d2, d3, d4, d5, d6, d7}\n"
#endif
    // The LR contains the address of the stub function on entry.
    // pass it as the argument to the C part of the callback
    "mov  r0, lr\n"
    "sub  sp, sp, #4\n"
    // Call the C portion of the callback
    "bl   " ASMPREFIX "ARMCompilationCallbackC\n"
    "add  sp, sp, #4\n"
    // Restoring the LR to the return address of the function that invoked
    // the stub and de-allocating the stack space for it requires us to
    // swap the two saved LR values on the stack, as they're backwards
    // for what we need since the pop instruction has a pre-determined
    // order for the registers.
    //      +--------+
    //   0  | LR     | Original return address
    //      +--------+
    //   1  | LR     | Stub address (start of stub)
    // 2-5  | R3..R0 | Saved registers (we need to preserve all regs)
    // 6-20 | D0..D7 | Saved VFP registers
    //      +--------+
    //
#if defined(__VFP_FP__) && !defined(__SOFTFP__))
    // Restore VFP caller-saved registers.
    "fldmfdd sp!, {d0, d1, d2, d3, d4, d5, d6, d7}\n"
#endif
    //
    //      We need to exchange the values in slots 0 and 1 so we can
    //      return to the address in slot 1 with the address in slot 0
    //      restored to the LR.
    "ldr  r0, [sp,#20]\n"
    "ldr  r1, [sp,#16]\n"
    "str  r1, [sp,#20]\n"
    "str  r0, [sp,#16]\n"
    // Return to the (newly modified) stub to invoke the real function.
    // The above twiddling of the saved return addresses allows us to
    // deallocate everything, including the LR the stub saved, all in one
    // pop instruction.
    "ldmia  sp!, {r0, r1, r2, r3, lr, pc}\n"
      );
#else  // Not an ARM host
  void ARMCompilationCallback() {
    llvm_unreachable("Cannot call ARMCompilationCallback() on a non-ARM arch!");
  }
#endif
}

/// ARMCompilationCallbackC - This is the target-specific function invoked
/// by the function stub when we did not know the real target of a call.
/// This function must locate the start of the stub or call site and pass
/// it into the JIT compiler function.
extern "C" void ARMCompilationCallbackC(intptr_t StubAddr) {
  // Get the address of the compiled code for this function.
  intptr_t NewVal = (intptr_t)JITCompilerFunction((void*)StubAddr);

  // Rewrite the call target... so that we don't end up here every time we
  // execute the call. We're replacing the first two instructions of the
  // stub with:
  //   ldr pc, [pc,#-4]
  //   <addr>
  if (!sys::Memory::setRangeWritable((void*)StubAddr, 8)) {
    llvm_unreachable("ERROR: Unable to mark stub writable");
  }
  *(intptr_t *)StubAddr = 0xe51ff004;  // ldr pc, [pc, #-4]
  *(intptr_t *)(StubAddr+4) = NewVal;
  if (!sys::Memory::setRangeExecutable((void*)StubAddr, 8)) {
    llvm_unreachable("ERROR: Unable to mark stub executable");
  }
}

TargetJITInfo::LazyResolverFn
ARMJITInfo::getLazyResolverFunction(JITCompilerFn F) {
  JITCompilerFunction = F;
  return ARMCompilationCallback;
}

void *ARMJITInfo::emitGlobalValueIndirectSym(const GlobalValue *GV, void *Ptr,
                                             JITCodeEmitter &JCE) {
  uint8_t Buffer[4];
  uint8_t *Cur = Buffer;
  MachineCodeEmitter::emitWordLEInto(Cur, (intptr_t)Ptr);
  void *PtrAddr = JCE.allocIndirectGV(
      GV, Buffer, sizeof(Buffer), /*Alignment=*/4);
  addIndirectSymAddr(Ptr, (intptr_t)PtrAddr);
  return PtrAddr;
}

TargetJITInfo::StubLayout ARMJITInfo::getStubLayout() {
  // The stub contains up to 3 4-byte instructions, aligned at 4 bytes, and a
  // 4-byte address.  See emitFunctionStub for details.
  StubLayout Result = {16, 4};
  return Result;
}

void *ARMJITInfo::emitFunctionStub(const Function* F, void *Fn,
                                   JITCodeEmitter &JCE) {
  void *Addr;
  // If this is just a call to an external function, emit a branch instead of a
  // call.  The code is the same except for one bit of the last instruction.
  if (Fn != (void*)(intptr_t)ARMCompilationCallback) {
    // Branch to the corresponding function addr.
    if (IsPIC) {
      // The stub is 16-byte size and 4-aligned.
      intptr_t LazyPtr = getIndirectSymAddr(Fn);
      if (!LazyPtr) {
        // In PIC mode, the function stub is loading a lazy-ptr.
        LazyPtr= (intptr_t)emitGlobalValueIndirectSym((GlobalValue*)F, Fn, JCE);
        DEBUG(if (F)
                errs() << "JIT: Indirect symbol emitted at [" << LazyPtr
                       << "] for GV '" << F->getName() << "'\n";
              else
                errs() << "JIT: Stub emitted at [" << LazyPtr
                       << "] for external function at '" << Fn << "'\n");
      }
      JCE.emitAlignment(4);
      Addr = (void*)JCE.getCurrentPCValue();
      if (!sys::Memory::setRangeWritable(Addr, 16)) {
        llvm_unreachable("ERROR: Unable to mark stub writable");
      }
      JCE.emitWordLE(0xe59fc004);            // ldr ip, [pc, #+4]
      JCE.emitWordLE(0xe08fc00c);            // L_func$scv: add ip, pc, ip
      JCE.emitWordLE(0xe59cf000);            // ldr pc, [ip]
      JCE.emitWordLE(LazyPtr - (intptr_t(Addr)+4+8));  // func - (L_func$scv+8)
      sys::Memory::InvalidateInstructionCache(Addr, 16);
      if (!sys::Memory::setRangeExecutable(Addr, 16)) {
        llvm_unreachable("ERROR: Unable to mark stub executable");
      }
    } else {
      // The stub is 8-byte size and 4-aligned.
      JCE.emitAlignment(4);
      Addr = (void*)JCE.getCurrentPCValue();
      if (!sys::Memory::setRangeWritable(Addr, 8)) {
        llvm_unreachable("ERROR: Unable to mark stub writable");
      }
      JCE.emitWordLE(0xe51ff004);    // ldr pc, [pc, #-4]
      JCE.emitWordLE((intptr_t)Fn);  // addr of function
      sys::Memory::InvalidateInstructionCache(Addr, 8);
      if (!sys::Memory::setRangeExecutable(Addr, 8)) {
        llvm_unreachable("ERROR: Unable to mark stub executable");
      }
    }
  } else {
    // The compilation callback will overwrite the first two words of this
    // stub with indirect branch instructions targeting the compiled code.
    // This stub sets the return address to restart the stub, so that
    // the new branch will be invoked when we come back.
    //
    // Branch and link to the compilation callback.
    // The stub is 16-byte size and 4-byte aligned.
    JCE.emitAlignment(4);
    Addr = (void*)JCE.getCurrentPCValue();
    if (!sys::Memory::setRangeWritable(Addr, 16)) {
      llvm_unreachable("ERROR: Unable to mark stub writable");
    }
    // Save LR so the callback can determine which stub called it.
    // The compilation callback is responsible for popping this prior
    // to returning.
    JCE.emitWordLE(0xe92d4000); // push {lr}
    // Set the return address to go back to the start of this stub.
    JCE.emitWordLE(0xe24fe00c); // sub lr, pc, #12
    // Invoke the compilation callback.
    JCE.emitWordLE(0xe51ff004); // ldr pc, [pc, #-4]
    // The address of the compilation callback.
    JCE.emitWordLE((intptr_t)ARMCompilationCallback);
    sys::Memory::InvalidateInstructionCache(Addr, 16);
    if (!sys::Memory::setRangeExecutable(Addr, 16)) {
      llvm_unreachable("ERROR: Unable to mark stub executable");
    }
  }

  return Addr;
}

intptr_t ARMJITInfo::resolveRelocDestAddr(MachineRelocation *MR) const {
  ARM::RelocationType RT = (ARM::RelocationType)MR->getRelocationType();
  switch (RT) {
  default:
    return (intptr_t)(MR->getResultPointer());
  case ARM::reloc_arm_pic_jt:
    // Destination address - jump table base.
    return (intptr_t)(MR->getResultPointer()) - MR->getConstantVal();
  case ARM::reloc_arm_jt_base:
    // Jump table base address.
    return getJumpTableBaseAddr(MR->getJumpTableIndex());
  case ARM::reloc_arm_cp_entry:
  case ARM::reloc_arm_vfp_cp_entry:
    // Constant pool entry address.
    return getConstantPoolEntryAddr(MR->getConstantPoolIndex());
  case ARM::reloc_arm_machine_cp_entry: {
    ARMConstantPoolValue *ACPV = (ARMConstantPoolValue*)MR->getConstantVal();
    assert((!ACPV->hasModifier() && !ACPV->mustAddCurrentAddress()) &&
           "Can't handle this machine constant pool entry yet!");
    intptr_t Addr = (intptr_t)(MR->getResultPointer());
    Addr -= getPCLabelAddr(ACPV->getLabelId()) + ACPV->getPCAdjustment();
    return Addr;
  }
  }
}

/// relocate - Before the JIT can run a block of code that has been emitted,
/// it must rewrite the code to contain the actual addresses of any
/// referenced global symbols.
void ARMJITInfo::relocate(void *Function, MachineRelocation *MR,
                          unsigned NumRelocs, unsigned char* GOTBase) {
  for (unsigned i = 0; i != NumRelocs; ++i, ++MR) {
    void *RelocPos = (char*)Function + MR->getMachineCodeOffset();
    intptr_t ResultPtr = resolveRelocDestAddr(MR);
    switch ((ARM::RelocationType)MR->getRelocationType()) {
    case ARM::reloc_arm_cp_entry:
    case ARM::reloc_arm_vfp_cp_entry:
    case ARM::reloc_arm_relative: {
      // It is necessary to calculate the correct PC relative value. We
      // subtract the base addr from the target addr to form a byte offset.
      ResultPtr = ResultPtr - (intptr_t)RelocPos - 8;
      // If the result is positive, set bit U(23) to 1.
      if (ResultPtr >= 0)
        *((intptr_t*)RelocPos) |= 1 << ARMII::U_BitShift;
      else {
        // Otherwise, obtain the absolute value and set bit U(23) to 0.
        *((intptr_t*)RelocPos) &= ~(1 << ARMII::U_BitShift);
        ResultPtr = - ResultPtr;
      }
      // Set the immed value calculated.
      // VFP immediate offset is multiplied by 4.
      if (MR->getRelocationType() == ARM::reloc_arm_vfp_cp_entry)
        ResultPtr = ResultPtr >> 2;
      *((intptr_t*)RelocPos) |= ResultPtr;
      // Set register Rn to PC.
      *((intptr_t*)RelocPos) |=
        ARMRegisterInfo::getRegisterNumbering(ARM::PC) << ARMII::RegRnShift;
      break;
    }
    case ARM::reloc_arm_pic_jt:
    case ARM::reloc_arm_machine_cp_entry:
    case ARM::reloc_arm_absolute: {
      // These addresses have already been resolved.
      *((intptr_t*)RelocPos) |= (intptr_t)ResultPtr;
      break;
    }
    case ARM::reloc_arm_branch: {
      // It is necessary to calculate the correct value of signed_immed_24
      // field. We subtract the base addr from the target addr to form a
      // byte offset, which must be inside the range -33554432 and +33554428.
      // Then, we set the signed_immed_24 field of the instruction to bits
      // [25:2] of the byte offset. More details ARM-ARM p. A4-11.
      ResultPtr = ResultPtr - (intptr_t)RelocPos - 8;
      ResultPtr = (ResultPtr & 0x03FFFFFC) >> 2;
      assert(ResultPtr >= -33554432 && ResultPtr <= 33554428);
      *((intptr_t*)RelocPos) |= ResultPtr;
      break;
    }
    case ARM::reloc_arm_jt_base: {
      // JT base - (instruction addr + 8)
      ResultPtr = ResultPtr - (intptr_t)RelocPos - 8;
      *((intptr_t*)RelocPos) |= ResultPtr;
      break;
    }
    }
  }
}
<commit_msg>fix typo add missing (<commit_after>//===-- ARMJITInfo.cpp - Implement the JIT interfaces for the ARM target --===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the JIT interfaces for the ARM target.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "jit"
#include "ARMJITInfo.h"
#include "ARMInstrInfo.h"
#include "ARMConstantPoolValue.h"
#include "ARMRelocations.h"
#include "ARMSubtarget.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/JITCodeEmitter.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Memory.h"
#include <cstdlib>
using namespace llvm;

void ARMJITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
  llvm_report_error("ARMJITInfo::replaceMachineCodeForFunction");
}

/// JITCompilerFunction - This contains the address of the JIT function used to
/// compile a function lazily.
static TargetJITInfo::JITCompilerFn JITCompilerFunction;

// Get the ASMPREFIX for the current host.  This is often '_'.
#ifndef __USER_LABEL_PREFIX__
#define __USER_LABEL_PREFIX__
#endif
#define GETASMPREFIX2(X) #X
#define GETASMPREFIX(X) GETASMPREFIX2(X)
#define ASMPREFIX GETASMPREFIX(__USER_LABEL_PREFIX__)

// CompilationCallback stub - We can't use a C function with inline assembly in
// it, because we the prolog/epilog inserted by GCC won't work for us (we need
// to preserve more context and manipulate the stack directly).  Instead,
// write our own wrapper, which does things our way, so we have complete
// control over register saving and restoring.
extern "C" {
#if defined(__arm__)
  void ARMCompilationCallback();
  asm(
    ".text\n"
    ".align 2\n"
    ".globl " ASMPREFIX "ARMCompilationCallback\n"
    ASMPREFIX "ARMCompilationCallback:\n"
    // Save caller saved registers since they may contain stuff
    // for the real target function right now. We have to act as if this
    // whole compilation callback doesn't exist as far as the caller is
    // concerned, so we can't just preserve the callee saved regs.
    "stmdb sp!, {r0, r1, r2, r3, lr}\n"
#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
    "fstmfdd sp!, {d0, d1, d2, d3, d4, d5, d6, d7}\n"
#endif
    // The LR contains the address of the stub function on entry.
    // pass it as the argument to the C part of the callback
    "mov  r0, lr\n"
    "sub  sp, sp, #4\n"
    // Call the C portion of the callback
    "bl   " ASMPREFIX "ARMCompilationCallbackC\n"
    "add  sp, sp, #4\n"
    // Restoring the LR to the return address of the function that invoked
    // the stub and de-allocating the stack space for it requires us to
    // swap the two saved LR values on the stack, as they're backwards
    // for what we need since the pop instruction has a pre-determined
    // order for the registers.
    //      +--------+
    //   0  | LR     | Original return address
    //      +--------+
    //   1  | LR     | Stub address (start of stub)
    // 2-5  | R3..R0 | Saved registers (we need to preserve all regs)
    // 6-20 | D0..D7 | Saved VFP registers
    //      +--------+
    //
#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
    // Restore VFP caller-saved registers.
    "fldmfdd sp!, {d0, d1, d2, d3, d4, d5, d6, d7}\n"
#endif
    //
    //      We need to exchange the values in slots 0 and 1 so we can
    //      return to the address in slot 1 with the address in slot 0
    //      restored to the LR.
    "ldr  r0, [sp,#20]\n"
    "ldr  r1, [sp,#16]\n"
    "str  r1, [sp,#20]\n"
    "str  r0, [sp,#16]\n"
    // Return to the (newly modified) stub to invoke the real function.
    // The above twiddling of the saved return addresses allows us to
    // deallocate everything, including the LR the stub saved, all in one
    // pop instruction.
    "ldmia  sp!, {r0, r1, r2, r3, lr, pc}\n"
      );
#else  // Not an ARM host
  void ARMCompilationCallback() {
    llvm_unreachable("Cannot call ARMCompilationCallback() on a non-ARM arch!");
  }
#endif
}

/// ARMCompilationCallbackC - This is the target-specific function invoked
/// by the function stub when we did not know the real target of a call.
/// This function must locate the start of the stub or call site and pass
/// it into the JIT compiler function.
extern "C" void ARMCompilationCallbackC(intptr_t StubAddr) {
  // Get the address of the compiled code for this function.
  intptr_t NewVal = (intptr_t)JITCompilerFunction((void*)StubAddr);

  // Rewrite the call target... so that we don't end up here every time we
  // execute the call. We're replacing the first two instructions of the
  // stub with:
  //   ldr pc, [pc,#-4]
  //   <addr>
  if (!sys::Memory::setRangeWritable((void*)StubAddr, 8)) {
    llvm_unreachable("ERROR: Unable to mark stub writable");
  }
  *(intptr_t *)StubAddr = 0xe51ff004;  // ldr pc, [pc, #-4]
  *(intptr_t *)(StubAddr+4) = NewVal;
  if (!sys::Memory::setRangeExecutable((void*)StubAddr, 8)) {
    llvm_unreachable("ERROR: Unable to mark stub executable");
  }
}

TargetJITInfo::LazyResolverFn
ARMJITInfo::getLazyResolverFunction(JITCompilerFn F) {
  JITCompilerFunction = F;
  return ARMCompilationCallback;
}

void *ARMJITInfo::emitGlobalValueIndirectSym(const GlobalValue *GV, void *Ptr,
                                             JITCodeEmitter &JCE) {
  uint8_t Buffer[4];
  uint8_t *Cur = Buffer;
  MachineCodeEmitter::emitWordLEInto(Cur, (intptr_t)Ptr);
  void *PtrAddr = JCE.allocIndirectGV(
      GV, Buffer, sizeof(Buffer), /*Alignment=*/4);
  addIndirectSymAddr(Ptr, (intptr_t)PtrAddr);
  return PtrAddr;
}

TargetJITInfo::StubLayout ARMJITInfo::getStubLayout() {
  // The stub contains up to 3 4-byte instructions, aligned at 4 bytes, and a
  // 4-byte address.  See emitFunctionStub for details.
  StubLayout Result = {16, 4};
  return Result;
}

void *ARMJITInfo::emitFunctionStub(const Function* F, void *Fn,
                                   JITCodeEmitter &JCE) {
  void *Addr;
  // If this is just a call to an external function, emit a branch instead of a
  // call.  The code is the same except for one bit of the last instruction.
  if (Fn != (void*)(intptr_t)ARMCompilationCallback) {
    // Branch to the corresponding function addr.
    if (IsPIC) {
      // The stub is 16-byte size and 4-aligned.
      intptr_t LazyPtr = getIndirectSymAddr(Fn);
      if (!LazyPtr) {
        // In PIC mode, the function stub is loading a lazy-ptr.
        LazyPtr= (intptr_t)emitGlobalValueIndirectSym((GlobalValue*)F, Fn, JCE);
        DEBUG(if (F)
                errs() << "JIT: Indirect symbol emitted at [" << LazyPtr
                       << "] for GV '" << F->getName() << "'\n";
              else
                errs() << "JIT: Stub emitted at [" << LazyPtr
                       << "] for external function at '" << Fn << "'\n");
      }
      JCE.emitAlignment(4);
      Addr = (void*)JCE.getCurrentPCValue();
      if (!sys::Memory::setRangeWritable(Addr, 16)) {
        llvm_unreachable("ERROR: Unable to mark stub writable");
      }
      JCE.emitWordLE(0xe59fc004);            // ldr ip, [pc, #+4]
      JCE.emitWordLE(0xe08fc00c);            // L_func$scv: add ip, pc, ip
      JCE.emitWordLE(0xe59cf000);            // ldr pc, [ip]
      JCE.emitWordLE(LazyPtr - (intptr_t(Addr)+4+8));  // func - (L_func$scv+8)
      sys::Memory::InvalidateInstructionCache(Addr, 16);
      if (!sys::Memory::setRangeExecutable(Addr, 16)) {
        llvm_unreachable("ERROR: Unable to mark stub executable");
      }
    } else {
      // The stub is 8-byte size and 4-aligned.
      JCE.emitAlignment(4);
      Addr = (void*)JCE.getCurrentPCValue();
      if (!sys::Memory::setRangeWritable(Addr, 8)) {
        llvm_unreachable("ERROR: Unable to mark stub writable");
      }
      JCE.emitWordLE(0xe51ff004);    // ldr pc, [pc, #-4]
      JCE.emitWordLE((intptr_t)Fn);  // addr of function
      sys::Memory::InvalidateInstructionCache(Addr, 8);
      if (!sys::Memory::setRangeExecutable(Addr, 8)) {
        llvm_unreachable("ERROR: Unable to mark stub executable");
      }
    }
  } else {
    // The compilation callback will overwrite the first two words of this
    // stub with indirect branch instructions targeting the compiled code.
    // This stub sets the return address to restart the stub, so that
    // the new branch will be invoked when we come back.
    //
    // Branch and link to the compilation callback.
    // The stub is 16-byte size and 4-byte aligned.
    JCE.emitAlignment(4);
    Addr = (void*)JCE.getCurrentPCValue();
    if (!sys::Memory::setRangeWritable(Addr, 16)) {
      llvm_unreachable("ERROR: Unable to mark stub writable");
    }
    // Save LR so the callback can determine which stub called it.
    // The compilation callback is responsible for popping this prior
    // to returning.
    JCE.emitWordLE(0xe92d4000); // push {lr}
    // Set the return address to go back to the start of this stub.
    JCE.emitWordLE(0xe24fe00c); // sub lr, pc, #12
    // Invoke the compilation callback.
    JCE.emitWordLE(0xe51ff004); // ldr pc, [pc, #-4]
    // The address of the compilation callback.
    JCE.emitWordLE((intptr_t)ARMCompilationCallback);
    sys::Memory::InvalidateInstructionCache(Addr, 16);
    if (!sys::Memory::setRangeExecutable(Addr, 16)) {
      llvm_unreachable("ERROR: Unable to mark stub executable");
    }
  }

  return Addr;
}

intptr_t ARMJITInfo::resolveRelocDestAddr(MachineRelocation *MR) const {
  ARM::RelocationType RT = (ARM::RelocationType)MR->getRelocationType();
  switch (RT) {
  default:
    return (intptr_t)(MR->getResultPointer());
  case ARM::reloc_arm_pic_jt:
    // Destination address - jump table base.
    return (intptr_t)(MR->getResultPointer()) - MR->getConstantVal();
  case ARM::reloc_arm_jt_base:
    // Jump table base address.
    return getJumpTableBaseAddr(MR->getJumpTableIndex());
  case ARM::reloc_arm_cp_entry:
  case ARM::reloc_arm_vfp_cp_entry:
    // Constant pool entry address.
    return getConstantPoolEntryAddr(MR->getConstantPoolIndex());
  case ARM::reloc_arm_machine_cp_entry: {
    ARMConstantPoolValue *ACPV = (ARMConstantPoolValue*)MR->getConstantVal();
    assert((!ACPV->hasModifier() && !ACPV->mustAddCurrentAddress()) &&
           "Can't handle this machine constant pool entry yet!");
    intptr_t Addr = (intptr_t)(MR->getResultPointer());
    Addr -= getPCLabelAddr(ACPV->getLabelId()) + ACPV->getPCAdjustment();
    return Addr;
  }
  }
}

/// relocate - Before the JIT can run a block of code that has been emitted,
/// it must rewrite the code to contain the actual addresses of any
/// referenced global symbols.
void ARMJITInfo::relocate(void *Function, MachineRelocation *MR,
                          unsigned NumRelocs, unsigned char* GOTBase) {
  for (unsigned i = 0; i != NumRelocs; ++i, ++MR) {
    void *RelocPos = (char*)Function + MR->getMachineCodeOffset();
    intptr_t ResultPtr = resolveRelocDestAddr(MR);
    switch ((ARM::RelocationType)MR->getRelocationType()) {
    case ARM::reloc_arm_cp_entry:
    case ARM::reloc_arm_vfp_cp_entry:
    case ARM::reloc_arm_relative: {
      // It is necessary to calculate the correct PC relative value. We
      // subtract the base addr from the target addr to form a byte offset.
      ResultPtr = ResultPtr - (intptr_t)RelocPos - 8;
      // If the result is positive, set bit U(23) to 1.
      if (ResultPtr >= 0)
        *((intptr_t*)RelocPos) |= 1 << ARMII::U_BitShift;
      else {
        // Otherwise, obtain the absolute value and set bit U(23) to 0.
        *((intptr_t*)RelocPos) &= ~(1 << ARMII::U_BitShift);
        ResultPtr = - ResultPtr;
      }
      // Set the immed value calculated.
      // VFP immediate offset is multiplied by 4.
      if (MR->getRelocationType() == ARM::reloc_arm_vfp_cp_entry)
        ResultPtr = ResultPtr >> 2;
      *((intptr_t*)RelocPos) |= ResultPtr;
      // Set register Rn to PC.
      *((intptr_t*)RelocPos) |=
        ARMRegisterInfo::getRegisterNumbering(ARM::PC) << ARMII::RegRnShift;
      break;
    }
    case ARM::reloc_arm_pic_jt:
    case ARM::reloc_arm_machine_cp_entry:
    case ARM::reloc_arm_absolute: {
      // These addresses have already been resolved.
      *((intptr_t*)RelocPos) |= (intptr_t)ResultPtr;
      break;
    }
    case ARM::reloc_arm_branch: {
      // It is necessary to calculate the correct value of signed_immed_24
      // field. We subtract the base addr from the target addr to form a
      // byte offset, which must be inside the range -33554432 and +33554428.
      // Then, we set the signed_immed_24 field of the instruction to bits
      // [25:2] of the byte offset. More details ARM-ARM p. A4-11.
      ResultPtr = ResultPtr - (intptr_t)RelocPos - 8;
      ResultPtr = (ResultPtr & 0x03FFFFFC) >> 2;
      assert(ResultPtr >= -33554432 && ResultPtr <= 33554428);
      *((intptr_t*)RelocPos) |= ResultPtr;
      break;
    }
    case ARM::reloc_arm_jt_base: {
      // JT base - (instruction addr + 8)
      ResultPtr = ResultPtr - (intptr_t)RelocPos - 8;
      *((intptr_t*)RelocPos) |= ResultPtr;
      break;
    }
    }
  }
}
<|endoftext|>


<commit_before>/* Begin CVS Header
   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/sensitivities/CSensProblem.cpp,v $
   $Revision: 1.11 $
   $Name:  $
   $Author: ssahle $
   $Date: 2006/06/29 14:12:18 $
   End CVS Header */

// Copyright  2005 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

#include <string>

#include "copasi.h"
#include "CSensProblem.h"
#include "CopasiDataModel/CCopasiDataModel.h"

bool CSensItem::isSingleObject() const
  {
    return mIsSingleObject;
  }

void CSensItem::setSingleObjectCN(const CCopasiObjectName & cn)
{
  mSingleObjectCN = cn;
  mIsSingleObject = true;
}

const CCopasiObjectName & CSensItem::getSingleObjectCN() const
  {
    return mSingleObjectCN;
  }

std::string CSensItem::getSingleObjectDisplayName() const
  {
    CCopasiObject* tmpObject = CCopasiContainer::ObjectFromName(mSingleObjectCN);
    if (tmpObject)
      return tmpObject->getObjectDisplayName();
    else
      return "";
  }

void CSensItem::setListType(CObjectLists::ListType lt)
{
  mListType = lt;
  mIsSingleObject = false;
}

const CObjectLists::ListType & CSensItem::getListType() const
  {
    return mListType;
  }

std::string CSensItem::getListTypeDisplayName() const
  {
    return "";
  }

//************************ CSensProblem ***************************

const std::string CSensProblem::SubTaskName[] =
  {
    "Not Set",
    "Steady State",
    "Time Series",
    "Lyapunov Exponents",
    ""
  };

const char * CSensProblem::XMLSubTask[] =
  {
    "NotSet",
    "SteadyState",
    "TimeSeries",
    "LyapunovExponents",
    NULL
  };

//static
void CSensProblem::createParametersInGroup(CCopasiParameterGroup *pg)
{
  if (!pg) return;

  pg->addParameter("SingleObject", CCopasiParameter::CN, CCopasiObjectName(""));
  pg->addParameter("ObjectListType", CCopasiParameter::UINT, (unsigned C_INT32) 0);
}

//static
void CSensProblem::copySensItemToParameterGroup(const CSensItem * si, CCopasiParameterGroup *pg)
{
  if (!pg) return; if (!si) return;

  if (si->isSingleObject())
    pg->setValue("SingleObject", si->getSingleObjectCN());
  else
    pg->setValue("ObjectListType", (unsigned C_INT32)si->getListType());
}

//static
void CSensProblem::copyParameterGroupToSensItem(const CCopasiParameterGroup *pg, CSensItem * si)
{
  if (!pg) return; if (!si) return;

  CCopasiObjectName* pCN = pg->getValue("SingleObject").pCN;
  CObjectLists::ListType* pLT = (CObjectLists::ListType*)pg->getValue("ObjectListType").pUINT;

  CCopasiObjectName cn("");
  if (pCN) cn = *pCN;

  CObjectLists::ListType lt = (CObjectLists::ListType)0;
  if (pLT) lt = *pLT;

  if (cn != "")
    si->setSingleObjectCN(cn);
  else
    si->setListType(lt);
}

/**
 *  Default constructor.
 *  @param "CModel *" pModel
 */
CSensProblem::CSensProblem(const CCopasiContainer * pParent):
    CCopasiProblem(CCopasiTask::sens, pParent),
    mpSubTaskType(NULL),
    mpTargetFunctions(NULL),
    mpVariablesGroup(NULL)
{
  addParameter("SubtaskType", CCopasiParameter::UINT, (unsigned C_INT32) 0);
  mpSubTaskType = (CSensProblem::SubTaskType*)getValue("SubtaskType").pUINT;

  //---------------------------------------------------
  addGroup("TargetFunctions");
  mpTargetFunctions = dynamic_cast<CCopasiParameterGroup*>(getParameter("TargetFunctions"));
  createParametersInGroup(mpTargetFunctions);

  //---------------------------------------------------
  addGroup("ListOfVariables");
  mpVariablesGroup = dynamic_cast<CCopasiParameterGroup*>(getParameter("ListOfVariables"));

  //initDebugProblem();
  CONSTRUCTOR_TRACE;
}

/**
 *  Copy constructor.
 *  @param "const CSensProblem &" src
 */
CSensProblem::CSensProblem(const CSensProblem & src,
                           const CCopasiContainer * pParent):
    CCopasiProblem(src, pParent),
    mpSubTaskType(NULL),
    mpTargetFunctions(NULL),
    mpVariablesGroup(NULL)
{
  mpSubTaskType = (CSensProblem::SubTaskType*)getValue("SubtaskType").pUINT;
  mpTargetFunctions = dynamic_cast<CCopasiParameterGroup*>(getParameter("TargetFunctions"));
  mpVariablesGroup = dynamic_cast<CCopasiParameterGroup*>(getParameter("ListOfVariables"));
  CONSTRUCTOR_TRACE;
}

/**
 *  Destructor.
 */
CSensProblem::~CSensProblem()
{DESTRUCTOR_TRACE;}

/**
 *   set the problem's SubTaskType:
 */
void
CSensProblem::setSubTaskType(const CSensProblem::SubTaskType & type)
{*mpSubTaskType = type;}

/**
 *   get the problem's SubTaskType:
 **/
const CSensProblem::SubTaskType
CSensProblem::getSubTaskType() const
  {
    if (mpSubTaskType)
      return *mpSubTaskType;
    else
      return CSensProblem::unset;
  }

CSensItem CSensProblem::getTargetFunctions() const
  {
    //    return mTargetFunctions;
  }

unsigned C_INT32 CSensProblem::getNumberOfVariables() const
  {
    return mpVariablesGroup->size();
  }

CSensItem CSensProblem::getVariables(unsigned C_INT32 index) const
  {}

void CSensProblem::addVariables(const CSensItem & item)
{
  //create parameter group corresponding to sens item
  CCopasiParameterGroup* tmp;
  mpVariablesGroup->addGroup("Variables");
  tmp = (CCopasiParameterGroup*)(mpVariablesGroup->getParameter(getNumberOfVariables() - 1));

  createParametersInGroup(tmp);

  copySensItemToParameterGroup(&item, tmp);
}

//static
std::vector<CObjectLists::ListType>
CSensProblem::getPossibleTargetFunctions(CSensProblem::SubTaskType type)
{
  std::vector<CObjectLists::ListType> list;

  // the 'unset' type, abusing CObjectLists::ALL_METABS
  list.push_back((CObjectLists::ListType) 0);

  // Add new functions here, under applicable SubTaskType case.
  // Don't forget to provide for a string value in
  //   getTargetFunctionName()
  switch (type)
    {
    case (CSensProblem::unset):
            // all available target functions
            list.push_back(CObjectLists::NON_CONST_METAB_CONCENTRATIONS);
      list.push_back(CObjectLists::NON_CONST_METAB_NUMBERS);
      list.push_back(CObjectLists::NON_CONST_METAB_CONC_RATES);
      list.push_back(CObjectLists::NON_CONST_METAB_PART_RATES);
      list.push_back(CObjectLists::REACTION_CONC_FLUXES);
      list.push_back(CObjectLists::REACTION_PART_FLUXES);
      break;

    case (CSensProblem::SteadyState):
            list.push_back(CObjectLists::NON_CONST_METAB_NUMBERS);
      list.push_back(CObjectLists::NON_CONST_METAB_CONC_RATES);
      list.push_back(CObjectLists::REACTION_CONC_FLUXES);
      list.push_back(CObjectLists::REACTION_PART_FLUXES);
      break;

    case (CSensProblem::TimeSeries):
            list.push_back(CObjectLists::NON_CONST_METAB_CONCENTRATIONS);
      list.push_back(CObjectLists::NON_CONST_METAB_CONC_RATES);
      list.push_back(CObjectLists::NON_CONST_METAB_PART_RATES);
      list.push_back(CObjectLists::REACTION_PART_FLUXES);
      break;

    case (CSensProblem::LyapunovExp):
            list.push_back(CObjectLists::NON_CONST_METAB_NUMBERS);
      list.push_back(CObjectLists::NON_CONST_METAB_CONCENTRATIONS);
      list.push_back(CObjectLists::REACTION_CONC_FLUXES);
      list.push_back(CObjectLists::NON_CONST_METAB_PART_RATES);
      break;
    }

  return list;
}

//static
std::string
CSensProblem::getTargetFunctionName(CObjectLists::ListType objtype)
{
  std::string ret;

  switch (objtype)
    {
      // exception: here '0' means 'unset'
    case ((CObjectLists::ListType) 0):
            ret = "Not Set";
      break;

      // change the following!!!
      // ret values for proof of concept in SensitivitiesWidget
    case (CObjectLists::NON_CONST_METAB_CONCENTRATIONS):
            ret = "not there in SteadyState";
      break;

    case (CObjectLists::NON_CONST_METAB_NUMBERS):
            ret = "not there in TimeSeries";
      break;

    case (CObjectLists::NON_CONST_METAB_CONC_RATES):
            ret = "not there in LyapunovExponents";
      break;

    case (CObjectLists::NON_CONST_METAB_PART_RATES):
            ret = "not there in SteadyState";
      break;

    case (CObjectLists::REACTION_CONC_FLUXES):
            ret = "not there in TimeSeries";
      break;

    case (CObjectLists::REACTION_PART_FLUXES):
            ret = "not there in LyapunovExponents";
      break;

      //never get here
    default:
      ret = "Error:  Value not handled";
    }

  return ret;
}

//static
std::vector<CObjectLists::ListType>
CSensProblem::getPossibleVariables(CSensProblem::SubTaskType type)
{
  std::vector<CObjectLists::ListType> list;

  // the 'unset' type, abusing CObjectLists::ALL_METABS
  list.push_back((CObjectLists::ListType) 0);

  // Add new variables here, to applicable SubTaskType case.
  // Don't forget to provide for a string value in
  //   getVariableName()
  switch (type)
    {
    case (unset):
          case (SteadyState):
            case (TimeSeries):
              case (LyapunovExp):
                  // all available target functions
                  list.push_back(CObjectLists::NON_CONST_METAB_CONCENTRATIONS);
      list.push_back(CObjectLists::GLOBAL_PARAMETERS);
    }

  return list;
}

//static
std::string
CSensProblem::getVariableGroupName(CObjectLists::ListType objtype)
{
  std::string ret;

  switch (objtype)
    {
    case ((CObjectLists::ListType) 0):
            ret = "Not Set";
      break;

    case (CObjectLists::NON_CONST_METAB_CONCENTRATIONS):
            ret = "Global Parameters";
      break;

    case (CObjectLists::GLOBAL_PARAMETERS):
            ret = "Metabolite Concentrations";
      break;

    default:
      ret = "Error:  Value not handled";
    }

  return ret;
}

void CSensProblem::initDebugProblem()
{
  CSensItem item;

  item.setSingleObjectCN(this->getCN());
  addVariables(item);

  item.setListType(CObjectLists::NON_CONST_METABS);
  addVariables(item);
}
<commit_msg>Added missing return values to compile unter Visual C++ 6.0<commit_after>/* Begin CVS Header
   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/sensitivities/CSensProblem.cpp,v $
   $Revision: 1.12 $
   $Name:  $
   $Author: shoops $
   $Date: 2006/07/05 15:07:52 $
   End CVS Header */

// Copyright  2005 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

#include <string>

#include "copasi.h"
#include "CSensProblem.h"
#include "CopasiDataModel/CCopasiDataModel.h"

bool CSensItem::isSingleObject() const
  {
    return mIsSingleObject;
  }

void CSensItem::setSingleObjectCN(const CCopasiObjectName & cn)
{
  mSingleObjectCN = cn;
  mIsSingleObject = true;
}

const CCopasiObjectName & CSensItem::getSingleObjectCN() const
  {
    return mSingleObjectCN;
  }

std::string CSensItem::getSingleObjectDisplayName() const
  {
    CCopasiObject* tmpObject = CCopasiContainer::ObjectFromName(mSingleObjectCN);
    if (tmpObject)
      return tmpObject->getObjectDisplayName();
    else
      return "";
  }

void CSensItem::setListType(CObjectLists::ListType lt)
{
  mListType = lt;
  mIsSingleObject = false;
}

const CObjectLists::ListType & CSensItem::getListType() const
  {
    return mListType;
  }

std::string CSensItem::getListTypeDisplayName() const
  {
    return "";
  }

//************************ CSensProblem ***************************

const std::string CSensProblem::SubTaskName[] =
  {
    "Not Set",
    "Steady State",
    "Time Series",
    "Lyapunov Exponents",
    ""
  };

const char * CSensProblem::XMLSubTask[] =
  {
    "NotSet",
    "SteadyState",
    "TimeSeries",
    "LyapunovExponents",
    NULL
  };

//static
void CSensProblem::createParametersInGroup(CCopasiParameterGroup *pg)
{
  if (!pg) return;

  pg->addParameter("SingleObject", CCopasiParameter::CN, CCopasiObjectName(""));
  pg->addParameter("ObjectListType", CCopasiParameter::UINT, (unsigned C_INT32) 0);
}

//static
void CSensProblem::copySensItemToParameterGroup(const CSensItem * si, CCopasiParameterGroup *pg)
{
  if (!pg) return; if (!si) return;

  if (si->isSingleObject())
    pg->setValue("SingleObject", si->getSingleObjectCN());
  else
    pg->setValue("ObjectListType", (unsigned C_INT32)si->getListType());
}

//static
void CSensProblem::copyParameterGroupToSensItem(const CCopasiParameterGroup *pg, CSensItem * si)
{
  if (!pg) return; if (!si) return;

  CCopasiObjectName* pCN = pg->getValue("SingleObject").pCN;
  CObjectLists::ListType* pLT = (CObjectLists::ListType*)pg->getValue("ObjectListType").pUINT;

  CCopasiObjectName cn("");
  if (pCN) cn = *pCN;

  CObjectLists::ListType lt = (CObjectLists::ListType)0;
  if (pLT) lt = *pLT;

  if (cn != "")
    si->setSingleObjectCN(cn);
  else
    si->setListType(lt);
}

/**
 *  Default constructor.
 *  @param "CModel *" pModel
 */
CSensProblem::CSensProblem(const CCopasiContainer * pParent):
    CCopasiProblem(CCopasiTask::sens, pParent),
    mpSubTaskType(NULL),
    mpTargetFunctions(NULL),
    mpVariablesGroup(NULL)
{
  addParameter("SubtaskType", CCopasiParameter::UINT, (unsigned C_INT32) 0);
  mpSubTaskType = (CSensProblem::SubTaskType*)getValue("SubtaskType").pUINT;

  //---------------------------------------------------
  addGroup("TargetFunctions");
  mpTargetFunctions = dynamic_cast<CCopasiParameterGroup*>(getParameter("TargetFunctions"));
  createParametersInGroup(mpTargetFunctions);

  //---------------------------------------------------
  addGroup("ListOfVariables");
  mpVariablesGroup = dynamic_cast<CCopasiParameterGroup*>(getParameter("ListOfVariables"));

  //initDebugProblem();
  CONSTRUCTOR_TRACE;
}

/**
 *  Copy constructor.
 *  @param "const CSensProblem &" src
 */
CSensProblem::CSensProblem(const CSensProblem & src,
                           const CCopasiContainer * pParent):
    CCopasiProblem(src, pParent),
    mpSubTaskType(NULL),
    mpTargetFunctions(NULL),
    mpVariablesGroup(NULL)
{
  mpSubTaskType = (CSensProblem::SubTaskType*)getValue("SubtaskType").pUINT;
  mpTargetFunctions = dynamic_cast<CCopasiParameterGroup*>(getParameter("TargetFunctions"));
  mpVariablesGroup = dynamic_cast<CCopasiParameterGroup*>(getParameter("ListOfVariables"));
  CONSTRUCTOR_TRACE;
}

/**
 *  Destructor.
 */
CSensProblem::~CSensProblem()
{DESTRUCTOR_TRACE;}

/**
 *   set the problem's SubTaskType:
 */
void
CSensProblem::setSubTaskType(const CSensProblem::SubTaskType & type)
{*mpSubTaskType = type;}

/**
 *   get the problem's SubTaskType:
 **/
const CSensProblem::SubTaskType
CSensProblem::getSubTaskType() const
  {
    if (mpSubTaskType)
      return *mpSubTaskType;
    else
      return CSensProblem::unset;
  }

CSensItem CSensProblem::getTargetFunctions() const
  {
    return CSensItem();
  }

unsigned C_INT32 CSensProblem::getNumberOfVariables() const
  {
    return mpVariablesGroup->size();
  }

CSensItem CSensProblem::getVariables(unsigned C_INT32 index) const
  {
    return CSensItem();
  }

void CSensProblem::addVariables(const CSensItem & item)
{
  //create parameter group corresponding to sens item
  CCopasiParameterGroup* tmp;
  mpVariablesGroup->addGroup("Variables");
  tmp = (CCopasiParameterGroup*)(mpVariablesGroup->getParameter(getNumberOfVariables() - 1));

  createParametersInGroup(tmp);

  copySensItemToParameterGroup(&item, tmp);
}

//static
std::vector<CObjectLists::ListType>
CSensProblem::getPossibleTargetFunctions(CSensProblem::SubTaskType type)
{
  std::vector<CObjectLists::ListType> list;

  // the 'unset' type, abusing CObjectLists::ALL_METABS
  list.push_back((CObjectLists::ListType) 0);

  // Add new functions here, under applicable SubTaskType case.
  // Don't forget to provide for a string value in
  //   getTargetFunctionName()
  switch (type)
    {
    case (CSensProblem::unset):
            // all available target functions
            list.push_back(CObjectLists::NON_CONST_METAB_CONCENTRATIONS);
      list.push_back(CObjectLists::NON_CONST_METAB_NUMBERS);
      list.push_back(CObjectLists::NON_CONST_METAB_CONC_RATES);
      list.push_back(CObjectLists::NON_CONST_METAB_PART_RATES);
      list.push_back(CObjectLists::REACTION_CONC_FLUXES);
      list.push_back(CObjectLists::REACTION_PART_FLUXES);
      break;

    case (CSensProblem::SteadyState):
            list.push_back(CObjectLists::NON_CONST_METAB_NUMBERS);
      list.push_back(CObjectLists::NON_CONST_METAB_CONC_RATES);
      list.push_back(CObjectLists::REACTION_CONC_FLUXES);
      list.push_back(CObjectLists::REACTION_PART_FLUXES);
      break;

    case (CSensProblem::TimeSeries):
            list.push_back(CObjectLists::NON_CONST_METAB_CONCENTRATIONS);
      list.push_back(CObjectLists::NON_CONST_METAB_CONC_RATES);
      list.push_back(CObjectLists::NON_CONST_METAB_PART_RATES);
      list.push_back(CObjectLists::REACTION_PART_FLUXES);
      break;

    case (CSensProblem::LyapunovExp):
            list.push_back(CObjectLists::NON_CONST_METAB_NUMBERS);
      list.push_back(CObjectLists::NON_CONST_METAB_CONCENTRATIONS);
      list.push_back(CObjectLists::REACTION_CONC_FLUXES);
      list.push_back(CObjectLists::NON_CONST_METAB_PART_RATES);
      break;
    }

  return list;
}

//static
std::string
CSensProblem::getTargetFunctionName(CObjectLists::ListType objtype)
{
  std::string ret;

  switch (objtype)
    {
      // exception: here '0' means 'unset'
    case ((CObjectLists::ListType) 0):
            ret = "Not Set";
      break;

      // change the following!!!
      // ret values for proof of concept in SensitivitiesWidget
    case (CObjectLists::NON_CONST_METAB_CONCENTRATIONS):
            ret = "not there in SteadyState";
      break;

    case (CObjectLists::NON_CONST_METAB_NUMBERS):
            ret = "not there in TimeSeries";
      break;

    case (CObjectLists::NON_CONST_METAB_CONC_RATES):
            ret = "not there in LyapunovExponents";
      break;

    case (CObjectLists::NON_CONST_METAB_PART_RATES):
            ret = "not there in SteadyState";
      break;

    case (CObjectLists::REACTION_CONC_FLUXES):
            ret = "not there in TimeSeries";
      break;

    case (CObjectLists::REACTION_PART_FLUXES):
            ret = "not there in LyapunovExponents";
      break;

      //never get here
    default:
      ret = "Error:  Value not handled";
    }

  return ret;
}

//static
std::vector<CObjectLists::ListType>
CSensProblem::getPossibleVariables(CSensProblem::SubTaskType type)
{
  std::vector<CObjectLists::ListType> list;

  // the 'unset' type, abusing CObjectLists::ALL_METABS
  list.push_back((CObjectLists::ListType) 0);

  // Add new variables here, to applicable SubTaskType case.
  // Don't forget to provide for a string value in
  //   getVariableName()
  switch (type)
    {
    case (unset):
          case (SteadyState):
            case (TimeSeries):
              case (LyapunovExp):
                  // all available target functions
                  list.push_back(CObjectLists::NON_CONST_METAB_CONCENTRATIONS);
      list.push_back(CObjectLists::GLOBAL_PARAMETERS);
    }

  return list;
}

//static
std::string
CSensProblem::getVariableGroupName(CObjectLists::ListType objtype)
{
  std::string ret;

  switch (objtype)
    {
    case ((CObjectLists::ListType) 0):
            ret = "Not Set";
      break;

    case (CObjectLists::NON_CONST_METAB_CONCENTRATIONS):
            ret = "Global Parameters";
      break;

    case (CObjectLists::GLOBAL_PARAMETERS):
            ret = "Metabolite Concentrations";
      break;

    default:
      ret = "Error:  Value not handled";
    }

  return ret;
}

void CSensProblem::initDebugProblem()
{
  CSensItem item;

  item.setSingleObjectCN(this->getCN());
  addVariables(item);

  item.setListType(CObjectLists::NON_CONST_METABS);
  addVariables(item);
}
<|endoftext|>


<commit_before>//===- DCE.cpp - Code to perform dead code elimination --------------------===//
//
// This file implements dead code elimination and basic block merging.
//
// Specifically, this:
//   * removes definitions with no uses (including unused constants)
//   * removes basic blocks with no predecessors
//   * merges a basic block into its predecessor if there is only one and the
//     predecessor only has one successor.
//   * Eliminates PHI nodes for basic blocks with a single predecessor
//   * Eliminates a basic block that only contains an unconditional branch
//
// TODO: This should REALLY be recursive instead of iterative.  Right now, we
// scan linearly through values, removing unused ones as we go.  The problem is
// that this may cause other earlier values to become unused.  To make sure that
// we get them all, we iterate until things stop changing.  Instead, when
// removing a value, recheck all of its operands to see if they are now unused.
// Piece of cake, and more efficient as well.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/Method.h"
#include "llvm/BasicBlock.h"
#include "llvm/iTerminators.h"
#include "llvm/iOther.h"
#include "llvm/Opt/AllOpts.h"
#include "llvm/Assembly/Writer.h"

struct ConstPoolDCE {
  enum { EndOffs = 0 };
  static bool isDCEable(const Value *) { return true; }
};

struct BasicBlockDCE {
  enum { EndOffs = 1 };
  static bool isDCEable(const Instruction *I) {
    return !I->hasSideEffects();
  }
};

template<class ValueSubclass, class ItemParentType, class DCEController>
static bool RemoveUnusedDefs(ValueHolder<ValueSubclass, ItemParentType> &Vals,
			     DCEController DCEControl) {
  bool Changed = false;
  typedef ValueHolder<ValueSubclass, ItemParentType> Container;

  int Offset = DCEController::EndOffs;
  for (Container::iterator DI = Vals.begin(); DI != Vals.end()-Offset; ) {
    // Look for un"used" definitions...
    if ((*DI)->use_empty() && DCEController::isDCEable(*DI)) {
      // Bye bye
      //cerr << "Removing: " << *DI;
      delete Vals.remove(DI);
      Changed = true;
    } else {
      DI++;
    }
  }
  return Changed;
}

// RemoveSingularPHIs - This removes PHI nodes from basic blocks that have only
// a single predecessor.  This means that the PHI node must only have a single
// RHS value and can be eliminated.
//
// This routine is very simple because we know that PHI nodes must be the first
// things in a basic block, if they are present.
//
static bool RemoveSingularPHIs(BasicBlock *BB) {
  BasicBlock::pred_iterator PI(BB->pred_begin());
  if (PI == BB->pred_end() || ++PI != BB->pred_end())
    return false;   // More than one predecessor...

  Instruction *I = BB->getInstList().front();
  if (I->getInstType() != Instruction::PHINode) return false;  // No PHI nodes

  cerr << "Killing PHIs from " << BB;
  cerr << "Pred #0 = " << *BB->pred_begin();

  cerr << "Method == " << BB->getParent();

  do {
    PHINode *PN = (PHINode*)I;
    assert(PN->getOperand(1) == 0 && "PHI node should only have one value!");
    Value *V = PN->getOperand(0);

    PN->replaceAllUsesWith(V);      // Replace PHI node with its single value.
    delete BB->getInstList().remove(BB->getInstList().begin());

    I = BB->getInstList().front();
  } while (I->getInstType() == Instruction::PHINode);

  return true;  // Yes, we nuked at least one phi node
}

bool DoRemoveUnusedConstants(SymTabValue *S) {
  bool Changed = false;
  ConstantPool &CP = S->getConstantPool();
  for (ConstantPool::plane_iterator PI = CP.begin(); PI != CP.end(); ++PI)
    Changed |= RemoveUnusedDefs(**PI, ConstPoolDCE());
  return Changed;
}

static void ReplaceUsesWithConstant(Instruction *I) {
  // Get the method level constant pool
  ConstantPool &CP = I->getParent()->getParent()->getConstantPool();

  ConstPoolVal *CPV = 0;
  ConstantPool::PlaneType *P;
  if (!CP.getPlane(I->getType(), P)) {  // Does plane exist?
    // Yes, is it empty?
    if (!P->empty()) CPV = P->front();
  }

  if (CPV == 0) { // We don't have an existing constant to reuse.  Just add one.
    CPV = ConstPoolVal::getNullConstant(I->getType());  // Create a new constant

    // Add the new value to the constant pool...
    CP.insert(CPV);
  }

  // Make all users of this instruction reference the constant instead
  I->replaceAllUsesWith(CPV);
}

// RemovePredecessorFromBlock - This function is called when we are about
// to remove a predecessor from a basic block.  This function takes care of
// removing the predecessor from the PHI nodes in BB so that after the pred
// is removed, the number of PHI slots per bb is equal to the number of
// predecessors.
//
static void RemovePredecessorFromBlock(BasicBlock *BB, BasicBlock *Pred) {
  BasicBlock::pred_iterator PI(BB->pred_begin()), EI(BB->pred_end());
  unsigned pred_idx = 0, max_idx;

  cerr << "RPFB: " << Pred << "From Block: " << BB;

  // Find out what index the predecessor is...
  for (; *PI != BB; ++PI, ++pred_idx) {
    assert(PI != EI && "Pred is not a predecessor of BB!");
  }

  // Loop over the rest of the predecssors until we run out, or until we find
  // out that there are more than 2 predecessors.
  for (max_idx = pred_idx; PI != EI && max_idx < 2; ++PI, ++max_idx) /*empty*/;

  // If there are exactly two predecessors, then we want to nuke the PHI nodes
  // altogether.
  bool NukePHIs = max_idx == 1;

  // Okay, now we know that we need to remove predecessor #pred_idx from all
  // PHI nodes.  Iterate over each PHI node fixing them up
  BasicBlock::InstListType::iterator II(BB->getInstList().begin());
  for (; (*II)->getInstType() == Instruction::PHINode; ++II) {
    PHINode *PN = (PHINode*)*II;
    PN->removeIncomingValue(pred_idx);

    if (NukePHIs) {  // Destroy the PHI altogether??
      assert(PN->getOperand(1) == 0 && "PHI node should only have one value!");
      Value *V = PN->getOperand(0);

      PN->replaceAllUsesWith(V);      // Replace PHI node with its single value.
      delete BB->getInstList().remove(II);
    }
  }
}

// PropogatePredecessors - This gets "Succ" ready to have the predecessors from
// "BB".  This is a little tricky because "Succ" has PHI nodes, which need to
// have extra slots added to them to hold the merge edges from BB's
// predecessors.
//
// Assumption: BB is the single predecessor of Succ.
//
static void PropogatePredecessorsForPHIs(BasicBlock *BB, BasicBlock *Succ) {
  assert(BB && Succ && *Succ->pred_begin() == BB && "BB is only pred of Succ" &&
	 ++Succ->pred_begin() == Succ->pred_end());

  // If there is more than one predecessor, and there are PHI nodes in
  // the successor, then we need to add incoming edges for the PHI nodes
  BasicBlock::pred_iterator PI(BB->pred_begin());
  for (; PI != BB->pred_end(); ++PI) {
    // TODO:
  }
}

static bool DoDCEPass(Method *M) {
  Method::BasicBlocksType &BBs = M->getBasicBlocks();
  Method::BasicBlocksType::iterator BBIt, BBEnd = BBs.end();
  if (BBs.begin() == BBEnd) return false;  // Nothing to do
  bool Changed = false;

  // Loop through now and remove instructions that have no uses...
  for (BBIt = BBs.begin(); BBIt != BBEnd; BBIt++) {
    Changed |= RemoveUnusedDefs((*BBIt)->getInstList(), BasicBlockDCE());
    Changed |= RemoveSingularPHIs(*BBIt);
  }

  // Loop over all of the basic blocks (except the first one) and remove them
  // if they are unneeded...
  //
  for (BBIt = BBs.begin(), ++BBIt; BBIt != BBs.end(); ++BBIt) {
    BasicBlock *BB = *BBIt;
    assert(BB->getTerminator() && "Degenerate basic block encountered!");

#if 0
    // Remove basic blocks that have no predecessors... which are unreachable.
    if (BB->pred_begin() == BB->pred_end() &&
	!BB->hasConstantPoolReferences() && 0) {
      cerr << "Removing BB: \n" << BB;

      // Loop through all of our successors and make sure they know that one
      // of their predecessors is going away.
      for (BasicBlock::succ_iterator SI = BB->succ_begin(), EI = BB->succ_end();
	   SI != EI; ++SI)
	RemovePredecessorFromBlock(*SI, BB);

      while (!BB->getInstList().empty()) {
	Instruction *I = BB->getInstList().front();
	// If this instruction is used, replace uses with an arbitrary
	// constant value.  Because control flow can't get here, we don't care
	// what we replace the value with.
	if (!I->use_empty()) ReplaceUsesWithConstant(I);

	// Remove the instruction from the basic block
	delete BB->getInstList().remove(BB->getInstList().begin());
      }
      delete BBs.remove(BBIt);
      --BBIt;  // remove puts use on the next block, we want the previous one
      Changed = true;
      continue;
    }

    // Check to see if this block has no instructions and only a single
    // successor.  If so, replace block references with successor.
    BasicBlock::succ_iterator SI(BB->succ_begin());
    if (SI != BB->succ_end() && ++SI == BB->succ_end()) {  // One succ?
      Instruction *I = BB->getInstList().front();
      if (I->isTerminator()) {   // Terminator is the only instruction!

	if (Succ->getInstList().front()->getInstType() == Instruction::PHINode){
	  // Add entries to the PHI nodes so that the PHI nodes have the right
	  // number of entries...
	  PropogatePredecessorsForPHIs(BB, Succ);
	}

	BasicBlock *Succ = *BB->succ_begin(); // There is exactly one successor
	BB->replaceAllUsesWith(Succ);
	cerr << "Killing Trivial BB: \n" << BB;

	BB = BBs.remove(BBIt);
	--BBIt; // remove puts use on the next block, we want the previous one

	if (BB->hasName() && !Succ->hasName())  // Transfer name if we can
	  Succ->setName(BB->getName());
	delete BB;                              // Delete basic block

	cerr << "Method after removal: \n" << M;
	Changed = true;
	continue;
      }
    }
#endif

    // Merge basic blocks into their predecessor if there is only one pred,
    // and if there is only one successor of the predecessor.
    BasicBlock::pred_iterator PI(BB->pred_begin());
    if (PI != BB->pred_end() && *PI != BB &&    // Not empty?  Not same BB?
	++PI == BB->pred_end() && !BB->hasConstantPoolReferences()) {
      BasicBlock *Pred = *BB->pred_begin();
      TerminatorInst *Term = Pred->getTerminator();
      assert(Term != 0 && "malformed basic block without terminator!");

      // Does the predecessor block only have a single successor?
      BasicBlock::succ_iterator SI(Pred->succ_begin());
      if (++SI == Pred->succ_end()) {
	//cerr << "Merging: " << BB << "into: " << Pred;

	// Delete the unconditianal branch from the predecessor...
	BasicBlock::InstListType::iterator DI = Pred->getInstList().end();
	assert(Pred->getTerminator() &&
	       "Degenerate basic block encountered!");  // Empty bb???
	delete Pred->getInstList().remove(--DI);

	// Move all definitions in the succecessor to the predecessor...
	while (!BB->getInstList().empty()) {
	  DI = BB->getInstList().begin();
	  Instruction *Def = BB->getInstList().remove(DI); // Remove from front
	  Pred->getInstList().push_back(Def);              // Add to end...
	}

	// Remove basic block from the method... and advance iterator to the
	// next valid block...
	BB = BBs.remove(BBIt);
	--BBIt;  // remove puts us on the NEXT bb.  We want the prev BB
	Changed = true;

	// Inherit predecessors name if it exists...
	if (BB->hasName() && !Pred->hasName()) Pred->setName(BB->getName());

	// You ARE the weakest link... goodbye
	delete BB;
      }
    }
  }

  // Remove unused constants
  Changed |= DoRemoveUnusedConstants(M);
  return Changed;
}

// It is possible that we may require multiple passes over the code to fully
// eliminate dead code.  Iterate until we are done.
//
bool DoDeadCodeElimination(Method *M) {
  bool Changed = false;
  while (DoDCEPass(M)) Changed = true;
  return Changed;
}

bool DoDeadCodeElimination(Module *C) {
  bool Val = ApplyOptToAllMethods(C, DoDeadCodeElimination);
  while (DoRemoveUnusedConstants(C)) Val = true;
  return Val;
}
<commit_msg>Updated to work with new CFG.h file.<commit_after>//===- DCE.cpp - Code to perform dead code elimination --------------------===//
//
// This file implements dead code elimination and basic block merging.
//
// Specifically, this:
//   * removes definitions with no uses (including unused constants)
//   * removes basic blocks with no predecessors
//   * merges a basic block into its predecessor if there is only one and the
//     predecessor only has one successor.
//   * Eliminates PHI nodes for basic blocks with a single predecessor
//   * Eliminates a basic block that only contains an unconditional branch
//
// TODO: This should REALLY be recursive instead of iterative.  Right now, we
// scan linearly through values, removing unused ones as we go.  The problem is
// that this may cause other earlier values to become unused.  To make sure that
// we get them all, we iterate until things stop changing.  Instead, when
// removing a value, recheck all of its operands to see if they are now unused.
// Piece of cake, and more efficient as well.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/Method.h"
#include "llvm/BasicBlock.h"
#include "llvm/iTerminators.h"
#include "llvm/iOther.h"
#include "llvm/Opt/AllOpts.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/CFG.h"

struct ConstPoolDCE {
  enum { EndOffs = 0 };
  static bool isDCEable(const Value *) { return true; }
};

struct BasicBlockDCE {
  enum { EndOffs = 1 };
  static bool isDCEable(const Instruction *I) {
    return !I->hasSideEffects();
  }
};

template<class ValueSubclass, class ItemParentType, class DCEController>
static bool RemoveUnusedDefs(ValueHolder<ValueSubclass, ItemParentType> &Vals,
			     DCEController DCEControl) {
  bool Changed = false;
  typedef ValueHolder<ValueSubclass, ItemParentType> Container;

  int Offset = DCEController::EndOffs;
  for (Container::iterator DI = Vals.begin(); DI != Vals.end()-Offset; ) {
    // Look for un"used" definitions...
    if ((*DI)->use_empty() && DCEController::isDCEable(*DI)) {
      // Bye bye
      //cerr << "Removing: " << *DI;
      delete Vals.remove(DI);
      Changed = true;
    } else {
      DI++;
    }
  }
  return Changed;
}

// RemoveSingularPHIs - This removes PHI nodes from basic blocks that have only
// a single predecessor.  This means that the PHI node must only have a single
// RHS value and can be eliminated.
//
// This routine is very simple because we know that PHI nodes must be the first
// things in a basic block, if they are present.
//
static bool RemoveSingularPHIs(BasicBlock *BB) {
  pred_iterator PI(pred_begin(BB));
  if (PI == pred_end(BB) || ++PI != pred_end(BB))
    return false;   // More than one predecessor...

  Instruction *I = BB->getInstList().front();
  if (I->getInstType() != Instruction::PHINode) return false;  // No PHI nodes

  cerr << "Killing PHIs from " << BB;
  cerr << "Pred #0 = " << *pred_begin(BB);

  cerr << "Method == " << BB->getParent();

  do {
    PHINode *PN = (PHINode*)I;
    assert(PN->getOperand(1) == 0 && "PHI node should only have one value!");
    Value *V = PN->getOperand(0);

    PN->replaceAllUsesWith(V);      // Replace PHI node with its single value.
    delete BB->getInstList().remove(BB->getInstList().begin());

    I = BB->getInstList().front();
  } while (I->getInstType() == Instruction::PHINode);

  return true;  // Yes, we nuked at least one phi node
}

bool DoRemoveUnusedConstants(SymTabValue *S) {
  bool Changed = false;
  ConstantPool &CP = S->getConstantPool();
  for (ConstantPool::plane_iterator PI = CP.begin(); PI != CP.end(); ++PI)
    Changed |= RemoveUnusedDefs(**PI, ConstPoolDCE());
  return Changed;
}

static void ReplaceUsesWithConstant(Instruction *I) {
  // Get the method level constant pool
  ConstantPool &CP = I->getParent()->getParent()->getConstantPool();

  ConstPoolVal *CPV = 0;
  ConstantPool::PlaneType *P;
  if (!CP.getPlane(I->getType(), P)) {  // Does plane exist?
    // Yes, is it empty?
    if (!P->empty()) CPV = P->front();
  }

  if (CPV == 0) { // We don't have an existing constant to reuse.  Just add one.
    CPV = ConstPoolVal::getNullConstant(I->getType());  // Create a new constant

    // Add the new value to the constant pool...
    CP.insert(CPV);
  }

  // Make all users of this instruction reference the constant instead
  I->replaceAllUsesWith(CPV);
}

// RemovePredecessorFromBlock - This function is called when we are about
// to remove a predecessor from a basic block.  This function takes care of
// removing the predecessor from the PHI nodes in BB so that after the pred
// is removed, the number of PHI slots per bb is equal to the number of
// predecessors.
//
static void RemovePredecessorFromBlock(BasicBlock *BB, BasicBlock *Pred) {
  pred_iterator PI(pred_begin(BB)), EI(pred_end(BB));
  unsigned pred_idx = 0, max_idx;

  cerr << "RPFB: " << Pred << "From Block: " << BB;

  // Find out what index the predecessor is...
  for (; *PI != BB; ++PI, ++pred_idx) {
    assert(PI != EI && "Pred is not a predecessor of BB!");
  }

  // Loop over the rest of the predecssors until we run out, or until we find
  // out that there are more than 2 predecessors.
  for (max_idx = pred_idx; PI != EI && max_idx < 2; ++PI, ++max_idx) /*empty*/;

  // If there are exactly two predecessors, then we want to nuke the PHI nodes
  // altogether.
  bool NukePHIs = max_idx == 1;

  // Okay, now we know that we need to remove predecessor #pred_idx from all
  // PHI nodes.  Iterate over each PHI node fixing them up
  BasicBlock::InstListType::iterator II(BB->getInstList().begin());
  for (; (*II)->getInstType() == Instruction::PHINode; ++II) {
    PHINode *PN = (PHINode*)*II;
    PN->removeIncomingValue(pred_idx);

    if (NukePHIs) {  // Destroy the PHI altogether??
      assert(PN->getOperand(1) == 0 && "PHI node should only have one value!");
      Value *V = PN->getOperand(0);

      PN->replaceAllUsesWith(V);      // Replace PHI node with its single value.
      delete BB->getInstList().remove(II);
    }
  }
}

// PropogatePredecessors - This gets "Succ" ready to have the predecessors from
// "BB".  This is a little tricky because "Succ" has PHI nodes, which need to
// have extra slots added to them to hold the merge edges from BB's
// predecessors.
//
// Assumption: BB is the single predecessor of Succ.
//
static void PropogatePredecessorsForPHIs(BasicBlock *BB, BasicBlock *Succ) {
  assert(BB && Succ && *pred_begin(Succ) == BB && "BB is only pred of Succ" &&
	 ++pred_begin(Succ) == pred_end(Succ));

  // If there is more than one predecessor, and there are PHI nodes in
  // the successor, then we need to add incoming edges for the PHI nodes
  pred_iterator PI(pred_begin(BB));
  for (; PI != pred_end(BB); ++PI) {
    // TODO:
  }
}

static bool DoDCEPass(Method *M) {
  Method::BasicBlocksType &BBs = M->getBasicBlocks();
  Method::BasicBlocksType::iterator BBIt, BBEnd = BBs.end();
  if (BBs.begin() == BBEnd) return false;  // Nothing to do
  bool Changed = false;

  // Loop through now and remove instructions that have no uses...
  for (BBIt = BBs.begin(); BBIt != BBEnd; BBIt++) {
    Changed |= RemoveUnusedDefs((*BBIt)->getInstList(), BasicBlockDCE());
    Changed |= RemoveSingularPHIs(*BBIt);
  }

  // Loop over all of the basic blocks (except the first one) and remove them
  // if they are unneeded...
  //
  for (BBIt = BBs.begin(), ++BBIt; BBIt != BBs.end(); ++BBIt) {
    BasicBlock *BB = *BBIt;
    assert(BB->getTerminator() && "Degenerate basic block encountered!");

#if 0
    // Remove basic blocks that have no predecessors... which are unreachable.
    if (pred_begin(BB) == pred_end(BB) &&
	!BB->hasConstantPoolReferences() && 0) {
      cerr << "Removing BB: \n" << BB;

      // Loop through all of our successors and make sure they know that one
      // of their predecessors is going away.
      for (succ_iterator SI = succ_begin(BB), EI = succ_end(BB); SI != EI; ++SI)
	RemovePredecessorFromBlock(*SI, BB);

      while (!BB->getInstList().empty()) {
	Instruction *I = BB->getInstList().front();
	// If this instruction is used, replace uses with an arbitrary
	// constant value.  Because control flow can't get here, we don't care
	// what we replace the value with.
	if (!I->use_empty()) ReplaceUsesWithConstant(I);

	// Remove the instruction from the basic block
	delete BB->getInstList().remove(BB->getInstList().begin());
      }
      delete BBs.remove(BBIt);
      --BBIt;  // remove puts use on the next block, we want the previous one
      Changed = true;
      continue;
    }

    // Check to see if this block has no instructions and only a single
    // successor.  If so, replace block references with successor.
    succ_iterator SI(succ_begin(BB));
    if (SI != succ_end(BB) && ++SI == succ_end(BB)) {  // One succ?
      Instruction *I = BB->getInstList().front();
      if (I->isTerminator()) {   // Terminator is the only instruction!

	if (Succ->getInstList().front()->getInstType() == Instruction::PHINode){
	  // Add entries to the PHI nodes so that the PHI nodes have the right
	  // number of entries...
	  PropogatePredecessorsForPHIs(BB, Succ);
	}

	BasicBlock *Succ = *succ_begin(BB); // There is exactly one successor
	BB->replaceAllUsesWith(Succ);
	cerr << "Killing Trivial BB: \n" << BB;

	BB = BBs.remove(BBIt);
	--BBIt; // remove puts use on the next block, we want the previous one

	if (BB->hasName() && !Succ->hasName())  // Transfer name if we can
	  Succ->setName(BB->getName());
	delete BB;                              // Delete basic block

	cerr << "Method after removal: \n" << M;
	Changed = true;
	continue;
      }
    }
#endif

    // Merge basic blocks into their predecessor if there is only one pred,
    // and if there is only one successor of the predecessor.
    pred_iterator PI(pred_begin(BB));
    if (PI != pred_end(BB) && *PI != BB &&    // Not empty?  Not same BB?
	++PI == pred_end(BB) && !BB->hasConstantPoolReferences()) {
      BasicBlock *Pred = *pred_begin(BB);
      TerminatorInst *Term = Pred->getTerminator();
      assert(Term != 0 && "malformed basic block without terminator!");

      // Does the predecessor block only have a single successor?
      succ_iterator SI(succ_begin(Pred));
      if (++SI == succ_end(Pred)) {
	//cerr << "Merging: " << BB << "into: " << Pred;

	// Delete the unconditianal branch from the predecessor...
	BasicBlock::InstListType::iterator DI = Pred->getInstList().end();
	assert(Pred->getTerminator() &&
	       "Degenerate basic block encountered!");  // Empty bb???
	delete Pred->getInstList().remove(--DI);

	// Move all definitions in the succecessor to the predecessor...
	while (!BB->getInstList().empty()) {
	  DI = BB->getInstList().begin();
	  Instruction *Def = BB->getInstList().remove(DI); // Remove from front
	  Pred->getInstList().push_back(Def);              // Add to end...
	}

	// Remove basic block from the method... and advance iterator to the
	// next valid block...
	BB = BBs.remove(BBIt);
	--BBIt;  // remove puts us on the NEXT bb.  We want the prev BB
	Changed = true;

	// Inherit predecessors name if it exists...
	if (BB->hasName() && !Pred->hasName()) Pred->setName(BB->getName());

	// You ARE the weakest link... goodbye
	delete BB;
      }
    }
  }

  // Remove unused constants
  Changed |= DoRemoveUnusedConstants(M);
  return Changed;
}

// It is possible that we may require multiple passes over the code to fully
// eliminate dead code.  Iterate until we are done.
//
bool DoDeadCodeElimination(Method *M) {
  bool Changed = false;
  while (DoDCEPass(M)) Changed = true;
  return Changed;
}

bool DoDeadCodeElimination(Module *C) {
  bool Val = ApplyOptToAllMethods(C, DoDeadCodeElimination);
  while (DoRemoveUnusedConstants(C)) Val = true;
  return Val;
}
<|endoftext|>