<commit_before>/***************************************************************************
    copyright            : (C) 2004 by Allan Sandfeld Jensen
    email                : kde@carewolf.com
 ***************************************************************************/

/***************************************************************************
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License version   *
 *   2.1 as published by the Free Software Foundation.                     *
 *                                                                         *
 *   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                                                       *
 *                                                                         *
 *   Alternatively, this file is available under the Mozilla Public        *
 *   License Version 1.1.  You may obtain a copy of the License at         *
 *   http://www.mozilla.org/MPL/                                           *
 ***************************************************************************/

#if defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5130)
// Sun Studio finds multiple specializations of Map because
// it considers specializations with and without class types
// to be different; this define forces Map to use only the
// specialization with the class keyword.
#define WANT_CLASS_INSTANTIATION_OF_MAP (1)
#endif

#include <tfile.h>
#include <tstring.h>
#include <tmap.h>
#include <tpropertymap.h>
#include <tdebug.h>
#include <tutils.h>

#include "apetag.h"
#include "apefooter.h"
#include "apeitem.h"

using namespace TagLib;
using namespace APE;

namespace
{
  const unsigned int MinKeyLength = 2;
  const unsigned int MaxKeyLength = 255;

  bool isKeyValid(const ByteVector &key)
  {
    const char *invalidKeys[] = { "ID3", "TAG", "OGGS", "MP+", 0 };

    // only allow printable ASCII including space (32..126)

    for(ByteVector::ConstIterator it = key.begin(); it != key.end(); ++it) {
      const int c = static_cast<unsigned char>(*it);
      if(c < 32 || c > 126)
        return false;
    }

    const String upperKey = String(key).upper();
    for(size_t i = 0; invalidKeys[i] != 0; ++i) {
      if(upperKey == invalidKeys[i])
        return false;
    }

    return true;
  }
}  // namespace

class APE::Tag::TagPrivate
{
public:
  TagPrivate() :
    file(0),
    footerLocation(0) {}

  File *file;
  long footerLocation;

  Footer footer;
  ItemListMap itemListMap;
};

////////////////////////////////////////////////////////////////////////////////
// public methods
////////////////////////////////////////////////////////////////////////////////

APE::Tag::Tag() :
  d(new TagPrivate())
{
}

APE::Tag::Tag(TagLib::File *file, long footerLocation) :
  d(new TagPrivate())
{
  d->file = file;
  d->footerLocation = footerLocation;

  read();
}

APE::Tag::~Tag()
{
  delete d;
}

ByteVector APE::Tag::fileIdentifier()
{
  return ByteVector::fromCString("APETAGEX");
}

String APE::Tag::title() const
{
  if(d->itemListMap["TITLE"].isEmpty())
    return String();
  return d->itemListMap["TITLE"].values().toString();
}

String APE::Tag::artist() const
{
  if(d->itemListMap["ARTIST"].isEmpty())
    return String();
  return d->itemListMap["ARTIST"].values().toString();
}

String APE::Tag::album() const
{
  if(d->itemListMap["ALBUM"].isEmpty())
    return String();
  return d->itemListMap["ALBUM"].values().toString();
}

String APE::Tag::comment() const
{
  if(d->itemListMap["COMMENT"].isEmpty())
    return String();
  return d->itemListMap["COMMENT"].values().toString();
}

String APE::Tag::genre() const
{
  if(d->itemListMap["GENRE"].isEmpty())
    return String();
  return d->itemListMap["GENRE"].values().toString();
}

unsigned int APE::Tag::year() const
{
  if(d->itemListMap["YEAR"].isEmpty())
    return 0;
  return d->itemListMap["YEAR"].toString().toInt();
}

unsigned int APE::Tag::track() const
{
  if(d->itemListMap["TRACK"].isEmpty())
    return 0;
  return d->itemListMap["TRACK"].toString().toInt();
}

void APE::Tag::setTitle(const String &s)
{
  addValue("TITLE", s, true);
}

void APE::Tag::setArtist(const String &s)
{
  addValue("ARTIST", s, true);
}

void APE::Tag::setAlbum(const String &s)
{
  addValue("ALBUM", s, true);
}

void APE::Tag::setComment(const String &s)
{
  addValue("COMMENT", s, true);
}

void APE::Tag::setGenre(const String &s)
{
  addValue("GENRE", s, true);
}

void APE::Tag::setYear(unsigned int i)
{
  if(i == 0)
    removeItem("YEAR");
  else
    addValue("YEAR", String::number(i), true);
}

void APE::Tag::setTrack(unsigned int i)
{
  if(i == 0)
    removeItem("TRACK");
  else
    addValue("TRACK", String::number(i), true);
}

namespace
{
  // conversions of tag keys between what we use in PropertyMap and what's usual
  // for APE tags
  //                usual,         APE
  const std::pair<const char *, const char *> keyConversions[] = {
    std::make_pair("TRACKNUMBER", "TRACK"),
    std::make_pair("DATE",        "YEAR"),
    std::make_pair("ALBUMARTIST", "ALBUM ARTIST"),
    std::make_pair("DISCNUMBER",  "DISC"),
    std::make_pair("REMIXER",     "MIXARTIST"),
    std::make_pair("RELEASESTATUS", "MUSICBRAINZ_ALBUMSTATUS"),
    std::make_pair("RELEASETYPE", "MUSICBRAINZ_ALBUMTYPE"),
  };
  const size_t keyConversionsSize = sizeof(keyConversions) / sizeof(keyConversions[0]);
}  // namespace

PropertyMap APE::Tag::properties() const
{
  PropertyMap properties;
  ItemListMap::ConstIterator it = itemListMap().begin();
  for(; it != itemListMap().end(); ++it) {
    String tagName = it->first.upper();
    // if the item is Binary or Locator, or if the key is an invalid string,
    // add to unsupportedData
    if(it->second.type() != Item::Text || tagName.isEmpty()) {
      properties.unsupportedData().append(it->first);
    }
    else {
      // Some tags need to be handled specially
      for(size_t i = 0; i < keyConversionsSize; ++i) {
        if(tagName == keyConversions[i].second)
          tagName = keyConversions[i].first;
      }
      properties[tagName].append(it->second.toStringList());
    }
  }
  return properties;
}

void APE::Tag::removeUnsupportedProperties(const StringList &properties)
{
  StringList::ConstIterator it = properties.begin();
  for(; it != properties.end(); ++it)
    removeItem(*it);
}

PropertyMap APE::Tag::setProperties(const PropertyMap &origProps)
{
  PropertyMap properties(origProps); // make a local copy that can be modified

  // see comment in properties()
  for(size_t i = 0; i < keyConversionsSize; ++i)
    if(properties.contains(keyConversions[i].first)) {
      properties.insert(keyConversions[i].second, properties[keyConversions[i].first]);
      properties.erase(keyConversions[i].first);
    }

  // first check if tags need to be removed completely
  StringList toRemove;
  ItemListMap::ConstIterator remIt = itemListMap().begin();
  for(; remIt != itemListMap().end(); ++remIt) {
    String key = remIt->first.upper();
    // only remove if a) key is valid, b) type is text, c) key not contained in new properties
    if(!key.isEmpty() && remIt->second.type() == APE::Item::Text && !properties.contains(key))
      toRemove.append(remIt->first);
  }

  for(StringList::ConstIterator removeIt = toRemove.begin(); removeIt != toRemove.end(); removeIt++)
    removeItem(*removeIt);

  // now sync in the "forward direction"
  PropertyMap::ConstIterator it = properties.begin();
  PropertyMap invalid;
  for(; it != properties.end(); ++it) {
    const String &tagName = it->first;
    if(!checkKey(tagName))
      invalid.insert(it->first, it->second);
    else if(!(itemListMap().contains(tagName)) || !(itemListMap()[tagName].values() == it->second)) {
      if(it->second.isEmpty())
        removeItem(tagName);
      else {
        StringList::ConstIterator valueIt = it->second.begin();
        addValue(tagName, *valueIt, true);
        ++valueIt;
        for(; valueIt != it->second.end(); ++valueIt)
          addValue(tagName, *valueIt, false);
      }
    }
  }
  return invalid;
}

bool APE::Tag::checkKey(const String &key)
{
  if(key.size() < MinKeyLength || key.size() > MaxKeyLength)
    return false;

  return isKeyValid(key.data(String::UTF8));
}

APE::Footer *APE::Tag::footer() const
{
  return &d->footer;
}

const APE::ItemListMap& APE::Tag::itemListMap() const
{
  return d->itemListMap;
}

void APE::Tag::removeItem(const String &key)
{
  d->itemListMap.erase(key.upper());
}

void APE::Tag::addValue(const String &key, const String &value, bool replace)
{
  if(replace)
    removeItem(key);

  if(value.isEmpty())
    return;

  // Text items may contain more than one value.
  // Binary or locator items may have only one value, hence always replaced.

  ItemListMap::Iterator it = d->itemListMap.find(key.upper());

  if(it != d->itemListMap.end() && it->second.type() == Item::Text)
    it->second.appendValue(value);
  else
    setItem(key, Item(key, value));
}

void APE::Tag::setData(const String &key, const ByteVector &value)
{
  removeItem(key);

  if(value.isEmpty())
    return;

  setItem(key, Item(key, value, true));
}

void APE::Tag::setItem(const String &key, const Item &item)
{
  if(!checkKey(key)) {
    debug("APE::Tag::setItem() - Couldn't set an item due to an invalid key.");
    return;
  }

  d->itemListMap[key.upper()] = item;
}

bool APE::Tag::isEmpty() const
{
  return d->itemListMap.isEmpty();
}

////////////////////////////////////////////////////////////////////////////////
// protected methods
////////////////////////////////////////////////////////////////////////////////

void APE::Tag::read()
{
  if(d->file && d->file->isValid()) {

    d->file->seek(d->footerLocation);
    d->footer.setData(d->file->readBlock(Footer::size()));

    if(d->footer.tagSize() <= Footer::size() ||
       d->footer.tagSize() > static_cast<unsigned long>(d->file->length()))
      return;

    d->file->seek(d->footerLocation + Footer::size() - d->footer.tagSize());
    parse(d->file->readBlock(d->footer.tagSize() - Footer::size()));
  }
}

ByteVector APE::Tag::render() const
{
  ByteVector data;
  unsigned int itemCount = 0;

  for(ItemListMap::ConstIterator it = d->itemListMap.begin(); it != d->itemListMap.end(); ++it) {
    data.append(it->second.render());
    itemCount++;
  }

  d->footer.setItemCount(itemCount);
  d->footer.setTagSize(data.size() + Footer::size());
  d->footer.setHeaderPresent(true);

  return d->footer.renderHeader() + data + d->footer.renderFooter();
}

void APE::Tag::parse(const ByteVector &data)
{
  // 11 bytes is the minimum size for an APE item

  if(data.size() < 11)
    return;

  unsigned int pos = 0;

  for(unsigned int i = 0; i < d->footer.itemCount() && pos <= data.size() - 11; i++) {

    const int nullPos = data.find('\0', pos + 8);
    if(nullPos < 0) {
      debug("APE::Tag::parse() - Couldn't find a key/value separator. Stopped parsing.");
      return;
    }

    const unsigned int keyLength = nullPos - pos - 8;
    const unsigned int valLength = data.toUInt(pos, false);

    if(valLength >= data.size() || pos > data.size() - valLength) {
      debug("APE::Tag::parse() - Invalid val length. Stopped parsing.");
      return;
    }

    if(keyLength >= MinKeyLength
      && keyLength <= MaxKeyLength
      && isKeyValid(data.mid(pos + 8, keyLength)))
    {
      APE::Item item;
      item.parse(data.mid(pos));

      d->itemListMap.insert(item.key().upper(), item);
    }
    else {
      debug("APE::Tag::parse() - Skipped an item due to an invalid key.");
    }

    pos += keyLength + valLength + 9;
  }
}
<commit_msg>APE: Do not create map entry if looked up tag does not exist (#931)<commit_after>/***************************************************************************
    copyright            : (C) 2004 by Allan Sandfeld Jensen
    email                : kde@carewolf.com
 ***************************************************************************/

/***************************************************************************
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License version   *
 *   2.1 as published by the Free Software Foundation.                     *
 *                                                                         *
 *   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                                                       *
 *                                                                         *
 *   Alternatively, this file is available under the Mozilla Public        *
 *   License Version 1.1.  You may obtain a copy of the License at         *
 *   http://www.mozilla.org/MPL/                                           *
 ***************************************************************************/

#if defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5130)
// Sun Studio finds multiple specializations of Map because
// it considers specializations with and without class types
// to be different; this define forces Map to use only the
// specialization with the class keyword.
#define WANT_CLASS_INSTANTIATION_OF_MAP (1)
#endif

#include <tfile.h>
#include <tstring.h>
#include <tmap.h>
#include <tpropertymap.h>
#include <tdebug.h>
#include <tutils.h>

#include "apetag.h"
#include "apefooter.h"
#include "apeitem.h"

using namespace TagLib;
using namespace APE;

namespace
{
  const unsigned int MinKeyLength = 2;
  const unsigned int MaxKeyLength = 255;

  bool isKeyValid(const ByteVector &key)
  {
    const char *invalidKeys[] = { "ID3", "TAG", "OGGS", "MP+", 0 };

    // only allow printable ASCII including space (32..126)

    for(ByteVector::ConstIterator it = key.begin(); it != key.end(); ++it) {
      const int c = static_cast<unsigned char>(*it);
      if(c < 32 || c > 126)
        return false;
    }

    const String upperKey = String(key).upper();
    for(size_t i = 0; invalidKeys[i] != 0; ++i) {
      if(upperKey == invalidKeys[i])
        return false;
    }

    return true;
  }
}  // namespace

class APE::Tag::TagPrivate
{
public:
  TagPrivate() :
    file(0),
    footerLocation(0) {}

  File *file;
  long footerLocation;

  Footer footer;
  ItemListMap itemListMap;
};

////////////////////////////////////////////////////////////////////////////////
// public methods
////////////////////////////////////////////////////////////////////////////////

APE::Tag::Tag() :
  d(new TagPrivate())
{
}

APE::Tag::Tag(TagLib::File *file, long footerLocation) :
  d(new TagPrivate())
{
  d->file = file;
  d->footerLocation = footerLocation;

  read();
}

APE::Tag::~Tag()
{
  delete d;
}

ByteVector APE::Tag::fileIdentifier()
{
  return ByteVector::fromCString("APETAGEX");
}

String APE::Tag::title() const
{
  Item value = d->itemListMap.value("TITLE");
  return value.isEmpty() ? String() : value.values().toString();
}

String APE::Tag::artist() const
{
  Item value = d->itemListMap.value("ARTIST");
  return value.isEmpty() ? String() : value.values().toString();
}

String APE::Tag::album() const
{
  Item value = d->itemListMap.value("ALBUM");
  return value.isEmpty() ? String() : value.values().toString();
}

String APE::Tag::comment() const
{
  Item value = d->itemListMap.value("COMMENT");
  return value.isEmpty() ? String() : value.values().toString();
}

String APE::Tag::genre() const
{
  Item value = d->itemListMap.value("GENRE");
  return value.isEmpty() ? String() : value.values().toString();
}

unsigned int APE::Tag::year() const
{
  Item value = d->itemListMap.value("YEAR");
  return value.isEmpty() ? 0 : value.toString().toInt();
}

unsigned int APE::Tag::track() const
{
  Item value = d->itemListMap.value("TRACK");
  return value.isEmpty() ? 0 : value.toString().toInt();
}

void APE::Tag::setTitle(const String &s)
{
  addValue("TITLE", s, true);
}

void APE::Tag::setArtist(const String &s)
{
  addValue("ARTIST", s, true);
}

void APE::Tag::setAlbum(const String &s)
{
  addValue("ALBUM", s, true);
}

void APE::Tag::setComment(const String &s)
{
  addValue("COMMENT", s, true);
}

void APE::Tag::setGenre(const String &s)
{
  addValue("GENRE", s, true);
}

void APE::Tag::setYear(unsigned int i)
{
  if(i == 0)
    removeItem("YEAR");
  else
    addValue("YEAR", String::number(i), true);
}

void APE::Tag::setTrack(unsigned int i)
{
  if(i == 0)
    removeItem("TRACK");
  else
    addValue("TRACK", String::number(i), true);
}

namespace
{
  // conversions of tag keys between what we use in PropertyMap and what's usual
  // for APE tags
  //                usual,         APE
  const std::pair<const char *, const char *> keyConversions[] = {
    std::make_pair("TRACKNUMBER", "TRACK"),
    std::make_pair("DATE",        "YEAR"),
    std::make_pair("ALBUMARTIST", "ALBUM ARTIST"),
    std::make_pair("DISCNUMBER",  "DISC"),
    std::make_pair("REMIXER",     "MIXARTIST"),
    std::make_pair("RELEASESTATUS", "MUSICBRAINZ_ALBUMSTATUS"),
    std::make_pair("RELEASETYPE", "MUSICBRAINZ_ALBUMTYPE"),
  };
  const size_t keyConversionsSize = sizeof(keyConversions) / sizeof(keyConversions[0]);
}  // namespace

PropertyMap APE::Tag::properties() const
{
  PropertyMap properties;
  ItemListMap::ConstIterator it = itemListMap().begin();
  for(; it != itemListMap().end(); ++it) {
    String tagName = it->first.upper();
    // if the item is Binary or Locator, or if the key is an invalid string,
    // add to unsupportedData
    if(it->second.type() != Item::Text || tagName.isEmpty()) {
      properties.unsupportedData().append(it->first);
    }
    else {
      // Some tags need to be handled specially
      for(size_t i = 0; i < keyConversionsSize; ++i) {
        if(tagName == keyConversions[i].second)
          tagName = keyConversions[i].first;
      }
      properties[tagName].append(it->second.toStringList());
    }
  }
  return properties;
}

void APE::Tag::removeUnsupportedProperties(const StringList &properties)
{
  StringList::ConstIterator it = properties.begin();
  for(; it != properties.end(); ++it)
    removeItem(*it);
}

PropertyMap APE::Tag::setProperties(const PropertyMap &origProps)
{
  PropertyMap properties(origProps); // make a local copy that can be modified

  // see comment in properties()
  for(size_t i = 0; i < keyConversionsSize; ++i)
    if(properties.contains(keyConversions[i].first)) {
      properties.insert(keyConversions[i].second, properties[keyConversions[i].first]);
      properties.erase(keyConversions[i].first);
    }

  // first check if tags need to be removed completely
  StringList toRemove;
  ItemListMap::ConstIterator remIt = itemListMap().begin();
  for(; remIt != itemListMap().end(); ++remIt) {
    String key = remIt->first.upper();
    // only remove if a) key is valid, b) type is text, c) key not contained in new properties
    if(!key.isEmpty() && remIt->second.type() == APE::Item::Text && !properties.contains(key))
      toRemove.append(remIt->first);
  }

  for(StringList::ConstIterator removeIt = toRemove.begin(); removeIt != toRemove.end(); removeIt++)
    removeItem(*removeIt);

  // now sync in the "forward direction"
  PropertyMap::ConstIterator it = properties.begin();
  PropertyMap invalid;
  for(; it != properties.end(); ++it) {
    const String &tagName = it->first;
    if(!checkKey(tagName))
      invalid.insert(it->first, it->second);
    else if(!(itemListMap().contains(tagName)) || !(itemListMap()[tagName].values() == it->second)) {
      if(it->second.isEmpty())
        removeItem(tagName);
      else {
        StringList::ConstIterator valueIt = it->second.begin();
        addValue(tagName, *valueIt, true);
        ++valueIt;
        for(; valueIt != it->second.end(); ++valueIt)
          addValue(tagName, *valueIt, false);
      }
    }
  }
  return invalid;
}

bool APE::Tag::checkKey(const String &key)
{
  if(key.size() < MinKeyLength || key.size() > MaxKeyLength)
    return false;

  return isKeyValid(key.data(String::UTF8));
}

APE::Footer *APE::Tag::footer() const
{
  return &d->footer;
}

const APE::ItemListMap& APE::Tag::itemListMap() const
{
  return d->itemListMap;
}

void APE::Tag::removeItem(const String &key)
{
  d->itemListMap.erase(key.upper());
}

void APE::Tag::addValue(const String &key, const String &value, bool replace)
{
  if(replace)
    removeItem(key);

  if(value.isEmpty())
    return;

  // Text items may contain more than one value.
  // Binary or locator items may have only one value, hence always replaced.

  ItemListMap::Iterator it = d->itemListMap.find(key.upper());

  if(it != d->itemListMap.end() && it->second.type() == Item::Text)
    it->second.appendValue(value);
  else
    setItem(key, Item(key, value));
}

void APE::Tag::setData(const String &key, const ByteVector &value)
{
  removeItem(key);

  if(value.isEmpty())
    return;

  setItem(key, Item(key, value, true));
}

void APE::Tag::setItem(const String &key, const Item &item)
{
  if(!checkKey(key)) {
    debug("APE::Tag::setItem() - Couldn't set an item due to an invalid key.");
    return;
  }

  d->itemListMap[key.upper()] = item;
}

bool APE::Tag::isEmpty() const
{
  return d->itemListMap.isEmpty();
}

////////////////////////////////////////////////////////////////////////////////
// protected methods
////////////////////////////////////////////////////////////////////////////////

void APE::Tag::read()
{
  if(d->file && d->file->isValid()) {

    d->file->seek(d->footerLocation);
    d->footer.setData(d->file->readBlock(Footer::size()));

    if(d->footer.tagSize() <= Footer::size() ||
       d->footer.tagSize() > static_cast<unsigned long>(d->file->length()))
      return;

    d->file->seek(d->footerLocation + Footer::size() - d->footer.tagSize());
    parse(d->file->readBlock(d->footer.tagSize() - Footer::size()));
  }
}

ByteVector APE::Tag::render() const
{
  ByteVector data;
  unsigned int itemCount = 0;

  for(ItemListMap::ConstIterator it = d->itemListMap.begin(); it != d->itemListMap.end(); ++it) {
    data.append(it->second.render());
    itemCount++;
  }

  d->footer.setItemCount(itemCount);
  d->footer.setTagSize(data.size() + Footer::size());
  d->footer.setHeaderPresent(true);

  return d->footer.renderHeader() + data + d->footer.renderFooter();
}

void APE::Tag::parse(const ByteVector &data)
{
  // 11 bytes is the minimum size for an APE item

  if(data.size() < 11)
    return;

  unsigned int pos = 0;

  for(unsigned int i = 0; i < d->footer.itemCount() && pos <= data.size() - 11; i++) {

    const int nullPos = data.find('\0', pos + 8);
    if(nullPos < 0) {
      debug("APE::Tag::parse() - Couldn't find a key/value separator. Stopped parsing.");
      return;
    }

    const unsigned int keyLength = nullPos - pos - 8;
    const unsigned int valLength = data.toUInt(pos, false);

    if(valLength >= data.size() || pos > data.size() - valLength) {
      debug("APE::Tag::parse() - Invalid val length. Stopped parsing.");
      return;
    }

    if(keyLength >= MinKeyLength
      && keyLength <= MaxKeyLength
      && isKeyValid(data.mid(pos + 8, keyLength)))
    {
      APE::Item item;
      item.parse(data.mid(pos));

      d->itemListMap.insert(item.key().upper(), item);
    }
    else {
      debug("APE::Tag::parse() - Skipped an item due to an invalid key.");
    }

    pos += keyLength + valLength + 9;
  }
}
<|endoftext|>


<commit_before>// Copyright 2018 Global Phasing Ltd.
//
// File-related utilities.

#ifndef GEMMI_FILEUTIL_HPP_
#define GEMMI_FILEUTIL_HPP_

#include <cctype>    // for isdigit, isalnum
#include <cstdio>    // for FILE, fopen, fclose
#include <cstdlib>   // getenv
#include <cstring>   // strlen
#include <initializer_list>
#include <memory>    // for unique_ptr
#include <string>
#include "fail.hpp"  // for fail, sys_fail
#include "util.hpp"  // for to_lower

#if defined(_WIN32) && !defined(GEMMI_USE_FOPEN)
#include "utf.hpp"
#endif

namespace gemmi {

// strip directory and suffixes from filename
inline std::string path_basename(const std::string& path,
                                 std::initializer_list<const char*> exts) {
  size_t pos = path.find_last_of("\\/");
  std::string basename = pos == std::string::npos ? path : path.substr(pos + 1);
  for (const char* ext : exts) {
    size_t len = std::strlen(ext);
    if (basename.size() > len &&
        basename.compare(basename.length() - len, len, ext, len) == 0)
      basename.resize(basename.length() - len);
  }
  return basename;
}

// file operations
typedef std::unique_ptr<std::FILE, decltype(&std::fclose)> fileptr_t;

inline fileptr_t file_open(const char* path, const char* mode) {
  std::FILE* file;
#if defined(_WIN32) && !defined(GEMMI_USE_FOPEN)
  std::wstring wpath = UTF8_to_wchar(path);
  std::wstring wmode = UTF8_to_wchar(mode);
  if ((file = ::_wfopen(wpath.c_str(), wmode.c_str())) == nullptr)
#else
  if ((file = std::fopen(path, mode)) == nullptr)
#endif
    sys_fail(std::string("Failed to open ") + path +
             (*mode == 'w' ? " for writing" : ""));
  return fileptr_t(file, &std::fclose);
}

// helper function for treating "-" as stdin or stdout
inline fileptr_t file_open_or(const char* path, const char* mode,
                              std::FILE* dash_stream) {
  if (path[0] == '-' && path[1] == '\0')
    return fileptr_t(dash_stream, [](std::FILE*) { return 0; });
  return file_open(path, mode);
}

inline std::size_t file_size(std::FILE* f, const std::string& path) {
  if (std::fseek(f, 0, SEEK_END) != 0)
    sys_fail(path + ": fseek failed");
  long length = std::ftell(f);
  if (length < 0)
    sys_fail(path + ": ftell failed");
  if (std::fseek(f, 0, SEEK_SET) != 0)
    sys_fail(path + ": fseek failed");
  return length;
}

inline bool is_pdb_code(const std::string& str) {
  return str.length() == 4 && std::isdigit(str[0]) && std::isalnum(str[1]) &&
                              std::isalnum(str[2]) && std::isalnum(str[3]);
}

// Call it after checking the code with gemmi::is_pdb_code(code).
// The convention for $PDB_DIR is the same as in BioJava, see the docs.
// type is the requested file type: 'M' for mmCIF or 'P' for PDB.
inline std::string expand_pdb_code_to_path(const std::string& code, char type) {
  std::string path;
  if (const char* pdb_dir = std::getenv("PDB_DIR")) {
    std::string lc = to_lower(code);
    path = pdb_dir;
    path += "/structures/divided/";
    path += (type == 'M' ? "mmCIF/" : "pdb/");
    path += lc.substr(1, 2) + "/";
    path += (type == 'M' ?  lc + ".cif.gz" : "pdb" + lc + ".ent.gz");
  }
  return path;
}

// type must be 'M' for mmCIF or 'P' for PDB
inline std::string expand_if_pdb_code(const std::string& input, char type='M') {
  std::string path;
  if (is_pdb_code(input)) {
    path = gemmi::expand_pdb_code_to_path(input, type);
    if (path.empty())
      fail(input + " is a PDB code, but $PDB_DIR is not set.");
  } else {
    path = input;
  }
  return path;
}

// helper function for working with binary files
inline bool is_little_endian() {
  std::uint32_t x = 1;
  return *reinterpret_cast<char *>(&x) == 1;
}

inline void swap_two_bytes(void* start) {
  char* bytes = static_cast<char*>(start);
  std::swap(bytes[0], bytes[1]);
}

inline void swap_four_bytes(void* start) {
  char* bytes = static_cast<char*>(start);
  std::swap(bytes[0], bytes[3]);
  std::swap(bytes[1], bytes[2]);
}

} // namespace gemmi
#endif
<commit_msg>Add helper: swap_eight_bytes for huge MTZ.<commit_after>// Copyright 2018 Global Phasing Ltd.
//
// File-related utilities.

#ifndef GEMMI_FILEUTIL_HPP_
#define GEMMI_FILEUTIL_HPP_

#include <cctype>    // for isdigit, isalnum
#include <cstdio>    // for FILE, fopen, fclose
#include <cstdlib>   // getenv
#include <cstring>   // strlen
#include <initializer_list>
#include <memory>    // for unique_ptr
#include <string>
#include "fail.hpp"  // for fail, sys_fail
#include "util.hpp"  // for to_lower

#if defined(_WIN32) && !defined(GEMMI_USE_FOPEN)
#include "utf.hpp"
#endif

namespace gemmi {

// strip directory and suffixes from filename
inline std::string path_basename(const std::string& path,
                                 std::initializer_list<const char*> exts) {
  size_t pos = path.find_last_of("\\/");
  std::string basename = pos == std::string::npos ? path : path.substr(pos + 1);
  for (const char* ext : exts) {
    size_t len = std::strlen(ext);
    if (basename.size() > len &&
        basename.compare(basename.length() - len, len, ext, len) == 0)
      basename.resize(basename.length() - len);
  }
  return basename;
}

// file operations
typedef std::unique_ptr<std::FILE, decltype(&std::fclose)> fileptr_t;

inline fileptr_t file_open(const char* path, const char* mode) {
  std::FILE* file;
#if defined(_WIN32) && !defined(GEMMI_USE_FOPEN)
  std::wstring wpath = UTF8_to_wchar(path);
  std::wstring wmode = UTF8_to_wchar(mode);
  if ((file = ::_wfopen(wpath.c_str(), wmode.c_str())) == nullptr)
#else
  if ((file = std::fopen(path, mode)) == nullptr)
#endif
    sys_fail(std::string("Failed to open ") + path +
             (*mode == 'w' ? " for writing" : ""));
  return fileptr_t(file, &std::fclose);
}

// helper function for treating "-" as stdin or stdout
inline fileptr_t file_open_or(const char* path, const char* mode,
                              std::FILE* dash_stream) {
  if (path[0] == '-' && path[1] == '\0')
    return fileptr_t(dash_stream, [](std::FILE*) { return 0; });
  return file_open(path, mode);
}

inline std::size_t file_size(std::FILE* f, const std::string& path) {
  if (std::fseek(f, 0, SEEK_END) != 0)
    sys_fail(path + ": fseek failed");
  long length = std::ftell(f);
  if (length < 0)
    sys_fail(path + ": ftell failed");
  if (std::fseek(f, 0, SEEK_SET) != 0)
    sys_fail(path + ": fseek failed");
  return length;
}

inline bool is_pdb_code(const std::string& str) {
  return str.length() == 4 && std::isdigit(str[0]) && std::isalnum(str[1]) &&
                              std::isalnum(str[2]) && std::isalnum(str[3]);
}

// Call it after checking the code with gemmi::is_pdb_code(code).
// The convention for $PDB_DIR is the same as in BioJava, see the docs.
// type is the requested file type: 'M' for mmCIF or 'P' for PDB.
inline std::string expand_pdb_code_to_path(const std::string& code, char type) {
  std::string path;
  if (const char* pdb_dir = std::getenv("PDB_DIR")) {
    std::string lc = to_lower(code);
    path = pdb_dir;
    path += "/structures/divided/";
    path += (type == 'M' ? "mmCIF/" : "pdb/");
    path += lc.substr(1, 2) + "/";
    path += (type == 'M' ?  lc + ".cif.gz" : "pdb" + lc + ".ent.gz");
  }
  return path;
}

// type must be 'M' for mmCIF or 'P' for PDB
inline std::string expand_if_pdb_code(const std::string& input, char type='M') {
  std::string path;
  if (is_pdb_code(input)) {
    path = gemmi::expand_pdb_code_to_path(input, type);
    if (path.empty())
      fail(input + " is a PDB code, but $PDB_DIR is not set.");
  } else {
    path = input;
  }
  return path;
}

// helper function for working with binary files
inline bool is_little_endian() {
  std::uint32_t x = 1;
  return *reinterpret_cast<char *>(&x) == 1;
}

inline void swap_two_bytes(void* start) {
  char* bytes = static_cast<char*>(start);
  std::swap(bytes[0], bytes[1]);
}

inline void swap_four_bytes(void* start) {
  char* bytes = static_cast<char*>(start);
  std::swap(bytes[0], bytes[3]);
  std::swap(bytes[1], bytes[2]);
}

inline void swap_eight_bytes(void* start) {
  char* bytes = static_cast<char*>(start);
  std::swap(bytes[0], bytes[7]);
  std::swap(bytes[1], bytes[6]);
  std::swap(bytes[2], bytes[5]);
  std::swap(bytes[3], bytes[4]);
}

} // namespace gemmi
#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: scuiimoptdlg.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: obo $ $Date: 2004-06-04 14:13:45 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SCUI_IMOPTDLG_HXX
#define SCUI_IMOPTDLG_HXX

#include "imoptdlg.hxx"

//===================================================================

class ScDelimiterTable;

class ScImportOptionsDlg : public ModalDialog
{
public:
                ScImportOptionsDlg( Window*                 pParent,
                                    BOOL                    bAscii = TRUE,
                                    const ScImportOptions*  pOptions = NULL,
                                    const String*           pStrTitle = NULL,
                                    BOOL                    bMultiByte = FALSE,
                                    BOOL                    bOnlyDbtoolsEncodings = FALSE,
                                    BOOL                    bImport = TRUE );

                ~ScImportOptionsDlg();

    void GetImportOptions( ScImportOptions& rOptions ) const;

private:
    FixedLine           aFlFieldOpt;
    FixedText           aFtFont;
    SvxTextEncodingBox  aLbFont;
    FixedText           aFtFieldSep;
    ComboBox            aEdFieldSep;
    FixedText           aFtTextSep;
    ComboBox            aEdTextSep;
    CheckBox            aCbFixed;
    OKButton            aBtnOk;
    CancelButton        aBtnCancel;
    HelpButton          aBtnHelp;

    ScDelimiterTable*   pFieldSepTab;
    ScDelimiterTable*   pTextSepTab;

private:
    USHORT GetCodeFromCombo( const ComboBox& rEd ) const;

    DECL_LINK( FixedWidthHdl, CheckBox* );
    DECL_LINK( DoubleClickHdl, ListBox* );
};

#endif

<commit_msg>INTEGRATION: CWS ooo19126 (1.3.452); FILE MERGED 2005/09/05 15:05:46 rt 1.3.452.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: scuiimoptdlg.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 21:48:34 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SCUI_IMOPTDLG_HXX
#define SCUI_IMOPTDLG_HXX

#include "imoptdlg.hxx"

//===================================================================

class ScDelimiterTable;

class ScImportOptionsDlg : public ModalDialog
{
public:
                ScImportOptionsDlg( Window*                 pParent,
                                    BOOL                    bAscii = TRUE,
                                    const ScImportOptions*  pOptions = NULL,
                                    const String*           pStrTitle = NULL,
                                    BOOL                    bMultiByte = FALSE,
                                    BOOL                    bOnlyDbtoolsEncodings = FALSE,
                                    BOOL                    bImport = TRUE );

                ~ScImportOptionsDlg();

    void GetImportOptions( ScImportOptions& rOptions ) const;

private:
    FixedLine           aFlFieldOpt;
    FixedText           aFtFont;
    SvxTextEncodingBox  aLbFont;
    FixedText           aFtFieldSep;
    ComboBox            aEdFieldSep;
    FixedText           aFtTextSep;
    ComboBox            aEdTextSep;
    CheckBox            aCbFixed;
    OKButton            aBtnOk;
    CancelButton        aBtnCancel;
    HelpButton          aBtnHelp;

    ScDelimiterTable*   pFieldSepTab;
    ScDelimiterTable*   pTextSepTab;

private:
    USHORT GetCodeFromCombo( const ComboBox& rEd ) const;

    DECL_LINK( FixedWidthHdl, CheckBox* );
    DECL_LINK( DoubleClickHdl, ListBox* );
};

#endif

<|endoftext|>


<commit_before>//===----------------------- SIFrameLowering.cpp --------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//==-----------------------------------------------------------------------===//

#include "SIFrameLowering.h"
#include "SIInstrInfo.h"
#include "SIMachineFunctionInfo.h"
#include "SIRegisterInfo.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/RegisterScavenging.h"

using namespace llvm;

static bool hasOnlySGPRSpills(const SIMachineFunctionInfo *FuncInfo,
                              const MachineFrameInfo *FrameInfo) {
  return FuncInfo->hasSpilledSGPRs() &&
    (!FuncInfo->hasSpilledVGPRs() && !FuncInfo->hasNonSpillStackObjects());
}

static ArrayRef<MCPhysReg> getAllSGPR128() {
  return makeArrayRef(AMDGPU::SReg_128RegClass.begin(),
                      AMDGPU::SReg_128RegClass.getNumRegs());
}

static ArrayRef<MCPhysReg> getAllSGPRs() {
  return makeArrayRef(AMDGPU::SGPR_32RegClass.begin(),
                      AMDGPU::SGPR_32RegClass.getNumRegs());
}

void SIFrameLowering::emitPrologue(MachineFunction &MF,
                                   MachineBasicBlock &MBB) const {
  if (!MF.getFrameInfo()->hasStackObjects())
    return;

  assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");

  SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();

  // If we only have SGPR spills, we won't actually be using scratch memory
  // since these spill to VGPRs.
  //
  // FIXME: We should be cleaning up these unused SGPR spill frame indices
  // somewhere.
  if (hasOnlySGPRSpills(MFI, MF.getFrameInfo()))
    return;

  const SIInstrInfo *TII =
      static_cast<const SIInstrInfo *>(MF.getSubtarget().getInstrInfo());
  const SIRegisterInfo *TRI = &TII->getRegisterInfo();
  const AMDGPUSubtarget &ST = MF.getSubtarget<AMDGPUSubtarget>();
  MachineRegisterInfo &MRI = MF.getRegInfo();
  MachineBasicBlock::iterator I = MBB.begin();

  // We need to insert initialization of the scratch resource descriptor.
  unsigned ScratchRsrcReg = MFI->getScratchRSrcReg();
  assert(ScratchRsrcReg != AMDGPU::NoRegister);

  unsigned ScratchWaveOffsetReg = MFI->getScratchWaveOffsetReg();
  assert(ScratchWaveOffsetReg != AMDGPU::NoRegister);

  unsigned PreloadedScratchWaveOffsetReg = TRI->getPreloadedValue(
    MF, SIRegisterInfo::PRIVATE_SEGMENT_WAVE_BYTE_OFFSET);

  unsigned PreloadedPrivateBufferReg = AMDGPU::NoRegister;
  if (ST.isAmdHsaOS()) {
    PreloadedPrivateBufferReg = TRI->getPreloadedValue(
      MF, SIRegisterInfo::PRIVATE_SEGMENT_BUFFER);
  }

  if (MFI->hasFlatScratchInit()) {
    // We don't need this if we only have spills since there is no user facing
    // scratch.

    // TODO: If we know we don't have flat instructions earlier, we can omit
    // this from the input registers.
    //
    // TODO: We only need to know if we access scratch space through a flat
    // pointer. Because we only detect if flat instructions are used at all,
    // this will be used more often than necessary on VI.

    DebugLoc DL;

    unsigned FlatScratchInitReg
      = TRI->getPreloadedValue(MF, SIRegisterInfo::FLAT_SCRATCH_INIT);

    MRI.addLiveIn(FlatScratchInitReg);
    MBB.addLiveIn(FlatScratchInitReg);

    // Copy the size in bytes.
    unsigned FlatScrInitHi = TRI->getSubReg(FlatScratchInitReg, AMDGPU::sub1);
    BuildMI(MBB, I, DL, TII->get(AMDGPU::S_MOV_B32), AMDGPU::FLAT_SCR_LO)
      .addReg(FlatScrInitHi, RegState::Kill);

    unsigned FlatScrInitLo = TRI->getSubReg(FlatScratchInitReg, AMDGPU::sub0);

    // Add wave offset in bytes to private base offset.
    // See comment in AMDKernelCodeT.h for enable_sgpr_flat_scratch_init.
    BuildMI(MBB, I, DL, TII->get(AMDGPU::S_ADD_U32), FlatScrInitLo)
      .addReg(FlatScrInitLo)
      .addReg(ScratchWaveOffsetReg);

    // Convert offset to 256-byte units.
    BuildMI(MBB, I, DL, TII->get(AMDGPU::S_LSHR_B32), AMDGPU::FLAT_SCR_HI)
      .addReg(FlatScrInitLo, RegState::Kill)
      .addImm(8);
  }

  // If we reserved the original input registers, we don't need to copy to the
  // reserved registers.
  if (ScratchRsrcReg == PreloadedPrivateBufferReg) {
    // We should always reserve these 5 registers at the same time.
    assert(ScratchWaveOffsetReg == PreloadedScratchWaveOffsetReg &&
           "scratch wave offset and private segment buffer inconsistent");
    return;
  }

  // We added live-ins during argument lowering, but since they were not used
  // they were deleted. We're adding the uses now, so add them back.
  MRI.addLiveIn(PreloadedScratchWaveOffsetReg);
  MBB.addLiveIn(PreloadedScratchWaveOffsetReg);

  if (ST.isAmdHsaOS()) {
    MRI.addLiveIn(PreloadedPrivateBufferReg);
    MBB.addLiveIn(PreloadedPrivateBufferReg);
  }

  if (!ST.hasSGPRInitBug()) {
    // We reserved the last registers for this. Shift it down to the end of those
    // which were actually used.
    //
    // FIXME: It might be safer to use a pseudoregister before replacement.

    // FIXME: We should be able to eliminate unused input registers. We only
    // cannot do this for the resources required for scratch access. For now we
    // skip over user SGPRs and may leave unused holes.

    // We find the resource first because it has an alignment requirement.
    if (ScratchRsrcReg == TRI->reservedPrivateSegmentBufferReg(MF)) {
      MachineRegisterInfo &MRI = MF.getRegInfo();

      unsigned NumPreloaded = MFI->getNumPreloadedSGPRs() / 4;
      // Skip the last 2 elements because the last one is reserved for VCC, and
      // this is the 2nd to last element already.
      for (MCPhysReg Reg : getAllSGPR128().drop_back(2).slice(NumPreloaded)) {
        // Pick the first unallocated one. Make sure we don't clobber the other
        // reserved input we needed.
        if (!MRI.isPhysRegUsed(Reg)) {
          assert(MRI.isAllocatable(Reg));
          MRI.replaceRegWith(ScratchRsrcReg, Reg);
          ScratchRsrcReg = Reg;
          MFI->setScratchRSrcReg(ScratchRsrcReg);
          break;
        }
      }
    }

    if (ScratchWaveOffsetReg == TRI->reservedPrivateSegmentWaveByteOffsetReg(MF)) {
      MachineRegisterInfo &MRI = MF.getRegInfo();
      // Skip the last 2 elements because the last one is reserved for VCC, and
      // this is the 2nd to last element already.
      unsigned NumPreloaded = MFI->getNumPreloadedSGPRs();
      for (MCPhysReg Reg : getAllSGPRs().drop_back(6).slice(NumPreloaded)) {
        // Pick the first unallocated SGPR. Be careful not to pick an alias of the
        // scratch descriptor, since we haven’t added its uses yet.
        if (!MRI.isPhysRegUsed(Reg)) {
          assert(MRI.isAllocatable(Reg) &&
                !TRI->isSubRegisterEq(ScratchRsrcReg, Reg));

          MRI.replaceRegWith(ScratchWaveOffsetReg, Reg);
          ScratchWaveOffsetReg = Reg;
          MFI->setScratchWaveOffsetReg(ScratchWaveOffsetReg);
          break;
        }
      }
    }
  }

  assert(!TRI->isSubRegister(ScratchRsrcReg, ScratchWaveOffsetReg));

  const MCInstrDesc &SMovB32 = TII->get(AMDGPU::S_MOV_B32);
  DebugLoc DL;

  if (PreloadedScratchWaveOffsetReg != ScratchWaveOffsetReg) {
    // Make sure we emit the copy for the offset first. We may have chosen to copy
    // the buffer resource into a register that aliases the input offset register.
    BuildMI(MBB, I, DL, SMovB32, ScratchWaveOffsetReg)
      .addReg(PreloadedScratchWaveOffsetReg, RegState::Kill);
  }

  if (ST.isAmdHsaOS()) {
    // Insert copies from argument register.
    assert(
      !TRI->isSubRegisterEq(PreloadedPrivateBufferReg, ScratchRsrcReg) &&
      !TRI->isSubRegisterEq(PreloadedPrivateBufferReg, ScratchWaveOffsetReg));

    unsigned Rsrc01 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub0_sub1);
    unsigned Rsrc23 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub2_sub3);

    unsigned Lo = TRI->getSubReg(PreloadedPrivateBufferReg, AMDGPU::sub0_sub1);
    unsigned Hi = TRI->getSubReg(PreloadedPrivateBufferReg, AMDGPU::sub2_sub3);

    const MCInstrDesc &SMovB64 = TII->get(AMDGPU::S_MOV_B64);

    BuildMI(MBB, I, DL, SMovB64, Rsrc01)
      .addReg(Lo, RegState::Kill);
    BuildMI(MBB, I, DL, SMovB64, Rsrc23)
      .addReg(Hi, RegState::Kill);
  } else {
    unsigned Rsrc0 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub0);
    unsigned Rsrc1 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub1);
    unsigned Rsrc2 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub2);
    unsigned Rsrc3 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub3);

    // Use relocations to get the pointer, and setup the other bits manually.
    uint64_t Rsrc23 = TII->getScratchRsrcWords23();
    BuildMI(MBB, I, DL, SMovB32, Rsrc0)
      .addExternalSymbol("SCRATCH_RSRC_DWORD0")
      .addReg(ScratchRsrcReg, RegState::ImplicitDefine);

    BuildMI(MBB, I, DL, SMovB32, Rsrc1)
      .addExternalSymbol("SCRATCH_RSRC_DWORD1")
      .addReg(ScratchRsrcReg, RegState::ImplicitDefine);

    BuildMI(MBB, I, DL, SMovB32, Rsrc2)
      .addImm(Rsrc23 & 0xffffffff)
      .addReg(ScratchRsrcReg, RegState::ImplicitDefine);

    BuildMI(MBB, I, DL, SMovB32, Rsrc3)
      .addImm(Rsrc23 >> 32)
      .addReg(ScratchRsrcReg, RegState::ImplicitDefine);
  }

  // Make the register selected live throughout the function.
  for (MachineBasicBlock &OtherBB : MF) {
    if (&OtherBB == &MBB)
      continue;

    OtherBB.addLiveIn(ScratchRsrcReg);
    OtherBB.addLiveIn(ScratchWaveOffsetReg);
  }
}

void SIFrameLowering::processFunctionBeforeFrameFinalized(
  MachineFunction &MF,
  RegScavenger *RS) const {
  MachineFrameInfo *MFI = MF.getFrameInfo();

  if (!MFI->hasStackObjects())
    return;

  bool MayNeedScavengingEmergencySlot = MFI->hasStackObjects();

  assert((RS || !MayNeedScavengingEmergencySlot) &&
         "RegScavenger required if spilling");

  if (MayNeedScavengingEmergencySlot) {
    int ScavengeFI = MFI->CreateSpillStackObject(
      AMDGPU::SGPR_32RegClass.getSize(),
      AMDGPU::SGPR_32RegClass.getAlignment());
    RS->addScavengingFrameIndex(ScavengeFI);
  }
}
<commit_msg>AMDGPU/SI: Don't try to move scratch wave offset when there are no free SGPRs<commit_after>//===----------------------- SIFrameLowering.cpp --------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//==-----------------------------------------------------------------------===//

#include "SIFrameLowering.h"
#include "SIInstrInfo.h"
#include "SIMachineFunctionInfo.h"
#include "SIRegisterInfo.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/RegisterScavenging.h"

using namespace llvm;

static bool hasOnlySGPRSpills(const SIMachineFunctionInfo *FuncInfo,
                              const MachineFrameInfo *FrameInfo) {
  return FuncInfo->hasSpilledSGPRs() &&
    (!FuncInfo->hasSpilledVGPRs() && !FuncInfo->hasNonSpillStackObjects());
}

static ArrayRef<MCPhysReg> getAllSGPR128() {
  return makeArrayRef(AMDGPU::SReg_128RegClass.begin(),
                      AMDGPU::SReg_128RegClass.getNumRegs());
}

static ArrayRef<MCPhysReg> getAllSGPRs() {
  return makeArrayRef(AMDGPU::SGPR_32RegClass.begin(),
                      AMDGPU::SGPR_32RegClass.getNumRegs());
}

void SIFrameLowering::emitPrologue(MachineFunction &MF,
                                   MachineBasicBlock &MBB) const {
  if (!MF.getFrameInfo()->hasStackObjects())
    return;

  assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");

  SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();

  // If we only have SGPR spills, we won't actually be using scratch memory
  // since these spill to VGPRs.
  //
  // FIXME: We should be cleaning up these unused SGPR spill frame indices
  // somewhere.
  if (hasOnlySGPRSpills(MFI, MF.getFrameInfo()))
    return;

  const SIInstrInfo *TII =
      static_cast<const SIInstrInfo *>(MF.getSubtarget().getInstrInfo());
  const SIRegisterInfo *TRI = &TII->getRegisterInfo();
  const AMDGPUSubtarget &ST = MF.getSubtarget<AMDGPUSubtarget>();
  MachineRegisterInfo &MRI = MF.getRegInfo();
  MachineBasicBlock::iterator I = MBB.begin();

  // We need to insert initialization of the scratch resource descriptor.
  unsigned ScratchRsrcReg = MFI->getScratchRSrcReg();
  assert(ScratchRsrcReg != AMDGPU::NoRegister);

  unsigned ScratchWaveOffsetReg = MFI->getScratchWaveOffsetReg();
  assert(ScratchWaveOffsetReg != AMDGPU::NoRegister);

  unsigned PreloadedScratchWaveOffsetReg = TRI->getPreloadedValue(
    MF, SIRegisterInfo::PRIVATE_SEGMENT_WAVE_BYTE_OFFSET);

  unsigned PreloadedPrivateBufferReg = AMDGPU::NoRegister;
  if (ST.isAmdHsaOS()) {
    PreloadedPrivateBufferReg = TRI->getPreloadedValue(
      MF, SIRegisterInfo::PRIVATE_SEGMENT_BUFFER);
  }

  if (MFI->hasFlatScratchInit()) {
    // We don't need this if we only have spills since there is no user facing
    // scratch.

    // TODO: If we know we don't have flat instructions earlier, we can omit
    // this from the input registers.
    //
    // TODO: We only need to know if we access scratch space through a flat
    // pointer. Because we only detect if flat instructions are used at all,
    // this will be used more often than necessary on VI.

    DebugLoc DL;

    unsigned FlatScratchInitReg
      = TRI->getPreloadedValue(MF, SIRegisterInfo::FLAT_SCRATCH_INIT);

    MRI.addLiveIn(FlatScratchInitReg);
    MBB.addLiveIn(FlatScratchInitReg);

    // Copy the size in bytes.
    unsigned FlatScrInitHi = TRI->getSubReg(FlatScratchInitReg, AMDGPU::sub1);
    BuildMI(MBB, I, DL, TII->get(AMDGPU::S_MOV_B32), AMDGPU::FLAT_SCR_LO)
      .addReg(FlatScrInitHi, RegState::Kill);

    unsigned FlatScrInitLo = TRI->getSubReg(FlatScratchInitReg, AMDGPU::sub0);

    // Add wave offset in bytes to private base offset.
    // See comment in AMDKernelCodeT.h for enable_sgpr_flat_scratch_init.
    BuildMI(MBB, I, DL, TII->get(AMDGPU::S_ADD_U32), FlatScrInitLo)
      .addReg(FlatScrInitLo)
      .addReg(ScratchWaveOffsetReg);

    // Convert offset to 256-byte units.
    BuildMI(MBB, I, DL, TII->get(AMDGPU::S_LSHR_B32), AMDGPU::FLAT_SCR_HI)
      .addReg(FlatScrInitLo, RegState::Kill)
      .addImm(8);
  }

  // If we reserved the original input registers, we don't need to copy to the
  // reserved registers.
  if (ScratchRsrcReg == PreloadedPrivateBufferReg) {
    // We should always reserve these 5 registers at the same time.
    assert(ScratchWaveOffsetReg == PreloadedScratchWaveOffsetReg &&
           "scratch wave offset and private segment buffer inconsistent");
    return;
  }

  // We added live-ins during argument lowering, but since they were not used
  // they were deleted. We're adding the uses now, so add them back.
  MRI.addLiveIn(PreloadedScratchWaveOffsetReg);
  MBB.addLiveIn(PreloadedScratchWaveOffsetReg);

  if (ST.isAmdHsaOS()) {
    MRI.addLiveIn(PreloadedPrivateBufferReg);
    MBB.addLiveIn(PreloadedPrivateBufferReg);
  }

  if (!ST.hasSGPRInitBug()) {
    // We reserved the last registers for this. Shift it down to the end of those
    // which were actually used.
    //
    // FIXME: It might be safer to use a pseudoregister before replacement.

    // FIXME: We should be able to eliminate unused input registers. We only
    // cannot do this for the resources required for scratch access. For now we
    // skip over user SGPRs and may leave unused holes.

    // We find the resource first because it has an alignment requirement.
    if (ScratchRsrcReg == TRI->reservedPrivateSegmentBufferReg(MF)) {
      MachineRegisterInfo &MRI = MF.getRegInfo();

      unsigned NumPreloaded = MFI->getNumPreloadedSGPRs() / 4;
      // Skip the last 2 elements because the last one is reserved for VCC, and
      // this is the 2nd to last element already.
      for (MCPhysReg Reg : getAllSGPR128().drop_back(2).slice(NumPreloaded)) {
        // Pick the first unallocated one. Make sure we don't clobber the other
        // reserved input we needed.
        if (!MRI.isPhysRegUsed(Reg)) {
          assert(MRI.isAllocatable(Reg));
          MRI.replaceRegWith(ScratchRsrcReg, Reg);
          ScratchRsrcReg = Reg;
          MFI->setScratchRSrcReg(ScratchRsrcReg);
          break;
        }
      }
    }

    if (ScratchWaveOffsetReg == TRI->reservedPrivateSegmentWaveByteOffsetReg(MF)) {
      MachineRegisterInfo &MRI = MF.getRegInfo();
      unsigned NumPreloaded = MFI->getNumPreloadedSGPRs();

      // We need to drop register from the end of the list that we cannot use
      // for the scratch wave offset.
      // + 2 s102 and s103 do not exist on VI.
      // + 2 for vcc
      // + 2 for xnack_mask
      // + 2 for flat_scratch
      // + 4 for registers reserved for scratch resource register
      // + 1 for register reserved for scratch wave offset.  (By exluding this
      //     register from the list to consider, it means that when this
      //     register is being used for the scratch wave offset and there
      //     are no other free SGPRs, then the value will stay in this register.
      // ----
      //  13
      for (MCPhysReg Reg : getAllSGPRs().drop_back(13).slice(NumPreloaded)) {
        // Pick the first unallocated SGPR. Be careful not to pick an alias of the
        // scratch descriptor, since we haven’t added its uses yet.
        if (!MRI.isPhysRegUsed(Reg)) {
          assert(MRI.isAllocatable(Reg) &&
                !TRI->isSubRegisterEq(ScratchRsrcReg, Reg));

          MRI.replaceRegWith(ScratchWaveOffsetReg, Reg);
          ScratchWaveOffsetReg = Reg;
          MFI->setScratchWaveOffsetReg(ScratchWaveOffsetReg);
          break;
        }
      }
    }
  }

  assert(!TRI->isSubRegister(ScratchRsrcReg, ScratchWaveOffsetReg));

  const MCInstrDesc &SMovB32 = TII->get(AMDGPU::S_MOV_B32);
  DebugLoc DL;

  if (PreloadedScratchWaveOffsetReg != ScratchWaveOffsetReg) {
    // Make sure we emit the copy for the offset first. We may have chosen to copy
    // the buffer resource into a register that aliases the input offset register.
    BuildMI(MBB, I, DL, SMovB32, ScratchWaveOffsetReg)
      .addReg(PreloadedScratchWaveOffsetReg, RegState::Kill);
  }

  if (ST.isAmdHsaOS()) {
    // Insert copies from argument register.
    assert(
      !TRI->isSubRegisterEq(PreloadedPrivateBufferReg, ScratchRsrcReg) &&
      !TRI->isSubRegisterEq(PreloadedPrivateBufferReg, ScratchWaveOffsetReg));

    unsigned Rsrc01 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub0_sub1);
    unsigned Rsrc23 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub2_sub3);

    unsigned Lo = TRI->getSubReg(PreloadedPrivateBufferReg, AMDGPU::sub0_sub1);
    unsigned Hi = TRI->getSubReg(PreloadedPrivateBufferReg, AMDGPU::sub2_sub3);

    const MCInstrDesc &SMovB64 = TII->get(AMDGPU::S_MOV_B64);

    BuildMI(MBB, I, DL, SMovB64, Rsrc01)
      .addReg(Lo, RegState::Kill);
    BuildMI(MBB, I, DL, SMovB64, Rsrc23)
      .addReg(Hi, RegState::Kill);
  } else {
    unsigned Rsrc0 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub0);
    unsigned Rsrc1 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub1);
    unsigned Rsrc2 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub2);
    unsigned Rsrc3 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub3);

    // Use relocations to get the pointer, and setup the other bits manually.
    uint64_t Rsrc23 = TII->getScratchRsrcWords23();
    BuildMI(MBB, I, DL, SMovB32, Rsrc0)
      .addExternalSymbol("SCRATCH_RSRC_DWORD0")
      .addReg(ScratchRsrcReg, RegState::ImplicitDefine);

    BuildMI(MBB, I, DL, SMovB32, Rsrc1)
      .addExternalSymbol("SCRATCH_RSRC_DWORD1")
      .addReg(ScratchRsrcReg, RegState::ImplicitDefine);

    BuildMI(MBB, I, DL, SMovB32, Rsrc2)
      .addImm(Rsrc23 & 0xffffffff)
      .addReg(ScratchRsrcReg, RegState::ImplicitDefine);

    BuildMI(MBB, I, DL, SMovB32, Rsrc3)
      .addImm(Rsrc23 >> 32)
      .addReg(ScratchRsrcReg, RegState::ImplicitDefine);
  }

  // Make the register selected live throughout the function.
  for (MachineBasicBlock &OtherBB : MF) {
    if (&OtherBB == &MBB)
      continue;

    OtherBB.addLiveIn(ScratchRsrcReg);
    OtherBB.addLiveIn(ScratchWaveOffsetReg);
  }
}

void SIFrameLowering::processFunctionBeforeFrameFinalized(
  MachineFunction &MF,
  RegScavenger *RS) const {
  MachineFrameInfo *MFI = MF.getFrameInfo();

  if (!MFI->hasStackObjects())
    return;

  bool MayNeedScavengingEmergencySlot = MFI->hasStackObjects();

  assert((RS || !MayNeedScavengingEmergencySlot) &&
         "RegScavenger required if spilling");

  if (MayNeedScavengingEmergencySlot) {
    int ScavengeFI = MFI->CreateSpillStackObject(
      AMDGPU::SGPR_32RegClass.getSize(),
      AMDGPU::SGPR_32RegClass.getAlignment());
    RS->addScavengingFrameIndex(ScavengeFI);
  }
}
<|endoftext|>


<commit_before><commit_msg>[products.base] added boundary operator handling to AssemblableBaseHelper<commit_after><|endoftext|>


<commit_before>/****************************************************************************

 This file is part of the GLC-lib library.
 Copyright (C) 2005-2008 Laurent Ribon (laumaya@users.sourceforge.net)
 Version 1.2.0, packaged on September 2009.

 http://glc-lib.sourceforge.net

 GLC-lib is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 GLC-lib is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with GLC-lib; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*****************************************************************************/

//! \file glc_instance.cpp implementation of the GLC_3DViewInstance class.

#include "glc_3dviewinstance.h"
#include "../shading/glc_selectionmaterial.h"
#include "../viewport/glc_viewport.h"
#include <QMutexLocker>
#include "../glc_state.h"

//! A Mutex
QMutex GLC_3DViewInstance::m_Mutex;

//! The global default LOD
int GLC_3DViewInstance::m_GlobalDefaultLOD= 10;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

// Default constructor
GLC_3DViewInstance::GLC_3DViewInstance()
: GLC_Object()
, m_3DRep()
, m_pBoundingBox(NULL)
, m_MatPos()
, m_IsBoundingBoxValid(false)
, m_IsSelected(false)
, m_PolyFace(GL_FRONT_AND_BACK)
, m_PolyMode(GL_FILL)
, m_IsVisible(true)
, m_colorId()
, m_DefaultLOD(m_GlobalDefaultLOD)
{
	// Encode Color Id
	encodeIdInRGBA();

	//qDebug() << "GLC_3DViewInstance::GLC_3DViewInstance null instance ID = " << m_Uid;
	//qDebug() << "Number of instance" << (*m_pNumberOfInstance);
}

// Contruct instance with a geometry
GLC_3DViewInstance::GLC_3DViewInstance(GLC_VboGeom* pGeom)
: GLC_Object()
, m_3DRep(pGeom)
, m_pBoundingBox(NULL)
, m_MatPos()
, m_IsBoundingBoxValid(false)
, m_IsSelected(false)
, m_PolyFace(GL_FRONT_AND_BACK)
, m_PolyMode(GL_FILL)
, m_IsVisible(true)
, m_colorId()
, m_DefaultLOD(m_GlobalDefaultLOD)
{
	// Encode Color Id
	encodeIdInRGBA();

	setName(m_3DRep.name());

	//qDebug() << "GLC_3DViewInstance::GLC_3DViewInstance ID = " << m_Uid;
	//qDebug() << "Number of instance" << (*m_pNumberOfInstance);
}

// Contruct instance with a 3DRep
GLC_3DViewInstance::GLC_3DViewInstance(const GLC_3DRep& rep)
: GLC_Object()
, m_3DRep(rep)
, m_pBoundingBox(NULL)
, m_MatPos()
, m_IsBoundingBoxValid(false)
, m_IsSelected(false)
, m_PolyFace(GL_FRONT_AND_BACK)
, m_PolyMode(GL_FILL)
, m_IsVisible(true)
, m_colorId()
, m_DefaultLOD(m_GlobalDefaultLOD)
{
	// Encode Color Id
	encodeIdInRGBA();

	setName(m_3DRep.name());

	//qDebug() << "GLC_3DViewInstance::GLC_3DViewInstance ID = " << m_Uid;
	//qDebug() << "Number of instance" << (*m_pNumberOfInstance);
}

// Copy constructor
GLC_3DViewInstance::GLC_3DViewInstance(const GLC_3DViewInstance& inputNode)
: GLC_Object(inputNode)
, m_3DRep(inputNode.m_3DRep)
, m_pBoundingBox(NULL)
, m_MatPos(inputNode.m_MatPos)
, m_IsBoundingBoxValid(inputNode.m_IsBoundingBoxValid)
, m_IsSelected(inputNode.m_IsSelected)
, m_PolyFace(inputNode.m_PolyFace)
, m_PolyMode(inputNode.m_PolyMode)
, m_IsVisible(inputNode.m_IsVisible)
, m_colorId()
, m_DefaultLOD(inputNode.m_DefaultLOD)
{
	// Encode Color Id
	encodeIdInRGBA();

	if (NULL != inputNode.m_pBoundingBox)
	{
		m_pBoundingBox= new GLC_BoundingBox(*inputNode.m_pBoundingBox);
	}
}

// Assignement operator
GLC_3DViewInstance& GLC_3DViewInstance::operator=(const GLC_3DViewInstance& inputNode)
{
	if (this != &inputNode)
	{
		// Clear this instance
		clear();
		GLC_Object::operator=(inputNode);
		// Encode Color Id
		encodeIdInRGBA();

		m_3DRep= inputNode.m_3DRep;
		if (NULL != inputNode.m_pBoundingBox)
		{
			m_pBoundingBox= new GLC_BoundingBox(*inputNode.m_pBoundingBox);
		}
		m_MatPos= inputNode.m_MatPos;
		m_IsBoundingBoxValid= inputNode.m_IsBoundingBoxValid;
		m_IsSelected= inputNode.m_IsSelected;
		m_PolyFace= inputNode.m_PolyFace;
		m_PolyMode= inputNode.m_PolyMode;
		m_IsVisible= inputNode.m_IsVisible;
		m_DefaultLOD= inputNode.m_DefaultLOD;

		//qDebug() << "GLC_3DViewInstance::operator= :ID = " << m_Uid;
		//qDebug() << "Number of instance" << (*m_pNumberOfInstance);
	}

	return *this;
}

// Destructor
GLC_3DViewInstance::~GLC_3DViewInstance()
{
	clear();
}

//////////////////////////////////////////////////////////////////////
// Get Functions
//////////////////////////////////////////////////////////////////////

// Get the bounding box
GLC_BoundingBox GLC_3DViewInstance::getBoundingBox(void)
{
	GLC_BoundingBox resultBox;
	if (getBoundingBoxValidity())
	{
		resultBox= *m_pBoundingBox;
	}
	else if (not m_3DRep.isEmpty())
	{
		computeBoundingBox();
		m_IsBoundingBoxValid= true;
		resultBox= *m_pBoundingBox;
	}

	return resultBox;
}

//! Set the global default LOD value
void GLC_3DViewInstance::setGlobalDefaultLod(int lod)
{
	QMutexLocker locker(&m_Mutex);
	m_GlobalDefaultLOD= lod;
}

// Clone the instance
GLC_3DViewInstance GLC_3DViewInstance::deepCopy() const
{

	GLC_3DViewInstance cloneInstance(m_3DRep.deepCopy());

	if (NULL != m_pBoundingBox)
	{
		cloneInstance.m_pBoundingBox= new GLC_BoundingBox(*m_pBoundingBox);
	}

	cloneInstance.m_MatPos= m_MatPos;
	cloneInstance.m_IsBoundingBoxValid= m_IsBoundingBoxValid;
	cloneInstance.m_IsSelected= m_IsSelected;
	cloneInstance.m_PolyFace= m_PolyFace;
	cloneInstance.m_PolyMode= m_PolyMode;
	cloneInstance.m_IsVisible= m_IsVisible;
	return cloneInstance;
}

// Instanciate the instance
GLC_3DViewInstance GLC_3DViewInstance::instanciate()
{
	GLC_3DViewInstance instance(*this);
	instance.m_Uid= glc::GLC_GenID();
	// Encode Color Id
	encodeIdInRGBA();

	return instance;
}

// Return the GLC_uint decoded ID from RGBA encoded ID
GLC_uint GLC_3DViewInstance::decodeRgbId(const GLubyte* pcolorId)
{
	GLC_uint returnId= 0;
	returnId|= (GLC_uint)pcolorId[0] << (0 * 8);
	returnId|= (GLC_uint)pcolorId[1] << (1 * 8);
	returnId|= (GLC_uint)pcolorId[2] << (2 * 8);
	// Only get first 24 bits
	//returnId|= (GLC_uint)pcolorId[3] << (3 * 8);

	return returnId;
}

//////////////////////////////////////////////////////////////////////
// Set Functions
//////////////////////////////////////////////////////////////////////

// Set the instance Geometry
bool GLC_3DViewInstance::setGeometry(GLC_VboGeom* pGeom)
{
	if (m_3DRep.contains(pGeom))
	{
		return false;
	}
	else
	{
		m_3DRep.addGeom(pGeom);
		return true;
	}
}

// Instance translation
GLC_3DViewInstance& GLC_3DViewInstance::translate(double Tx, double Ty, double Tz)
{
	multMatrix(GLC_Matrix4x4(Tx, Ty, Tz));

	return *this;
}

// Move instance with a 4x4Matrix
GLC_3DViewInstance& GLC_3DViewInstance::multMatrix(const GLC_Matrix4x4 &MultMat)
{
	m_MatPos= MultMat * m_MatPos;
	m_IsBoundingBoxValid= false;

	return *this;
}

// Replace the instance Matrix
GLC_3DViewInstance& GLC_3DViewInstance::setMatrix(const GLC_Matrix4x4 &SetMat)
{
	m_MatPos= SetMat;
	m_IsBoundingBoxValid= false;

	return *this;
}

// Reset the instance Matrix
GLC_3DViewInstance& GLC_3DViewInstance::resetMatrix(void)
{
	m_MatPos.setToIdentity();
	m_IsBoundingBoxValid= false;

	return *this;
}

// Polygon's display style
void GLC_3DViewInstance::setPolygonMode(GLenum Face, GLenum Mode)
{
	// Change the polygon mode only if there is a change
	if ((m_PolyFace != Face) || (m_PolyMode != Mode))
	{
		m_PolyFace= Face;
		m_PolyMode= Mode;
	}
}

//////////////////////////////////////////////////////////////////////
// OpenGL Functions
//////////////////////////////////////////////////////////////////////

// Display the instance
void GLC_3DViewInstance::glExecute(bool transparent, bool useLod, GLC_Viewport* pView)
{
	if (m_3DRep.isEmpty()) return;
	// Save current OpenGL Matrix
	glPushMatrix();
	glVisProperties();
	if(GLC_State::isInSelectionMode())
	{
		glColor3ubv(m_colorId); // D'ont use Alpha component
	}
	const int size= m_3DRep.numberOfBody();
	if (useLod and (NULL != pView))
	{
		for (int i= 0; i < size; ++i)
		{
			const int lodValue= choseLod(m_3DRep.geomAt(i)->boundingBox(), pView);
			if (lodValue <= 100)
			{
				m_3DRep.geomAt(i)->setCurrentLod(lodValue);
				m_3DRep.geomAt(i)->glExecute(m_IsSelected, transparent);
			}
		}
	}
	else
	{
		for (int i= 0; i < size; ++i)
		{
			int lodValue= 0;
			if (GLC_State::isPixelCullingActivated())
			{
				lodValue= choseLod(m_3DRep.geomAt(i)->boundingBox(), pView);
			}

			if (lodValue <= 100)
			{
				m_3DRep.geomAt(i)->setCurrentLod(m_DefaultLOD);
				m_3DRep.geomAt(i)->glExecute(m_IsSelected, transparent);
			}

		}
	}
	// Restore OpenGL Matrix
	glPopMatrix();
}

//////////////////////////////////////////////////////////////////////
// private services functions
//////////////////////////////////////////////////////////////////////

// compute the instance bounding box
// m_pGeomList should be not null
void GLC_3DViewInstance::computeBoundingBox(void)
{
	if (m_3DRep.isEmpty()) return;

	if (m_pBoundingBox != NULL)
	{
		delete m_pBoundingBox;
		m_pBoundingBox= NULL;
	}
	m_pBoundingBox= new GLC_BoundingBox();
	const int size= m_3DRep.numberOfBody();
	for (int i= 0; i < size; ++i)
	{
		m_pBoundingBox->combine(m_3DRep.geomAt(i)->boundingBox());
	}

	m_pBoundingBox->transform(m_MatPos);
}

// Clear current instance
void GLC_3DViewInstance::clear()
{

	delete m_pBoundingBox;
	m_pBoundingBox= NULL;

	// invalidate the bounding box
	m_IsBoundingBoxValid= false;

}

//! Encode Id to RGBA color
void GLC_3DViewInstance::encodeIdInRGBA()
{
	m_colorId[0]= static_cast<GLubyte>((m_Uid >> (0 * 8)) & 0xFF);
	m_colorId[1]= static_cast<GLubyte>((m_Uid >> (1 * 8)) & 0xFF);
	m_colorId[2]= static_cast<GLubyte>((m_Uid >> (2 * 8)) & 0xFF);
	m_colorId[3]= static_cast<GLubyte>((m_Uid >> (3 * 8)) & 0xFF);
}

// Compute LOD
int GLC_3DViewInstance::choseLod(const GLC_BoundingBox& boundingBox, GLC_Viewport* pView)
{
	if (NULL == pView) return 0;
	const double diameter= boundingBox.boundingSphereRadius() * 2.0 * m_MatPos.scalingX();
	GLC_Vector4d center(m_MatPos * boundingBox.getCenter());

	const double dist= (center - pView->cameraHandle()->getEye()).norm();
	const double cameraCover= dist * (2.0 * tan((pView->getFov() * glc::PI / 180.0) / 2.0));
	double ratio= diameter / cameraCover * 150.0;

	if (ratio > 100.0) ratio= 100.0;
	ratio= 100.0 - ratio;
	if ((ratio > 98.0) and GLC_State::isPixelCullingActivated()) ratio= 110.0;
	if (ratio < static_cast<double>(m_DefaultLOD)) ratio= static_cast<double>(m_DefaultLOD);
	//qDebug() << "RATIO = " << static_cast<int>(ratio);

	return static_cast<int>(ratio);
}

<commit_msg>Update deepCopy with the new GLC_3DRep deepCopy interface.<commit_after>/****************************************************************************

 This file is part of the GLC-lib library.
 Copyright (C) 2005-2008 Laurent Ribon (laumaya@users.sourceforge.net)
 Version 1.2.0, packaged on September 2009.

 http://glc-lib.sourceforge.net

 GLC-lib is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 GLC-lib is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with GLC-lib; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*****************************************************************************/

//! \file glc_instance.cpp implementation of the GLC_3DViewInstance class.

#include "glc_3dviewinstance.h"
#include "../shading/glc_selectionmaterial.h"
#include "../viewport/glc_viewport.h"
#include <QMutexLocker>
#include "../glc_state.h"

//! A Mutex
QMutex GLC_3DViewInstance::m_Mutex;

//! The global default LOD
int GLC_3DViewInstance::m_GlobalDefaultLOD= 10;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

// Default constructor
GLC_3DViewInstance::GLC_3DViewInstance()
: GLC_Object()
, m_3DRep()
, m_pBoundingBox(NULL)
, m_MatPos()
, m_IsBoundingBoxValid(false)
, m_IsSelected(false)
, m_PolyFace(GL_FRONT_AND_BACK)
, m_PolyMode(GL_FILL)
, m_IsVisible(true)
, m_colorId()
, m_DefaultLOD(m_GlobalDefaultLOD)
{
	// Encode Color Id
	encodeIdInRGBA();

	//qDebug() << "GLC_3DViewInstance::GLC_3DViewInstance null instance ID = " << m_Uid;
	//qDebug() << "Number of instance" << (*m_pNumberOfInstance);
}

// Contruct instance with a geometry
GLC_3DViewInstance::GLC_3DViewInstance(GLC_VboGeom* pGeom)
: GLC_Object()
, m_3DRep(pGeom)
, m_pBoundingBox(NULL)
, m_MatPos()
, m_IsBoundingBoxValid(false)
, m_IsSelected(false)
, m_PolyFace(GL_FRONT_AND_BACK)
, m_PolyMode(GL_FILL)
, m_IsVisible(true)
, m_colorId()
, m_DefaultLOD(m_GlobalDefaultLOD)
{
	// Encode Color Id
	encodeIdInRGBA();

	setName(m_3DRep.name());

	//qDebug() << "GLC_3DViewInstance::GLC_3DViewInstance ID = " << m_Uid;
	//qDebug() << "Number of instance" << (*m_pNumberOfInstance);
}

// Contruct instance with a 3DRep
GLC_3DViewInstance::GLC_3DViewInstance(const GLC_3DRep& rep)
: GLC_Object()
, m_3DRep(rep)
, m_pBoundingBox(NULL)
, m_MatPos()
, m_IsBoundingBoxValid(false)
, m_IsSelected(false)
, m_PolyFace(GL_FRONT_AND_BACK)
, m_PolyMode(GL_FILL)
, m_IsVisible(true)
, m_colorId()
, m_DefaultLOD(m_GlobalDefaultLOD)
{
	// Encode Color Id
	encodeIdInRGBA();

	setName(m_3DRep.name());

	//qDebug() << "GLC_3DViewInstance::GLC_3DViewInstance ID = " << m_Uid;
	//qDebug() << "Number of instance" << (*m_pNumberOfInstance);
}

// Copy constructor
GLC_3DViewInstance::GLC_3DViewInstance(const GLC_3DViewInstance& inputNode)
: GLC_Object(inputNode)
, m_3DRep(inputNode.m_3DRep)
, m_pBoundingBox(NULL)
, m_MatPos(inputNode.m_MatPos)
, m_IsBoundingBoxValid(inputNode.m_IsBoundingBoxValid)
, m_IsSelected(inputNode.m_IsSelected)
, m_PolyFace(inputNode.m_PolyFace)
, m_PolyMode(inputNode.m_PolyMode)
, m_IsVisible(inputNode.m_IsVisible)
, m_colorId()
, m_DefaultLOD(inputNode.m_DefaultLOD)
{
	// Encode Color Id
	encodeIdInRGBA();

	if (NULL != inputNode.m_pBoundingBox)
	{
		m_pBoundingBox= new GLC_BoundingBox(*inputNode.m_pBoundingBox);
	}
}

// Assignement operator
GLC_3DViewInstance& GLC_3DViewInstance::operator=(const GLC_3DViewInstance& inputNode)
{
	if (this != &inputNode)
	{
		// Clear this instance
		clear();
		GLC_Object::operator=(inputNode);
		// Encode Color Id
		encodeIdInRGBA();

		m_3DRep= inputNode.m_3DRep;
		if (NULL != inputNode.m_pBoundingBox)
		{
			m_pBoundingBox= new GLC_BoundingBox(*inputNode.m_pBoundingBox);
		}
		m_MatPos= inputNode.m_MatPos;
		m_IsBoundingBoxValid= inputNode.m_IsBoundingBoxValid;
		m_IsSelected= inputNode.m_IsSelected;
		m_PolyFace= inputNode.m_PolyFace;
		m_PolyMode= inputNode.m_PolyMode;
		m_IsVisible= inputNode.m_IsVisible;
		m_DefaultLOD= inputNode.m_DefaultLOD;

		//qDebug() << "GLC_3DViewInstance::operator= :ID = " << m_Uid;
		//qDebug() << "Number of instance" << (*m_pNumberOfInstance);
	}

	return *this;
}

// Destructor
GLC_3DViewInstance::~GLC_3DViewInstance()
{
	clear();
}

//////////////////////////////////////////////////////////////////////
// Get Functions
//////////////////////////////////////////////////////////////////////

// Get the bounding box
GLC_BoundingBox GLC_3DViewInstance::getBoundingBox(void)
{
	GLC_BoundingBox resultBox;
	if (getBoundingBoxValidity())
	{
		resultBox= *m_pBoundingBox;
	}
	else if (not m_3DRep.isEmpty())
	{
		computeBoundingBox();
		m_IsBoundingBoxValid= true;
		resultBox= *m_pBoundingBox;
	}

	return resultBox;
}

//! Set the global default LOD value
void GLC_3DViewInstance::setGlobalDefaultLod(int lod)
{
	QMutexLocker locker(&m_Mutex);
	m_GlobalDefaultLOD= lod;
}

// Clone the instance
GLC_3DViewInstance GLC_3DViewInstance::deepCopy() const
{

	GLC_3DRep* pRep= dynamic_cast<GLC_3DRep*>(m_3DRep.deepCopy());
	GLC_3DRep newRep(*pRep);
	delete pRep;
	GLC_3DViewInstance cloneInstance(newRep);

	if (NULL != m_pBoundingBox)
	{
		cloneInstance.m_pBoundingBox= new GLC_BoundingBox(*m_pBoundingBox);
	}

	cloneInstance.m_MatPos= m_MatPos;
	cloneInstance.m_IsBoundingBoxValid= m_IsBoundingBoxValid;
	cloneInstance.m_IsSelected= m_IsSelected;
	cloneInstance.m_PolyFace= m_PolyFace;
	cloneInstance.m_PolyMode= m_PolyMode;
	cloneInstance.m_IsVisible= m_IsVisible;
	return cloneInstance;
}

// Instanciate the instance
GLC_3DViewInstance GLC_3DViewInstance::instanciate()
{
	GLC_3DViewInstance instance(*this);
	instance.m_Uid= glc::GLC_GenID();
	// Encode Color Id
	encodeIdInRGBA();

	return instance;
}

// Return the GLC_uint decoded ID from RGBA encoded ID
GLC_uint GLC_3DViewInstance::decodeRgbId(const GLubyte* pcolorId)
{
	GLC_uint returnId= 0;
	returnId|= (GLC_uint)pcolorId[0] << (0 * 8);
	returnId|= (GLC_uint)pcolorId[1] << (1 * 8);
	returnId|= (GLC_uint)pcolorId[2] << (2 * 8);
	// Only get first 24 bits
	//returnId|= (GLC_uint)pcolorId[3] << (3 * 8);

	return returnId;
}

//////////////////////////////////////////////////////////////////////
// Set Functions
//////////////////////////////////////////////////////////////////////

// Set the instance Geometry
bool GLC_3DViewInstance::setGeometry(GLC_VboGeom* pGeom)
{
	if (m_3DRep.contains(pGeom))
	{
		return false;
	}
	else
	{
		m_3DRep.addGeom(pGeom);
		return true;
	}
}

// Instance translation
GLC_3DViewInstance& GLC_3DViewInstance::translate(double Tx, double Ty, double Tz)
{
	multMatrix(GLC_Matrix4x4(Tx, Ty, Tz));

	return *this;
}

// Move instance with a 4x4Matrix
GLC_3DViewInstance& GLC_3DViewInstance::multMatrix(const GLC_Matrix4x4 &MultMat)
{
	m_MatPos= MultMat * m_MatPos;
	m_IsBoundingBoxValid= false;

	return *this;
}

// Replace the instance Matrix
GLC_3DViewInstance& GLC_3DViewInstance::setMatrix(const GLC_Matrix4x4 &SetMat)
{
	m_MatPos= SetMat;
	m_IsBoundingBoxValid= false;

	return *this;
}

// Reset the instance Matrix
GLC_3DViewInstance& GLC_3DViewInstance::resetMatrix(void)
{
	m_MatPos.setToIdentity();
	m_IsBoundingBoxValid= false;

	return *this;
}

// Polygon's display style
void GLC_3DViewInstance::setPolygonMode(GLenum Face, GLenum Mode)
{
	// Change the polygon mode only if there is a change
	if ((m_PolyFace != Face) || (m_PolyMode != Mode))
	{
		m_PolyFace= Face;
		m_PolyMode= Mode;
	}
}

//////////////////////////////////////////////////////////////////////
// OpenGL Functions
//////////////////////////////////////////////////////////////////////

// Display the instance
void GLC_3DViewInstance::glExecute(bool transparent, bool useLod, GLC_Viewport* pView)
{
	if (m_3DRep.isEmpty()) return;
	// Save current OpenGL Matrix
	glPushMatrix();
	glVisProperties();
	if(GLC_State::isInSelectionMode())
	{
		glColor3ubv(m_colorId); // D'ont use Alpha component
	}
	const int size= m_3DRep.numberOfBody();
	if (useLod and (NULL != pView))
	{
		for (int i= 0; i < size; ++i)
		{
			const int lodValue= choseLod(m_3DRep.geomAt(i)->boundingBox(), pView);
			if (lodValue <= 100)
			{
				m_3DRep.geomAt(i)->setCurrentLod(lodValue);
				m_3DRep.geomAt(i)->glExecute(m_IsSelected, transparent);
			}
		}
	}
	else
	{
		for (int i= 0; i < size; ++i)
		{
			int lodValue= 0;
			if (GLC_State::isPixelCullingActivated())
			{
				lodValue= choseLod(m_3DRep.geomAt(i)->boundingBox(), pView);
			}

			if (lodValue <= 100)
			{
				m_3DRep.geomAt(i)->setCurrentLod(m_DefaultLOD);
				m_3DRep.geomAt(i)->glExecute(m_IsSelected, transparent);
			}

		}
	}
	// Restore OpenGL Matrix
	glPopMatrix();
}

//////////////////////////////////////////////////////////////////////
// private services functions
//////////////////////////////////////////////////////////////////////

// compute the instance bounding box
// m_pGeomList should be not null
void GLC_3DViewInstance::computeBoundingBox(void)
{
	if (m_3DRep.isEmpty()) return;

	if (m_pBoundingBox != NULL)
	{
		delete m_pBoundingBox;
		m_pBoundingBox= NULL;
	}
	m_pBoundingBox= new GLC_BoundingBox();
	const int size= m_3DRep.numberOfBody();
	for (int i= 0; i < size; ++i)
	{
		m_pBoundingBox->combine(m_3DRep.geomAt(i)->boundingBox());
	}

	m_pBoundingBox->transform(m_MatPos);
}

// Clear current instance
void GLC_3DViewInstance::clear()
{

	delete m_pBoundingBox;
	m_pBoundingBox= NULL;

	// invalidate the bounding box
	m_IsBoundingBoxValid= false;

}

//! Encode Id to RGBA color
void GLC_3DViewInstance::encodeIdInRGBA()
{
	m_colorId[0]= static_cast<GLubyte>((m_Uid >> (0 * 8)) & 0xFF);
	m_colorId[1]= static_cast<GLubyte>((m_Uid >> (1 * 8)) & 0xFF);
	m_colorId[2]= static_cast<GLubyte>((m_Uid >> (2 * 8)) & 0xFF);
	m_colorId[3]= static_cast<GLubyte>((m_Uid >> (3 * 8)) & 0xFF);
}

// Compute LOD
int GLC_3DViewInstance::choseLod(const GLC_BoundingBox& boundingBox, GLC_Viewport* pView)
{
	if (NULL == pView) return 0;
	const double diameter= boundingBox.boundingSphereRadius() * 2.0 * m_MatPos.scalingX();
	GLC_Vector4d center(m_MatPos * boundingBox.getCenter());

	const double dist= (center - pView->cameraHandle()->getEye()).norm();
	const double cameraCover= dist * (2.0 * tan((pView->getFov() * glc::PI / 180.0) / 2.0));
	double ratio= diameter / cameraCover * 150.0;

	if (ratio > 100.0) ratio= 100.0;
	ratio= 100.0 - ratio;
	if ((ratio > 98.0) and GLC_State::isPixelCullingActivated()) ratio= 110.0;
	if (ratio < static_cast<double>(m_DefaultLOD)) ratio= static_cast<double>(m_DefaultLOD);
	//qDebug() << "RATIO = " << static_cast<int>(ratio);

	return static_cast<int>(ratio);
}

<|endoftext|>


<commit_before>#include <cassert>
#include "Collective.hpp"
#include "Delegate.hpp"

// Delegates implementation of reductions.
// Only one reduction can happen at a time.

#define _MAX_PROC_NODES 128

// relies on static address being the same all binaries
int64_t _col_values[_MAX_PROC_NODES];
int64_t _col_done_count;
bool _col_allowed = true;

/// Reduction involving all SoftXMT Nodes.
/// For now involves a barrier, so only one
/// collective op is allowed at a time.
int64_t SoftXMT_collective_reduce( int64_t (*commutative_func)(int64_t, int64_t), Node home_node, int64_t myValue, int64_t initial ) {
    assert(_col_allowed);
    _col_allowed = false;

    Node myNode = SoftXMT_mynode();
    if (myNode == home_node) {
        const uint64_t num_nodes = SoftXMT_nodes();
        assert( num_nodes <= _MAX_PROC_NODES );

        _col_done_count = 0;

        // TODO method without barrier (or reducer thread-only barrier)
        VLOG(5) << "home enters collective barrier";
        SoftXMT_barrier_commsafe();
        VLOG(5) << SoftXMT_mynode() << " exits collective barrier";

        _col_values[home_node] = myValue;
        VLOG(5) << "home enters collective waiting";
        while (true) {
            SoftXMT_yield();
            if (_col_done_count==num_nodes-1) {
                break;
            }
        }

        // perform the reduction
        int64_t sofar = initial;
        for (int i=0; i<num_nodes; i++) {
           sofar = (*commutative_func)(sofar, _col_values[i]);
        }

        _col_allowed = true;
        return sofar;
    } else {
        GlobalAddress<int64_t> done_adr = GlobalAddress<int64_t>::TwoDimensional(&_col_done_count, home_node);
        GlobalAddress<int64_t> value_adr = GlobalAddress<int64_t>::TwoDimensional(&_col_values[myNode], home_node);

        // TODO no barrier
        VLOG(5) << SoftXMT_mynode() << " enters collective barrier";
        SoftXMT_barrier_commsafe();
        VLOG(5) << SoftXMT_mynode() << " exits collective barrier";

        SoftXMT_delegate_write_word( value_adr, myValue );
        /* implicit fence since write is blocking */
        SoftXMT_delegate_fetch_and_add_word( done_adr, 1);

        _col_allowed = true;
        return 0;
    }
}

int64_t collective_max(int64_t a, int64_t b) { return (a>b) ? a : b; }
int64_t collective_min(int64_t a, int64_t b) { return (a<b) ? a : b; }
int64_t collective_add(int64_t a, int64_t b) { return a+b; }
int64_t collective_mult(int64_t a, int64_t b) { return a*b; }
<commit_msg>added storage for allreduce<commit_after>#include <cassert>
#include "Collective.hpp"
#include "Delegate.hpp"

// Delegates implementation of reductions.
// Only one reduction can happen at a time.

#define _MAX_PROC_NODES 128

// relies on static address being the same all binaries
int64_t _col_values[_MAX_PROC_NODES];
int64_t _col_done_count;
bool _col_allowed = true;

Thread * reducing_thread;
int64_t reduction_result;
Node reduction_reported_in = 0;

/// Reduction involving all SoftXMT Nodes.
/// For now involves a barrier, so only one
/// collective op is allowed at a time.
int64_t SoftXMT_collective_reduce( int64_t (*commutative_func)(int64_t, int64_t), Node home_node, int64_t myValue, int64_t initial ) {
    assert(_col_allowed);
    _col_allowed = false;

    Node myNode = SoftXMT_mynode();
    if (myNode == home_node) {
        const uint64_t num_nodes = SoftXMT_nodes();
        assert( num_nodes <= _MAX_PROC_NODES );

        _col_done_count = 0;

        // TODO method without barrier (or reducer thread-only barrier)
        VLOG(5) << "home enters collective barrier";
        SoftXMT_barrier_commsafe();
        VLOG(5) << SoftXMT_mynode() << " exits collective barrier";

        _col_values[home_node] = myValue;
        VLOG(5) << "home enters collective waiting";
        while (true) {
            SoftXMT_yield();
            if (_col_done_count==num_nodes-1) {
                break;
            }
        }

        // perform the reduction
        int64_t sofar = initial;
        for (int i=0; i<num_nodes; i++) {
           sofar = (*commutative_func)(sofar, _col_values[i]);
        }

        _col_allowed = true;
        return sofar;
    } else {
        GlobalAddress<int64_t> done_adr = GlobalAddress<int64_t>::TwoDimensional(&_col_done_count, home_node);
        GlobalAddress<int64_t> value_adr = GlobalAddress<int64_t>::TwoDimensional(&_col_values[myNode], home_node);

        // TODO no barrier
        VLOG(5) << SoftXMT_mynode() << " enters collective barrier";
        SoftXMT_barrier_commsafe();
        VLOG(5) << SoftXMT_mynode() << " exits collective barrier";

        SoftXMT_delegate_write_word( value_adr, myValue );
        /* implicit fence since write is blocking */
        SoftXMT_delegate_fetch_and_add_word( done_adr, 1);

        _col_allowed = true;
        return 0;
    }
}

int64_t collective_max(int64_t a, int64_t b) { return (a>b) ? a : b; }
int64_t collective_min(int64_t a, int64_t b) { return (a<b) ? a : b; }
int64_t collective_add(int64_t a, int64_t b) { return a+b; }
int64_t collective_mult(int64_t a, int64_t b) { return a*b; }
<|endoftext|>