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

YASK: Yet Another Stencil Kit
Copyright (c) 2014-2020, Intel Corporation

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

* The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

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

//////// Some common code shared between YASK compiler and kernel. //////////

// Include this first to assure NDEBUG is set properly.
#include "yask_assert.hpp"

#include <sstream>
#include "common_utils.hpp"

using namespace std;

namespace yask {

    // Update this version string anytime changes are
    // committed to a repository, especially when
    // affecting master or develop branches.
    // Be sure to keep 2 digits in minor and patch
    // fields to allow proper alphanumeric sorting
    // for numbers above 9 (at least up to 99).

    // Format: "major.minor.patch".
    const string version = "3.05.04";

    string yask_get_version_string() {
        return version;
    }

    // Controls whether make*Str() functions add
    // suffixes or just print full number for
    // machine parsing.
    bool is_suffix_print_enabled = true;

    // Return num with SI multiplier and "iB" suffix,
    // e.g., 412KiB.
    string make_byte_str(size_t nbytes)
    {
        if (!is_suffix_print_enabled)
            return to_string(nbytes);

        ostringstream os;
        double num = double(nbytes);
        const double one_ki = 1024;
        const double one_mi = one_ki * one_ki;
        const double one_gi = one_ki * one_mi;
        const double one_ti = one_ki * one_gi;
        const double one_pi = one_ki * one_ti;
        const double one_ei = one_ki * one_pi;
        if (num > one_ei)
            os << (num / one_ei) << "Ei";
        else if (num > one_pi)
            os << (num / one_pi) << "Pi";
        else if (num > one_ti)
            os << (num / one_ti) << "Ti";
        else if (num > one_gi)
            os << (num / one_gi) << "Gi";
        else if (num > one_mi)
            os << (num / one_mi) << "Mi";
        else if (num > one_ki)
            os << (num / one_ki) << "Ki";
        else
            os << num;
        os << "B";
        return os.str();
    }

    // Return num with SI multiplier, e.g. "3.14M".
    // Use this one for rates, etc.
    string make_num_str(idx_t num) {
        if (!is_suffix_print_enabled || (num >= 0 && num < 1000))
            return to_string(num);
        return make_num_str(double(num));
    }
    string make_num_str(double num)
    {
        if (!is_suffix_print_enabled)
            return to_string(num);

        ostringstream os;
        const double one_k = 1e3;
        const double one_m = 1e6;
        const double one_g = 1e9;
        const double one_t = 1e12;
        const double one_p = 1e15;
        const double one_e = 1e18;
        const double onem = 1e-3;
        const double oneu = 1e-6;
        const double onen = 1e-9;
#ifdef USE_PICO
        const double onep = 1e-12;
        const double onef = 1e-15;
#endif
        if (num == 0.)
            os << num;
        else if (num > one_e)
            os << (num / one_e) << "E";
        else if (num > one_p)
            os << (num / one_p) << "P";
        else if (num > one_t)
            os << (num / one_t) << "T";
        else if (num > one_g)
            os << (num / one_g) << "G";
        else if (num > one_m)
            os << (num / one_m) << "M";
        else if (num > one_k)
            os << (num / one_k) << "K"; // NB: official SI symbol is "k".
#ifdef USE_PICO
        else if (num < onep)
            os << (num / onef) << "f";
        else if (num < onen)
            os << (num / onep) << "p";
#endif
        else if (num < oneu)
            os << (num / onen) << "n";
        else if (num < onem)
            os << (num / oneu) << "u"; // NB: official SI symbol is Greek mu.
        else if (num < 1.)
            os << (num / onem) << "m";
        else
            os << num;
        return os.str();
    }

    // A var that behaves like OMP_NUM_THREADS.
    int yask_num_threads[yask_max_levels] = { 0 };

    // See yask_common_api.hpp for documentation.
    const char* yask_exception::what() const noexcept {
        return _msg.c_str();
    }

    void yask_exception::add_message(const string& arg_msg) {
        _msg.append(arg_msg);
    }

    const char* yask_exception::get_message() const {
        return _msg.c_str();
    }

}
<commit_msg>Update release number.<commit_after>/*****************************************************************************

YASK: Yet Another Stencil Kit
Copyright (c) 2014-2020, Intel Corporation

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

* The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

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

//////// Some common code shared between YASK compiler and kernel. //////////

// Include this first to assure NDEBUG is set properly.
#include "yask_assert.hpp"

#include <sstream>
#include "common_utils.hpp"

using namespace std;

namespace yask {

    // Update this version string anytime changes are
    // committed to a repository, especially when
    // affecting master or develop branches.
    // Be sure to keep 2 digits in minor and patch
    // fields to allow proper alphanumeric sorting
    // for numbers above 9 (at least up to 99).

    // Format: "major.minor.patch".
    const string version = "3.05.05";

    string yask_get_version_string() {
        return version;
    }

    // Controls whether make*Str() functions add
    // suffixes or just print full number for
    // machine parsing.
    bool is_suffix_print_enabled = true;

    // Return num with SI multiplier and "iB" suffix,
    // e.g., 412KiB.
    string make_byte_str(size_t nbytes)
    {
        if (!is_suffix_print_enabled)
            return to_string(nbytes);

        ostringstream os;
        double num = double(nbytes);
        const double one_ki = 1024;
        const double one_mi = one_ki * one_ki;
        const double one_gi = one_ki * one_mi;
        const double one_ti = one_ki * one_gi;
        const double one_pi = one_ki * one_ti;
        const double one_ei = one_ki * one_pi;
        if (num > one_ei)
            os << (num / one_ei) << "Ei";
        else if (num > one_pi)
            os << (num / one_pi) << "Pi";
        else if (num > one_ti)
            os << (num / one_ti) << "Ti";
        else if (num > one_gi)
            os << (num / one_gi) << "Gi";
        else if (num > one_mi)
            os << (num / one_mi) << "Mi";
        else if (num > one_ki)
            os << (num / one_ki) << "Ki";
        else
            os << num;
        os << "B";
        return os.str();
    }

    // Return num with SI multiplier, e.g. "3.14M".
    // Use this one for rates, etc.
    string make_num_str(idx_t num) {
        if (!is_suffix_print_enabled || (num >= 0 && num < 1000))
            return to_string(num);
        return make_num_str(double(num));
    }
    string make_num_str(double num)
    {
        if (!is_suffix_print_enabled)
            return to_string(num);

        ostringstream os;
        const double one_k = 1e3;
        const double one_m = 1e6;
        const double one_g = 1e9;
        const double one_t = 1e12;
        const double one_p = 1e15;
        const double one_e = 1e18;
        const double onem = 1e-3;
        const double oneu = 1e-6;
        const double onen = 1e-9;
#ifdef USE_PICO
        const double onep = 1e-12;
        const double onef = 1e-15;
#endif
        if (num == 0.)
            os << num;
        else if (num > one_e)
            os << (num / one_e) << "E";
        else if (num > one_p)
            os << (num / one_p) << "P";
        else if (num > one_t)
            os << (num / one_t) << "T";
        else if (num > one_g)
            os << (num / one_g) << "G";
        else if (num > one_m)
            os << (num / one_m) << "M";
        else if (num > one_k)
            os << (num / one_k) << "K"; // NB: official SI symbol is "k".
#ifdef USE_PICO
        else if (num < onep)
            os << (num / onef) << "f";
        else if (num < onen)
            os << (num / onep) << "p";
#endif
        else if (num < oneu)
            os << (num / onen) << "n";
        else if (num < onem)
            os << (num / oneu) << "u"; // NB: official SI symbol is Greek mu.
        else if (num < 1.)
            os << (num / onem) << "m";
        else
            os << num;
        return os.str();
    }

    // A var that behaves like OMP_NUM_THREADS.
    int yask_num_threads[yask_max_levels] = { 0 };

    // See yask_common_api.hpp for documentation.
    const char* yask_exception::what() const noexcept {
        return _msg.c_str();
    }

    void yask_exception::add_message(const string& arg_msg) {
        _msg.append(arg_msg);
    }

    const char* yask_exception::get_message() const {
        return _msg.c_str();
    }

}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include "config/bitcoin-config.h"
#endif

#include <cstddef>

#if defined(HAVE_SYS_SELECT_H)
#include <sys/select.h>
#endif

// Prior to GLIBC_2.14, memcpy was aliased to memmove.
extern "C" void* memmove(void* a, const void* b, size_t c);
extern "C" void* memcpy(void* a, const void* b, size_t c)
{
    return memmove(a, b, c);
}

extern "C" void __chk_fail(void) __attribute__((__noreturn__));
extern "C" FDELT_TYPE __fdelt_warn(FDELT_TYPE a)
{
    if (a >= FD_SETSIZE)
        __chk_fail();
    return a / __NFDBITS;
}
extern "C" FDELT_TYPE __fdelt_chk(FDELT_TYPE) __attribute__((weak, alias("__fdelt_warn")));
<commit_msg>GCC-7 and glibc-2.27 compat code<commit_after>// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif

#include <cstddef>
#include <cstdint>

#if defined(HAVE_SYS_SELECT_H)
#include <sys/select.h>
#endif

// Prior to GLIBC_2.14, memcpy was aliased to memmove.
extern "C" void* memmove(void* a, const void* b, size_t c);
extern "C" void* memcpy(void* a, const void* b, size_t c)
{
    return memmove(a, b, c);
}

extern "C" void __chk_fail(void) __attribute__((__noreturn__));
extern "C" FDELT_TYPE __fdelt_warn(FDELT_TYPE a)
{
    if (a >= FD_SETSIZE)
        __chk_fail();
    return a / __NFDBITS;
}
extern "C" FDELT_TYPE __fdelt_chk(FDELT_TYPE) __attribute__((weak, alias("__fdelt_warn")));

#if defined(__i386__) || defined(__arm__)

extern "C" int64_t __udivmoddi4(uint64_t u, uint64_t v, uint64_t* rp);

extern "C" int64_t __wrap___divmoddi4(int64_t u, int64_t v, int64_t* rp)
{
    int32_t c1 = 0, c2 = 0;
    int64_t uu = u, vv = v;
    int64_t w;
    int64_t r;

    if (uu < 0) {
        c1 = ~c1, c2 = ~c2, uu = -uu;
    }
    if (vv < 0) {
        c1 = ~c1, vv = -vv;
    }

    w = __udivmoddi4(uu, vv, (uint64_t*)&r);
    if (c1)
        w = -w;
    if (c2)
        r = -r;

    *rp = r;
    return w;
}
#endif

extern "C" float log2f_old(float x);
#ifdef __i386__
__asm(".symver log2f_old,log2f@GLIBC_2.1");
#elif defined(__amd64__)
__asm(".symver log2f_old,log2f@GLIBC_2.2.5");
#elif defined(__arm__)
__asm(".symver log2f_old,log2f@GLIBC_2.4");
#elif defined(__aarch64__)
__asm(".symver log2f_old,log2f@GLIBC_2.17");
#elif defined(__riscv)
__asm(".symver log2f_old,log2f@GLIBC_2.27");
#endif
extern "C" float __wrap_log2f(float x)
{
    return log2f_old(x);
}
<|endoftext|>


<commit_before>
// =================================================================================================
// This file is part of the CLBlast project. The project is licensed under Apache Version 2.0. This
// project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max-
// width of 100 characters per line.
//
// Author(s):
//   Cedric Nugteren <www.cedricnugteren.nl>
//
// This file implements the caching functionality of compiled binaries and programs.
//
// =================================================================================================

#ifndef CLBLAST_CACHE_H_
#define CLBLAST_CACHE_H_

#include <string>
#include <mutex>
#include <map>

#include "utilities/utilities.hpp"

namespace clblast {
// =================================================================================================

// The generic thread-safe cache. We assume that the Key may be a heavyweight struct that is not
// normally used by the caller, while the Value is either lightweight or ref-counted.
// Hence, searching by non-Key is supported (if there is a corresponding operator<()), and
// on Store() the Key instance is moved from the caller (because it will likely be constructed
// as temporary at the time of Store()).
template <typename Key, typename Value>
class Cache {
public:
  // Cached object is returned by-value to avoid racing with Invalidate().
  // Due to lack of std::optional<>, in case of a cache miss we return a default-constructed
  // Value and set the flag to false.
  template <typename U>
  Value Get(const U &key, bool *in_cache) const;

  // We do not return references to just stored object to avoid racing with Invalidate().
  // Caller is expected to store a temporary.
  void Store(Key &&key, Value &&value);
  void Invalidate();

  // Removes all entries with a given key
  void Remove(const Key &key);
  template <int I1, int I2> void RemoveBySubset(const Key &key); // currently supports 2 indices

  static Cache<Key, Value> &Instance();

private:
#if __cplusplus >= 201402L
  // The std::less<void> allows to search in cache by an object comparable with Key, without
  // constructing a temporary Key
  // (see http://en.cppreference.com/w/cpp/utility/functional/less_void,
  //      http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3657.htm,
  //      http://stackoverflow.com/questions/10536788/avoiding-key-construction-for-stdmapfind)
  std::map<Key, Value, std::less<void>> cache_;
#else
  std::vector<std::pair<Key, Value>> cache_;
#endif
  mutable std::mutex cache_mutex_;

  static Cache<Key, Value> instance_;
}; // class Cache

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

// The key struct for the cache of compiled OpenCL binaries
// Order of fields: precision, routine_name, device_name (smaller fields first)
typedef std::tuple<Precision, std::string, std::string> BinaryKey;
typedef std::tuple<const Precision &, const std::string &, const std::string &> BinaryKeyRef;

typedef Cache<BinaryKey, std::string> BinaryCache;

extern template class Cache<BinaryKey, std::string>;
extern template std::string BinaryCache::Get(const BinaryKeyRef &, bool *) const;

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

// The key struct for the cache of compiled OpenCL programs (context-dependent)
// Order of fields: context, precision, routine_name (smaller fields first)
typedef std::tuple<cl_context, cl_device_id, Precision, std::string> ProgramKey;
typedef std::tuple<const cl_context &, const cl_device_id &, const Precision &, const std::string &> ProgramKeyRef;

typedef Cache<ProgramKey, Program> ProgramCache;

extern template class Cache<ProgramKey, Program>;
extern template Program ProgramCache::Get(const ProgramKeyRef &, bool *) const;

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

class Database;

// The key struct for the cache of database maps.
// Order of fields: precision, device_name, kernel_name (smaller fields first)
typedef std::tuple<Precision, std::string, std::string> DatabaseKey;
typedef std::tuple<const Precision &, const std::string &, const std::string &> DatabaseKeyRef;

typedef Cache<DatabaseKey, Database> DatabaseCache;

extern template class Cache<DatabaseKey, Database>;
extern template Database DatabaseCache::Get(const DatabaseKeyRef &, bool *) const;

// =================================================================================================
} // namespace clblast

// CLBLAST_CACHE_H_
#endif
<commit_msg>Fixed comment decribing the order of program cache fields<commit_after>
// =================================================================================================
// This file is part of the CLBlast project. The project is licensed under Apache Version 2.0. This
// project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max-
// width of 100 characters per line.
//
// Author(s):
//   Cedric Nugteren <www.cedricnugteren.nl>
//
// This file implements the caching functionality of compiled binaries and programs.
//
// =================================================================================================

#ifndef CLBLAST_CACHE_H_
#define CLBLAST_CACHE_H_

#include <string>
#include <mutex>
#include <map>

#include "utilities/utilities.hpp"

namespace clblast {
// =================================================================================================

// The generic thread-safe cache. We assume that the Key may be a heavyweight struct that is not
// normally used by the caller, while the Value is either lightweight or ref-counted.
// Hence, searching by non-Key is supported (if there is a corresponding operator<()), and
// on Store() the Key instance is moved from the caller (because it will likely be constructed
// as temporary at the time of Store()).
template <typename Key, typename Value>
class Cache {
public:
  // Cached object is returned by-value to avoid racing with Invalidate().
  // Due to lack of std::optional<>, in case of a cache miss we return a default-constructed
  // Value and set the flag to false.
  template <typename U>
  Value Get(const U &key, bool *in_cache) const;

  // We do not return references to just stored object to avoid racing with Invalidate().
  // Caller is expected to store a temporary.
  void Store(Key &&key, Value &&value);
  void Invalidate();

  // Removes all entries with a given key
  void Remove(const Key &key);
  template <int I1, int I2> void RemoveBySubset(const Key &key); // currently supports 2 indices

  static Cache<Key, Value> &Instance();

private:
#if __cplusplus >= 201402L
  // The std::less<void> allows to search in cache by an object comparable with Key, without
  // constructing a temporary Key
  // (see http://en.cppreference.com/w/cpp/utility/functional/less_void,
  //      http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3657.htm,
  //      http://stackoverflow.com/questions/10536788/avoiding-key-construction-for-stdmapfind)
  std::map<Key, Value, std::less<void>> cache_;
#else
  std::vector<std::pair<Key, Value>> cache_;
#endif
  mutable std::mutex cache_mutex_;

  static Cache<Key, Value> instance_;
}; // class Cache

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

// The key struct for the cache of compiled OpenCL binaries
// Order of fields: precision, routine_name, device_name (smaller fields first)
typedef std::tuple<Precision, std::string, std::string> BinaryKey;
typedef std::tuple<const Precision &, const std::string &, const std::string &> BinaryKeyRef;

typedef Cache<BinaryKey, std::string> BinaryCache;

extern template class Cache<BinaryKey, std::string>;
extern template std::string BinaryCache::Get(const BinaryKeyRef &, bool *) const;

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

// The key struct for the cache of compiled OpenCL programs (context-dependent)
// Order of fields: context, device_id, precision, routine_name (smaller fields first)
typedef std::tuple<cl_context, cl_device_id, Precision, std::string> ProgramKey;
typedef std::tuple<const cl_context &, const cl_device_id &, const Precision &, const std::string &> ProgramKeyRef;

typedef Cache<ProgramKey, Program> ProgramCache;

extern template class Cache<ProgramKey, Program>;
extern template Program ProgramCache::Get(const ProgramKeyRef &, bool *) const;

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

class Database;

// The key struct for the cache of database maps.
// Order of fields: precision, device_name, kernel_name (smaller fields first)
typedef std::tuple<Precision, std::string, std::string> DatabaseKey;
typedef std::tuple<const Precision &, const std::string &, const std::string &> DatabaseKeyRef;

typedef Cache<DatabaseKey, Database> DatabaseCache;

extern template class Cache<DatabaseKey, Database>;
extern template Database DatabaseCache::Get(const DatabaseKeyRef &, bool *) const;

// =================================================================================================
} // namespace clblast

// CLBLAST_CACHE_H_
#endif
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright (c) 2000-2016 Ericsson Telecom AB
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Balasko, Jeno
 *   Baranyi, Botond
 *   Raduly, Csaba
 *   Szabados, Kristof
 *   Szabo, Bence Janos
 *
 ******************************************************************************/
/*
 * XerAttributes.cpp
 *
 *  Created on: Oct 17, 2008
 *      Author: ecsardu
 */

#include "XerAttributes.hh"
// The above line must be the first in this file
#include "../common/memory.h"

#include "Value.hh"

static const NamespaceRestriction empty_nsr = {
  0, 0, NamespaceRestriction::UNUSED
};

static const XerAttributes::NameChange nochange= { NamespaceSpecification::NO_MANGLING };

XerAttributes::XerAttributes()
: abstract_(false)
, attribute_(false)
, anyAttributes_(empty_nsr)
, anyElement_(empty_nsr)
, base64_(false)
, block_(false)
, decimal_(false)
, defaultForEmpty_(0)
, defaultValue_(0)
, element_(false)
, embedValues_(false)
, form_(UNSET)
, has_fractionDigits_(false)
, fractionDigits_(0)
, hex_(false)
, list_(false)
, name_(nochange)
, namespace_()
//, pi_or_comment_()
, num_text_(0)
, text_(0)
, untagged_(false)
, useNil_(false)
, useNumber_(false)
, useOrder_(false)
, useQName_(false)
, useType_(false)
, useUnion_(false)
, whitespace_(PRESERVE)
{
  //__asm("int3");
  //fprintf(stderr, "XER attributes(%p) new\n", (void*)this);
}

void FreeNamespaceRestriction(NamespaceRestriction& nsr)
{
  for (size_t i=0; i < nsr.nElements_; ++i) {
    Free(nsr.uris_[i]);
  }
  Free(nsr.uris_);
}

XerAttributes::~XerAttributes()
{
  FreeNamespaceRestriction(anyAttributes_);
  FreeNamespaceRestriction(anyElement_);

  Free(defaultForEmpty_);
  delete defaultValue_;

  FreeNameChange(name_);
  FreeNamespace(namespace_);

  //if (pi_or_comment_.position_ > AFTER_VALUE) {
  //  Free(pi_or_comment_.value_);
  //}

  for (size_t i=0; i < num_text_; ++i) {
    if ((unsigned long)text_[i].keyword
      > (unsigned long)NamespaceSpecification::LOWERCASED) {
      Free(text_[i].uri);
    }
    if (text_[i].prefix > (char*)NamespaceSpecification::ALL) {
      Free(text_[i].prefix);
    }
  }
  Free(text_);
}

void XerAttributes::FreeNamespace(NamespaceSpecification &ns) {
  switch (ns.keyword) {
  case NamespaceSpecification::NO_MANGLING:
  case NamespaceSpecification::CAPITALIZED:
  case NamespaceSpecification::UNCAPITALIZED:
  case NamespaceSpecification::UPPERCASED:
  case NamespaceSpecification::LOWERCASED:
    break; // nothing to do
  default: // real string, must be freed
    Free(ns.uri);
    break;
  }
  ns.uri = 0;
  Free(ns.prefix);
  ns.prefix = 0;
}

void XerAttributes::FreeNameChange(XerAttributes::NameChange& n) {
  switch (n.kw_) {
  case NamespaceSpecification::NO_MANGLING:
  case NamespaceSpecification::CAPITALIZED:
  case NamespaceSpecification::UNCAPITALIZED:
  case NamespaceSpecification::UPPERCASED:
  case NamespaceSpecification::LOWERCASED:
    break; // nothing to do
  default: // real string, must be freed
    Free(n.nn_);
    break;
  }
  n.kw_ = NamespaceSpecification::NO_MANGLING;
}

void XerAttributes::print(const char *type_name) const {
  fprintf(stderr, "XER attributes(%p) for %s:\n", (const void*)this, type_name);
  if (empty()) fputs("...Empty...\n", stderr);
  else {
    fputs(abstract_ ? "ABSTRACT\n" : "", stderr);
    fputs(attribute_ ? "ATTRIBUTE\n" : "", stderr);

    if (has_aa(this)) {
      if (anyAttributes_.type_ == NamespaceRestriction::NOTHING) {
        fputs("ANY-ATTRIBUTES\n", stderr);
      }
      else for (size_t i = 0; i < anyAttributes_.nElements_; ++i) {
        fprintf(stderr, "ANY-ATTRIBUTES %s %s\n",
          anyAttributes_.type_ == NamespaceRestriction::FROM ? "EXCEPT" : "FROM",
            (anyAttributes_.uris_[i] && *anyAttributes_.uris_[i]) ?
              anyAttributes_.uris_[i] : "ABSENT");
      }
    }

    if (has_ae(this)) {
      if (anyElement_.type_ == NamespaceRestriction::NOTHING) {
        fputs("ANY-ELEMENT\n", stderr);
      }
      else for (size_t i = 0; i < anyElement_.nElements_; ++i) {
        fprintf(stderr, "ANY-ELEMENT %s %s\n",
          anyElement_.type_ == NamespaceRestriction::FROM ? "EXCEPT" : "FROM",
            (anyElement_.uris_[i] && *anyElement_.uris_[i]) ?
              anyElement_.uris_[i] : "ABSENT");
      }
    }
    fputs(base64_ ? "BASE64\n" : "", stderr);
    fputs(block_ ? "BLOCK\n" : "", stderr);
    fputs(decimal_ ? "DECIMAL\n" : "", stderr);

    if (defaultForEmpty_)  fprintf(stderr, "DEFAULT-FOR-EMPTY '%s'\n", defaultForEmpty_);

    if (element_) fputs("ELEMENT\n", stderr);
    fputs(embedValues_ ? "EMBED-VALUES\n" : "", stderr);
    fputs((form_ & QUALIFIED) ? "FORM AS QUALIFIED\n" : "", stderr);
    if (has_fractionDigits_) fprintf(stderr, "FRACTIONDIGITS '%i'\n", fractionDigits_);
    fputs(hex_ ? "hexBinary" : "", stderr);
    fputs(list_ ? "LIST\n" : "", stderr);

    static const char * xforms[] = {
      "CAPITALIZED", "UNCAPITALIZED", "UPPERCASED", "LOWERCASED"
    };
    switch (name_.kw_) {
    case NamespaceSpecification::NO_MANGLING: // nothing to do
      break;
    default: // a string
      fprintf(stderr, "NAME AS '%s'\n", name_.nn_);
      break;
    case NamespaceSpecification::CAPITALIZED:
    case NamespaceSpecification::UNCAPITALIZED:
    case NamespaceSpecification::LOWERCASED:
    case NamespaceSpecification::UPPERCASED:
      fprintf(stderr, "NAME AS %s\n",
        xforms[name_.kw_ - NamespaceSpecification::CAPITALIZED]);
      break;
    }

    if (namespace_.uri) {
      fprintf(stderr, "NAMESPACE '%s' %s %s\n", namespace_.uri,
        (namespace_.prefix ? "PREFIX" : ""),
        (namespace_.prefix ? namespace_.prefix : ""));
    }

    //if (pi_or_comment_.position_ != NOWHERE) {
    //  fputs("PI-OR-COMMENT\n", stderr);
    //}
    if (num_text_) {
      fputs("TEXT\n", stderr);
      for (size_t t=0; t < num_text_; ++t) {
        const char* who = 0, *action = 0;
        switch ((unsigned long)(text_[t].uri) ) {
        case NamespaceSpecification::LOWERCASED:
          action = "LOWERCASED"; break;
        case NamespaceSpecification::UPPERCASED:
          action = "UPPERCASED"; break;
        case NamespaceSpecification::CAPITALIZED:
          action = "CAPITALIZED"; break;
        case NamespaceSpecification::UNCAPITALIZED:
          action = "UNCAPITALIZED"; break;
        case 0:
          action = "text"; break;
        default:
          action = text_[t].uri; break;
        }

        switch ((unsigned long)text_[t].prefix) {
        case 0: who = ""; break;
        case NamespaceSpecification::ALL: who = "ALL"; break;
        default: who = text_[t].prefix; break;
        }
        fprintf(stderr, "   %s as %s\n", who, action);
      }
    }
    fputs(untagged_ ? "UNTAGGED\n" : "", stderr);
    fputs(useNil_ ? "USE-NIL\n" : "", stderr);
    fputs(useNumber_ ? "USE-NUMBER\n" : "", stderr);
    fputs(useOrder_ ? "USE-ORDER\n" : "", stderr);
    fputs(useQName_ ? "USE-QNAME\n" : "", stderr);
    fputs(useType_ ? "USE-TYPE\n" : "", stderr);
    fputs(useUnion_ ? "USE-UNION\n" : "", stderr);
    if (whitespace_ != PRESERVE) fprintf(stderr, "WHITESPACE %s\n",
      whitespace_ == COLLAPSE ? "COLLAPSE" : "REPLACE");
    fputs(". . . . .\n", stderr);
  }
}

XerAttributes& XerAttributes::operator |= (const XerAttributes& other)
{
  if (other.empty()) FATAL_ERROR("XerAttributes::operator |=");
/*
fprintf(stderr, "@@@ replacing:\n");
print("orig.");
other.print("other");
*/
  abstract_ |= other.abstract_;
  attribute_ |= other.attribute_;
  if (has_aa(&other)) {
    FreeNamespaceRestriction(anyAttributes_);
    anyAttributes_.nElements_ = other.anyAttributes_.nElements_;
    anyAttributes_.type_      = other.anyAttributes_.type_;
    anyAttributes_.uris_      = (char**)Malloc(anyAttributes_.nElements_
      * sizeof(char*));
    for (size_t i=0; i < anyAttributes_.nElements_; ++i) {
      anyAttributes_.uris_[i] = mcopystr(other.anyAttributes_.uris_[i]);
    }
  }
  if (has_ae(&other)) {
    FreeNamespaceRestriction(anyElement_);
    anyElement_.nElements_ = other.anyElement_.nElements_;
    anyElement_.type_      = other.anyElement_.type_;
    anyElement_.uris_      = (char**)Malloc(anyElement_.nElements_
      * sizeof(char*));
    for (size_t i=0; i < anyElement_.nElements_; ++i) {
      anyElement_.uris_[i] = mcopystr(other.anyElement_.uris_[i]);
    }
  }
  base64_ |= other.base64_;
  block_ |= other.block_;
  decimal_ |= other.decimal_;

  if (other.defaultForEmpty_ != 0) {
    Free(defaultForEmpty_);
    defaultForEmpty_ = mcopystr(other.defaultForEmpty_);
  }

  element_ |= other.element_;
  embedValues_ |= other.embedValues_;
  form_ = other.form_;
  has_fractionDigits_ = other.has_fractionDigits_;
  fractionDigits_ = other.fractionDigits_;
  hex_  |= other.hex_;
  list_ |= other.list_;
  if (other.name_.kw_ != NamespaceSpecification::NO_MANGLING) {
    FreeNameChange(name_);
    switch (other.name_.kw_) {
    case NamespaceSpecification::NO_MANGLING:
      break; // not possible inside the if
    case NamespaceSpecification::CAPITALIZED:
    case NamespaceSpecification::UNCAPITALIZED:
    case NamespaceSpecification::UPPERCASED:
    case NamespaceSpecification::LOWERCASED:
      name_.kw_ = other.name_.kw_;
      break;
    default: // a real string
      name_.nn_ = mcopystr(other.name_.nn_);
      break;
    }
  }

  if (other.namespace_.uri != 0) {
    switch (namespace_.keyword) {
    case NamespaceSpecification::NO_MANGLING:
    case NamespaceSpecification::CAPITALIZED:
    case NamespaceSpecification::UNCAPITALIZED:
    case NamespaceSpecification::UPPERCASED:
    case NamespaceSpecification::LOWERCASED:
      break; // nothing to do
    default: // real string, must be freed
      Free(namespace_.uri);
      break;
    }
    switch (other.namespace_.keyword) {
    case NamespaceSpecification::NO_MANGLING:
    case NamespaceSpecification::CAPITALIZED:
    case NamespaceSpecification::UNCAPITALIZED:
    case NamespaceSpecification::UPPERCASED:
    case NamespaceSpecification::LOWERCASED:
      namespace_.uri = other.namespace_.uri;
      break;
    default: // real string
      namespace_.uri = mcopystr(other.namespace_.uri);
      break;
    }
    Free(namespace_.prefix);
    namespace_.prefix = mcopystr(other.namespace_.prefix);
  }
  //pi_or_comment_;

  if (other.num_text_) {
    // Append the other TEXT. No attempt is made to eliminate duplicates.
    // This will be done in Type::chk_xer_text().
    size_t old_num = num_text_;
    num_text_ += other.num_text_;
    text_ = (NamespaceSpecification *)Realloc(
      text_, num_text_ * sizeof(NamespaceSpecification));
    for (size_t t = 0; t < other.num_text_; ++t) {
      switch ((unsigned long)(other.text_[t].uri) ) {
      case NamespaceSpecification::LOWERCASED:
      case NamespaceSpecification::UPPERCASED:
      case NamespaceSpecification::CAPITALIZED:
      case NamespaceSpecification::UNCAPITALIZED:
      case NamespaceSpecification::NO_MANGLING:
        text_[old_num + t].uri = other.text_[t].uri;
        break;
      default:
        text_[old_num + t].uri = mcopystr(other.text_[t].uri);
        break;
      }

      switch ((unsigned long)other.text_[t].prefix) {
      case 0: case NamespaceSpecification::ALL:
        text_[old_num + t].prefix = other.text_[t].prefix;
        break;
      default:
        text_[old_num + t].prefix = mcopystr(other.text_[t].prefix);
        break;
      }
    }
  }
  untagged_ |= other.untagged_;
  useNil_ |= other.useNil_;
  useNumber_ |= other.useNumber_;
  useOrder_ |= other.useOrder_;
  useQName_ |= other.useQName_;
  useType_ |= other.useType_;
  useUnion_ |= other.useUnion_;
  whitespace_ = other.whitespace_;
  return *this;
}

bool XerAttributes::empty() const
{
  return !abstract_
  && !attribute_
  && !has_aa(this)
  && !has_ae(this)
  && !base64_
  && !block_
  && !decimal_
  && defaultForEmpty_ == 0
  && !element_
  && !embedValues_
  && !(form_ & LOCALLY_SET)
  && !has_fractionDigits_
  && !hex_
  && !list_
  && name_.kw_ == NamespaceSpecification::NO_MANGLING
  && namespace_.uri == 0
  && num_text_ == 0
  && !untagged_
  && !useNil_
  && !useNumber_
  && !useOrder_
  && !useQName_
  && !useType_
  && !useUnion_
  && whitespace_ == PRESERVE;
}

<commit_msg>fractiondigits fix<commit_after>/******************************************************************************
 * Copyright (c) 2000-2016 Ericsson Telecom AB
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Balasko, Jeno
 *   Baranyi, Botond
 *   Raduly, Csaba
 *   Szabados, Kristof
 *   Szabo, Bence Janos
 *
 ******************************************************************************/
/*
 * XerAttributes.cpp
 *
 *  Created on: Oct 17, 2008
 *      Author: ecsardu
 */

#include "XerAttributes.hh"
// The above line must be the first in this file
#include "../common/memory.h"

#include "Value.hh"

static const NamespaceRestriction empty_nsr = {
  0, 0, NamespaceRestriction::UNUSED
};

static const XerAttributes::NameChange nochange= { NamespaceSpecification::NO_MANGLING };

XerAttributes::XerAttributes()
: abstract_(false)
, attribute_(false)
, anyAttributes_(empty_nsr)
, anyElement_(empty_nsr)
, base64_(false)
, block_(false)
, decimal_(false)
, defaultForEmpty_(0)
, defaultValue_(0)
, element_(false)
, embedValues_(false)
, form_(UNSET)
, has_fractionDigits_(false)
, fractionDigits_(0)
, hex_(false)
, list_(false)
, name_(nochange)
, namespace_()
//, pi_or_comment_()
, num_text_(0)
, text_(0)
, untagged_(false)
, useNil_(false)
, useNumber_(false)
, useOrder_(false)
, useQName_(false)
, useType_(false)
, useUnion_(false)
, whitespace_(PRESERVE)
{
  //__asm("int3");
  //fprintf(stderr, "XER attributes(%p) new\n", (void*)this);
}

void FreeNamespaceRestriction(NamespaceRestriction& nsr)
{
  for (size_t i=0; i < nsr.nElements_; ++i) {
    Free(nsr.uris_[i]);
  }
  Free(nsr.uris_);
}

XerAttributes::~XerAttributes()
{
  FreeNamespaceRestriction(anyAttributes_);
  FreeNamespaceRestriction(anyElement_);

  Free(defaultForEmpty_);
  delete defaultValue_;

  FreeNameChange(name_);
  FreeNamespace(namespace_);

  //if (pi_or_comment_.position_ > AFTER_VALUE) {
  //  Free(pi_or_comment_.value_);
  //}

  for (size_t i=0; i < num_text_; ++i) {
    if ((unsigned long)text_[i].keyword
      > (unsigned long)NamespaceSpecification::LOWERCASED) {
      Free(text_[i].uri);
    }
    if (text_[i].prefix > (char*)NamespaceSpecification::ALL) {
      Free(text_[i].prefix);
    }
  }
  Free(text_);
}

void XerAttributes::FreeNamespace(NamespaceSpecification &ns) {
  switch (ns.keyword) {
  case NamespaceSpecification::NO_MANGLING:
  case NamespaceSpecification::CAPITALIZED:
  case NamespaceSpecification::UNCAPITALIZED:
  case NamespaceSpecification::UPPERCASED:
  case NamespaceSpecification::LOWERCASED:
    break; // nothing to do
  default: // real string, must be freed
    Free(ns.uri);
    break;
  }
  ns.uri = 0;
  Free(ns.prefix);
  ns.prefix = 0;
}

void XerAttributes::FreeNameChange(XerAttributes::NameChange& n) {
  switch (n.kw_) {
  case NamespaceSpecification::NO_MANGLING:
  case NamespaceSpecification::CAPITALIZED:
  case NamespaceSpecification::UNCAPITALIZED:
  case NamespaceSpecification::UPPERCASED:
  case NamespaceSpecification::LOWERCASED:
    break; // nothing to do
  default: // real string, must be freed
    Free(n.nn_);
    break;
  }
  n.kw_ = NamespaceSpecification::NO_MANGLING;
}

void XerAttributes::print(const char *type_name) const {
  fprintf(stderr, "XER attributes(%p) for %s:\n", (const void*)this, type_name);
  if (empty()) fputs("...Empty...\n", stderr);
  else {
    fputs(abstract_ ? "ABSTRACT\n" : "", stderr);
    fputs(attribute_ ? "ATTRIBUTE\n" : "", stderr);

    if (has_aa(this)) {
      if (anyAttributes_.type_ == NamespaceRestriction::NOTHING) {
        fputs("ANY-ATTRIBUTES\n", stderr);
      }
      else for (size_t i = 0; i < anyAttributes_.nElements_; ++i) {
        fprintf(stderr, "ANY-ATTRIBUTES %s %s\n",
          anyAttributes_.type_ == NamespaceRestriction::FROM ? "EXCEPT" : "FROM",
            (anyAttributes_.uris_[i] && *anyAttributes_.uris_[i]) ?
              anyAttributes_.uris_[i] : "ABSENT");
      }
    }

    if (has_ae(this)) {
      if (anyElement_.type_ == NamespaceRestriction::NOTHING) {
        fputs("ANY-ELEMENT\n", stderr);
      }
      else for (size_t i = 0; i < anyElement_.nElements_; ++i) {
        fprintf(stderr, "ANY-ELEMENT %s %s\n",
          anyElement_.type_ == NamespaceRestriction::FROM ? "EXCEPT" : "FROM",
            (anyElement_.uris_[i] && *anyElement_.uris_[i]) ?
              anyElement_.uris_[i] : "ABSENT");
      }
    }
    fputs(base64_ ? "BASE64\n" : "", stderr);
    fputs(block_ ? "BLOCK\n" : "", stderr);
    fputs(decimal_ ? "DECIMAL\n" : "", stderr);

    if (defaultForEmpty_)  fprintf(stderr, "DEFAULT-FOR-EMPTY '%s'\n", defaultForEmpty_);

    if (element_) fputs("ELEMENT\n", stderr);
    fputs(embedValues_ ? "EMBED-VALUES\n" : "", stderr);
    fputs((form_ & QUALIFIED) ? "FORM AS QUALIFIED\n" : "", stderr);
    if (has_fractionDigits_) fprintf(stderr, "FRACTIONDIGITS '%i'\n", fractionDigits_);
    fputs(hex_ ? "hexBinary" : "", stderr);
    fputs(list_ ? "LIST\n" : "", stderr);

    static const char * xforms[] = {
      "CAPITALIZED", "UNCAPITALIZED", "UPPERCASED", "LOWERCASED"
    };
    switch (name_.kw_) {
    case NamespaceSpecification::NO_MANGLING: // nothing to do
      break;
    default: // a string
      fprintf(stderr, "NAME AS '%s'\n", name_.nn_);
      break;
    case NamespaceSpecification::CAPITALIZED:
    case NamespaceSpecification::UNCAPITALIZED:
    case NamespaceSpecification::LOWERCASED:
    case NamespaceSpecification::UPPERCASED:
      fprintf(stderr, "NAME AS %s\n",
        xforms[name_.kw_ - NamespaceSpecification::CAPITALIZED]);
      break;
    }

    if (namespace_.uri) {
      fprintf(stderr, "NAMESPACE '%s' %s %s\n", namespace_.uri,
        (namespace_.prefix ? "PREFIX" : ""),
        (namespace_.prefix ? namespace_.prefix : ""));
    }

    //if (pi_or_comment_.position_ != NOWHERE) {
    //  fputs("PI-OR-COMMENT\n", stderr);
    //}
    if (num_text_) {
      fputs("TEXT\n", stderr);
      for (size_t t=0; t < num_text_; ++t) {
        const char* who = 0, *action = 0;
        switch ((unsigned long)(text_[t].uri) ) {
        case NamespaceSpecification::LOWERCASED:
          action = "LOWERCASED"; break;
        case NamespaceSpecification::UPPERCASED:
          action = "UPPERCASED"; break;
        case NamespaceSpecification::CAPITALIZED:
          action = "CAPITALIZED"; break;
        case NamespaceSpecification::UNCAPITALIZED:
          action = "UNCAPITALIZED"; break;
        case 0:
          action = "text"; break;
        default:
          action = text_[t].uri; break;
        }

        switch ((unsigned long)text_[t].prefix) {
        case 0: who = ""; break;
        case NamespaceSpecification::ALL: who = "ALL"; break;
        default: who = text_[t].prefix; break;
        }
        fprintf(stderr, "   %s as %s\n", who, action);
      }
    }
    fputs(untagged_ ? "UNTAGGED\n" : "", stderr);
    fputs(useNil_ ? "USE-NIL\n" : "", stderr);
    fputs(useNumber_ ? "USE-NUMBER\n" : "", stderr);
    fputs(useOrder_ ? "USE-ORDER\n" : "", stderr);
    fputs(useQName_ ? "USE-QNAME\n" : "", stderr);
    fputs(useType_ ? "USE-TYPE\n" : "", stderr);
    fputs(useUnion_ ? "USE-UNION\n" : "", stderr);
    if (whitespace_ != PRESERVE) fprintf(stderr, "WHITESPACE %s\n",
      whitespace_ == COLLAPSE ? "COLLAPSE" : "REPLACE");
    fputs(". . . . .\n", stderr);
  }
}

XerAttributes& XerAttributes::operator |= (const XerAttributes& other)
{
  if (other.empty()) FATAL_ERROR("XerAttributes::operator |=");
/*
fprintf(stderr, "@@@ replacing:\n");
print("orig.");
other.print("other");
*/
  abstract_ |= other.abstract_;
  attribute_ |= other.attribute_;
  if (has_aa(&other)) {
    FreeNamespaceRestriction(anyAttributes_);
    anyAttributes_.nElements_ = other.anyAttributes_.nElements_;
    anyAttributes_.type_      = other.anyAttributes_.type_;
    anyAttributes_.uris_      = (char**)Malloc(anyAttributes_.nElements_
      * sizeof(char*));
    for (size_t i=0; i < anyAttributes_.nElements_; ++i) {
      anyAttributes_.uris_[i] = mcopystr(other.anyAttributes_.uris_[i]);
    }
  }
  if (has_ae(&other)) {
    FreeNamespaceRestriction(anyElement_);
    anyElement_.nElements_ = other.anyElement_.nElements_;
    anyElement_.type_      = other.anyElement_.type_;
    anyElement_.uris_      = (char**)Malloc(anyElement_.nElements_
      * sizeof(char*));
    for (size_t i=0; i < anyElement_.nElements_; ++i) {
      anyElement_.uris_[i] = mcopystr(other.anyElement_.uris_[i]);
    }
  }
  base64_ |= other.base64_;
  block_ |= other.block_;
  decimal_ |= other.decimal_;

  if (other.defaultForEmpty_ != 0) {
    Free(defaultForEmpty_);
    defaultForEmpty_ = mcopystr(other.defaultForEmpty_);
  }

  element_ |= other.element_;
  embedValues_ |= other.embedValues_;
  form_ = other.form_;
  if (other.has_fractionDigits_) {
    has_fractionDigits_ = other.has_fractionDigits_;
    fractionDigits_ = other.fractionDigits_;
  }
  hex_  |= other.hex_;
  list_ |= other.list_;
  if (other.name_.kw_ != NamespaceSpecification::NO_MANGLING) {
    FreeNameChange(name_);
    switch (other.name_.kw_) {
    case NamespaceSpecification::NO_MANGLING:
      break; // not possible inside the if
    case NamespaceSpecification::CAPITALIZED:
    case NamespaceSpecification::UNCAPITALIZED:
    case NamespaceSpecification::UPPERCASED:
    case NamespaceSpecification::LOWERCASED:
      name_.kw_ = other.name_.kw_;
      break;
    default: // a real string
      name_.nn_ = mcopystr(other.name_.nn_);
      break;
    }
  }

  if (other.namespace_.uri != 0) {
    switch (namespace_.keyword) {
    case NamespaceSpecification::NO_MANGLING:
    case NamespaceSpecification::CAPITALIZED:
    case NamespaceSpecification::UNCAPITALIZED:
    case NamespaceSpecification::UPPERCASED:
    case NamespaceSpecification::LOWERCASED:
      break; // nothing to do
    default: // real string, must be freed
      Free(namespace_.uri);
      break;
    }
    switch (other.namespace_.keyword) {
    case NamespaceSpecification::NO_MANGLING:
    case NamespaceSpecification::CAPITALIZED:
    case NamespaceSpecification::UNCAPITALIZED:
    case NamespaceSpecification::UPPERCASED:
    case NamespaceSpecification::LOWERCASED:
      namespace_.uri = other.namespace_.uri;
      break;
    default: // real string
      namespace_.uri = mcopystr(other.namespace_.uri);
      break;
    }
    Free(namespace_.prefix);
    namespace_.prefix = mcopystr(other.namespace_.prefix);
  }
  //pi_or_comment_;

  if (other.num_text_) {
    // Append the other TEXT. No attempt is made to eliminate duplicates.
    // This will be done in Type::chk_xer_text().
    size_t old_num = num_text_;
    num_text_ += other.num_text_;
    text_ = (NamespaceSpecification *)Realloc(
      text_, num_text_ * sizeof(NamespaceSpecification));
    for (size_t t = 0; t < other.num_text_; ++t) {
      switch ((unsigned long)(other.text_[t].uri) ) {
      case NamespaceSpecification::LOWERCASED:
      case NamespaceSpecification::UPPERCASED:
      case NamespaceSpecification::CAPITALIZED:
      case NamespaceSpecification::UNCAPITALIZED:
      case NamespaceSpecification::NO_MANGLING:
        text_[old_num + t].uri = other.text_[t].uri;
        break;
      default:
        text_[old_num + t].uri = mcopystr(other.text_[t].uri);
        break;
      }

      switch ((unsigned long)other.text_[t].prefix) {
      case 0: case NamespaceSpecification::ALL:
        text_[old_num + t].prefix = other.text_[t].prefix;
        break;
      default:
        text_[old_num + t].prefix = mcopystr(other.text_[t].prefix);
        break;
      }
    }
  }
  untagged_ |= other.untagged_;
  useNil_ |= other.useNil_;
  useNumber_ |= other.useNumber_;
  useOrder_ |= other.useOrder_;
  useQName_ |= other.useQName_;
  useType_ |= other.useType_;
  useUnion_ |= other.useUnion_;
  whitespace_ = other.whitespace_;
  return *this;
}

bool XerAttributes::empty() const
{
  return !abstract_
  && !attribute_
  && !has_aa(this)
  && !has_ae(this)
  && !base64_
  && !block_
  && !decimal_
  && defaultForEmpty_ == 0
  && !element_
  && !embedValues_
  && !(form_ & LOCALLY_SET)
  && !has_fractionDigits_
  && !hex_
  && !list_
  && name_.kw_ == NamespaceSpecification::NO_MANGLING
  && namespace_.uri == 0
  && num_text_ == 0
  && !untagged_
  && !useNil_
  && !useNumber_
  && !useOrder_
  && !useQName_
  && !useType_
  && !useUnion_
  && whitespace_ == PRESERVE;
}

<|endoftext|>


<commit_before>/*******************************************************************************
 * Copyright (c) 2015-2016 Vanamco AG, http://www.vanamco.com
 *
 * The MIT License (MIT)
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * Contributors:
 * Matthias Christen, Vanamco AG
 * Florian Müller, Vanamco AG
 *******************************************************************************/

#include <fstream>
#include <sstream>

#include <glob.h>
#include <pwd.h>
#include <libgen.h>

#include <sys/stat.h>
#include <gtk/gtk.h>

#include "base/app.h"
#include "util/string_util.h"
#include "native_extensions/image_util_linux.h"
#include "native_extensions/os_util.h"
#include "native_extensions/file_util.h"
#include "zephyros_strings.h"

bool OpenFileDlg(GtkFileChooserAction action, int titleId, int okId, Zephyros::Path& path)
{
    bool retVal = false;

    GtkWidget* dialog = gtk_file_chooser_dialog_new(
        Zephyros::GetString(titleId).c_str(),
        NULL,
        action,
        Zephyros::GetString(ZS_DIALOG_FILE_CANCEL_BUTTON).c_str(),
        GTK_RESPONSE_CANCEL,
        Zephyros::GetString(okId).c_str(),
        GTK_RESPONSE_ACCEPT,
        NULL
    );

    if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
    {
        char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
        path = Zephyros::Path(filename);
        retVal = true;
        g_free(filename);
    }

    gtk_widget_destroy(dialog);
    return retVal;
}

/**
 * Check if a file is binary base on its mime type as reported by 'file'.
 * Stores the binary flag in result[0], the image flag in result[1],
 * and returns the mime type for further processing.
 */
String CheckForBinaryAndImage(String filename, bool& isBinary, bool& isImage)
{
    isBinary = false;
    isImage = false;

    String strCmd = "file -bi ";
    strCmd.append(filename);

    String guess = Zephyros::OSUtil::Exec(strCmd);
    String mimeType = guess.substr(0, guess.find(";"));

    size_t foundBinaryCharset = guess.find("charset=binary");
    if (foundBinaryCharset == String::npos)
        return mimeType;

    isBinary = true;
    size_t foundImageMimeType = guess.find("image/");
    if(foundImageMimeType == String::npos)
        return mimeType;

    isImage = true;
    return mimeType;
}

/**
 * Get the filename for the preferences file, to use in Load/StorePreferences.
 */
String GetPreferencesFile()
{
    String strFilename(Zephyros::OSUtil::GetConfigDirectory());
	strFilename.append(TEXT("/"));
	strFilename.append("preferences.ini");
    return strFilename;
}

namespace Zephyros {
namespace FileUtil {

bool ShowOpenFileDialog(Path& path)
{
    return OpenFileDlg(GTK_FILE_CHOOSER_ACTION_OPEN, ZS_DIALOG_OPEN_FILE, ZS_DIALOG_FILE_OPEN_BUTTON, path);
}

bool ShowSaveFileDialog(Path& path)
{
    return OpenFileDlg(GTK_FILE_CHOOSER_ACTION_SAVE, ZS_DIALOG_SAVE_FILE, ZS_DIALOG_FILE_SAVE_BUTTON, path);
}

bool ShowOpenDirectoryDialog(Path& path)
{
    return OpenFileDlg(GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, ZS_DIALOG_OPEN_FOLDER, ZS_DIALOG_FILE_OPEN_BUTTON, path);
}

bool ShowOpenFileOrDirectoryDialog(Path& path)
{
    // TODO: not available in GTK? Seems only either file or folder is possible.
	return false;
}

void ShowInFileManager(String path)
{
	String strWhichCmd = TEXT("which xdg-open");
    String strCommand = OSUtil::Exec(strWhichCmd);
    Trim(strCommand);

    if (strCommand.length() > 0)
    {
        strCommand.append(" ");
        strCommand.append(path);
        strCommand.append(" &");
        system(strCommand.c_str());
    }
}

bool ExistsFile(String filename)
{
	struct stat buffer;
	return stat(filename.c_str(), &buffer) == 0;
}

bool IsDirectory(String path)
{
    struct stat buffer;
    stat(path.c_str(), &buffer);
    return S_ISDIR(buffer.st_mode);
}

bool MakeDirectory(String path, bool recursive)
{
	String strWhichCmd = "which mkdir";
    String strCommand = OSUtil::Exec(strWhichCmd);
    Trim(strCommand);
    if (recursive)
        strCommand.append(" -p");
    strCommand.append(" ");
    strCommand.append(path);

    int exitCode = system(strCommand.c_str());
    return exitCode == 0;
}

bool ReadFile(String filename, JavaScript::Object options, String& result)
{
    bool isBinary;
    bool isImage;
    String mimeType = CheckForBinaryAndImage(filename, isBinary, isImage);

    std::ifstream fs;
    fs.open(filename, std::ios::in);
    if (fs.is_open())
    {
        fs.seekg(0, std::ios::end);
        long size = fs.tellg();
        char* contents = new char[size];
        fs.seekg(0, std::ios::beg);
        fs.read(contents, size);

        if (isImage)
        {
            // TODO: convert .ico to .png
            // http://fossies.org/linux/xpaint/util/ico2png/create_icon.c ?
            result = "data:";
            result.append(mimeType);
            result.append(";base64,");
            result.append(ImageUtil::Base64Encode(contents, size));
        }
        else
            result = String(contents);

        delete[] contents;
        fs.close();
        return true;
    }

    return false;
}

bool WriteFile(String filename, String contents)
{
    std::ofstream file;
    file.open(filename, std::ios::out | std::ios::binary);

    if (!file.is_open())
        return false;

    file << contents;
    file.close();

    return true;
}

bool MoveFile(String oldFilename, String newFilename)
{
    return rename(oldFilename.c_str(), newFilename.c_str()) != 0;
}

bool DeleteFiles(String filenames)
{
    glob_t glob_result;

    glob(filenames.c_str(), GLOB_TILDE, NULL, &glob_result);

    // no match
    if (glob_result.gl_pathc == 0)
        return false;

    for (unsigned int i = 0; i < glob_result.gl_pathc; i++)
        if (unlink(glob_result.gl_pathv[i]) != 0)
            return false;

    // there was a match, and all matching files were deleted successfully
    return true;
}

void LoadPreferences(String key, String& data)
{
    std::ifstream fs(GetPreferencesFile());
    if (!fs.is_open())
        return;

    String line;
    while (getline(fs, line))
    {
        size_t idx = line.find(key);
        if (idx == 0)
        {
            data = line.substr(key.size() + 1);
            break;
        }
    }
}

void StorePreferences(String key, String data)
{
    String prefFile = GetPreferencesFile();
    std::ifstream fsIn(prefFile);

    StringStream newContents;
    bool alreadyFound = false;

    if (fsIn.is_open())
    {
        String line;
        while (getline(fsIn, line))
        {
            size_t idx = line.find(key + "=");
            if (idx == 0)
            {
                alreadyFound = true;
                newContents << key << "=" << data << std::endl;
            }
            else
                newContents << line << std::endl;
        }

        fsIn.close();
        if (!alreadyFound)
            newContents << key << "=" << data << std::endl;
    }
    else
        newContents << key << "=" << data << std::endl;

    WriteFile(prefFile, newContents.str());
}

bool StartAccessingPath(Path& path)
{
	// not supported on Linux
	return true;
}

void StopAccessingPath(Path& path)
{
	// not supported on Linux
}

void GetTempDir(Path& path)
{
    path = Path(P_tmpdir);
}

String GetApplicationPath()
{
    char path[PATH_MAX];
    if (readlink("/proc/self/exe", path, PATH_MAX) != -1)
    {
        dirname(path);
        strcat(path, "/");
        return String(path);
    }

    return "";
}

void GetApplicationResourcesPath(Path& path)
{
	path = Path(FileUtil::GetApplicationPath() + TEXT("/res"));
}

} // namespace FileUtil
} // namespace Zephyros
<commit_msg>readDirectory (linux); refactored makeDirectory (don't start external process)<commit_after>/*******************************************************************************
 * Copyright (c) 2015-2016 Vanamco AG, http://www.vanamco.com
 *
 * The MIT License (MIT)
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * Contributors:
 * Matthias Christen, Vanamco AG
 * Florian Müller, Vanamco AG
 *******************************************************************************/

#include <fstream>
#include <sstream>

#include <glob.h>
#include <pwd.h>
#include <libgen.h>

#include <sys/stat.h>
#include <gtk/gtk.h>

#include "base/app.h"
#include "util/string_util.h"
#include "native_extensions/image_util_linux.h"
#include "native_extensions/os_util.h"
#include "native_extensions/file_util.h"
#include "zephyros_strings.h"

bool OpenFileDlg(GtkFileChooserAction action, int titleId, int okId, Zephyros::Path& path)
{
    bool retVal = false;

    GtkWidget* dialog = gtk_file_chooser_dialog_new(
        Zephyros::GetString(titleId).c_str(),
        NULL,
        action,
        Zephyros::GetString(ZS_DIALOG_FILE_CANCEL_BUTTON).c_str(),
        GTK_RESPONSE_CANCEL,
        Zephyros::GetString(okId).c_str(),
        GTK_RESPONSE_ACCEPT,
        NULL
    );

    if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
    {
        char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
        path = Zephyros::Path(filename);
        retVal = true;
        g_free(filename);
    }

    gtk_widget_destroy(dialog);
    return retVal;
}

/**
 * Check if a file is binary base on its mime type as reported by 'file'.
 * Stores the binary flag in result[0], the image flag in result[1],
 * and returns the mime type for further processing.
 */
String CheckForBinaryAndImage(String filename, bool& isBinary, bool& isImage)
{
    isBinary = false;
    isImage = false;

    String strCmd = "file -bi ";
    strCmd.append(filename);

    String guess = Zephyros::OSUtil::Exec(strCmd);
    String mimeType = guess.substr(0, guess.find(";"));

    size_t foundBinaryCharset = guess.find("charset=binary");
    if (foundBinaryCharset == String::npos)
        return mimeType;

    isBinary = true;
    size_t foundImageMimeType = guess.find("image/");
    if(foundImageMimeType == String::npos)
        return mimeType;

    isImage = true;
    return mimeType;
}

/**
 * Get the filename for the preferences file, to use in Load/StorePreferences.
 */
String GetPreferencesFile()
{
    String strFilename(Zephyros::OSUtil::GetConfigDirectory());
	strFilename.append(TEXT("/"));
	strFilename.append("preferences.ini");
    return strFilename;
}

namespace Zephyros {
namespace FileUtil {

bool ShowOpenFileDialog(Path& path)
{
    return OpenFileDlg(GTK_FILE_CHOOSER_ACTION_OPEN, ZS_DIALOG_OPEN_FILE, ZS_DIALOG_FILE_OPEN_BUTTON, path);
}

bool ShowSaveFileDialog(Path& path)
{
    return OpenFileDlg(GTK_FILE_CHOOSER_ACTION_SAVE, ZS_DIALOG_SAVE_FILE, ZS_DIALOG_FILE_SAVE_BUTTON, path);
}

bool ShowOpenDirectoryDialog(Path& path)
{
    return OpenFileDlg(GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, ZS_DIALOG_OPEN_FOLDER, ZS_DIALOG_FILE_OPEN_BUTTON, path);
}

bool ShowOpenFileOrDirectoryDialog(Path& path)
{
    // TODO: not available in GTK? Seems only either file or folder is possible.
	return false;
}

void ShowInFileManager(String path)
{
	String strWhichCmd = TEXT("which xdg-open");
    String strCommand = OSUtil::Exec(strWhichCmd);
    Trim(strCommand);

    if (strCommand.length() > 0)
    {
        strCommand.append(" ");
        strCommand.append(path);
        strCommand.append(" &");
        system(strCommand.c_str());
    }
}

bool ExistsFile(String filename)
{
	struct stat buffer;
	return stat(filename.c_str(), &buffer) == 0;
}

bool IsDirectory(String path)
{
    struct stat buffer;
    stat(path.c_str(), &buffer);
    return S_ISDIR(buffer.st_mode);
}

// cf. http://stackoverflow.com/questions/675039/how-can-i-create-directory-tree-in-c-linux
int MakeDirectoryInternal(const char* path, mode_t mode)
{
    struct stat st;
    int status = 0;

    if (stat(path, &st) != 0)
    {
        // directory does not exist. EEXIST for race condition
        if (mkdir(path, mode) != 0 && errno != EEXIST)
            status = -1;
    }
    else if (!S_ISDIR(st.st_mode))
    {
        errno = ENOTDIR;
        status = -1;
    }

    return status;
}

bool MakeDirectory(String path, bool recursive)
{
    int status = 0;
    char* pathTmp = strdup(path.c_str());
    char* pp = pathTmp;
    char* sp;

    while (status == 0 && (sp = strchr(pp, '/')) != 0)
    {
        if (sp != pp)
        {
            // neither root nor double slash in path
            *sp = '\0';
            status = MakeDirectoryInternal(pathTmp, 0777);
            *sp = '/';
        }

        pp = sp + 1;
    }

    if (status == 0)
        status = MakeDirectoryInternal(path.c_str(), 0777);

    free(pathTmp);

    return status == 0;
}

bool ReadDirectory(String path, std::vector<String>& files)
{
    if (path.find_first_of(TEXT("*?")) == String::npos)
    {
        if (path.back() == TEXT('/'))
            path.append(TEXT("*"));
        else
            path.append(TEXT("/*"));
    }

    glob_t glob_result;
    glob(path.c_str(), GLOB_TILDE, NULL, &glob_result);

    // no match
    if (glob_result.gl_pathc == 0)
        return true;

    for (unsigned int i = 0; i < glob_result.gl_pathc; i++)
        files.push_back(String(glob_result.gl_pathv[i]));

    return true;
}

bool ReadFile(String filename, JavaScript::Object options, String& result)
{
    bool isBinary;
    bool isImage;
    String mimeType = CheckForBinaryAndImage(filename, isBinary, isImage);

    std::ifstream fs;
    fs.open(filename, std::ios::in);
    if (fs.is_open())
    {
        fs.seekg(0, std::ios::end);
        long size = fs.tellg();
        char* contents = new char[size];
        fs.seekg(0, std::ios::beg);
        fs.read(contents, size);

        if (isImage)
        {
            // TODO: convert .ico to .png
            // http://fossies.org/linux/xpaint/util/ico2png/create_icon.c ?
            result = "data:";
            result.append(mimeType);
            result.append(";base64,");
            result.append(ImageUtil::Base64Encode(contents, size));
        }
        else
            result = String(contents);

        delete[] contents;
        fs.close();
        return true;
    }

    return false;
}

bool WriteFile(String filename, String contents)
{
    std::ofstream file;
    file.open(filename, std::ios::out | std::ios::binary);

    if (!file.is_open())
        return false;

    file << contents;
    file.close();

    return true;
}

bool MoveFile(String oldFilename, String newFilename)
{
    return rename(oldFilename.c_str(), newFilename.c_str()) != 0;
}

bool DeleteFiles(String filenames)
{
    glob_t glob_result;

    glob(filenames.c_str(), GLOB_TILDE, NULL, &glob_result);

    // no match
    if (glob_result.gl_pathc == 0)
        return false;

    for (unsigned int i = 0; i < glob_result.gl_pathc; i++)
        if (unlink(glob_result.gl_pathv[i]) != 0)
            return false;

    // there was a match, and all matching files were deleted successfully
    return true;
}

void LoadPreferences(String key, String& data)
{
    std::ifstream fs(GetPreferencesFile());
    if (!fs.is_open())
        return;

    String line;
    while (getline(fs, line))
    {
        size_t idx = line.find(key);
        if (idx == 0)
        {
            data = line.substr(key.size() + 1);
            break;
        }
    }
}

void StorePreferences(String key, String data)
{
    String prefFile = GetPreferencesFile();
    std::ifstream fsIn(prefFile);

    StringStream newContents;
    bool alreadyFound = false;

    if (fsIn.is_open())
    {
        String line;
        while (getline(fsIn, line))
        {
            size_t idx = line.find(key + "=");
            if (idx == 0)
            {
                alreadyFound = true;
                newContents << key << "=" << data << std::endl;
            }
            else
                newContents << line << std::endl;
        }

        fsIn.close();
        if (!alreadyFound)
            newContents << key << "=" << data << std::endl;
    }
    else
        newContents << key << "=" << data << std::endl;

    WriteFile(prefFile, newContents.str());
}

bool StartAccessingPath(Path& path)
{
	// not supported on Linux
	return true;
}

void StopAccessingPath(Path& path)
{
	// not supported on Linux
}

void GetTempDir(Path& path)
{
    path = Path(P_tmpdir);
}

String GetApplicationPath()
{
    char path[PATH_MAX];
    if (readlink("/proc/self/exe", path, PATH_MAX) != -1)
    {
        dirname(path);
        strcat(path, "/");
        return String(path);
    }

    return "";
}

void GetApplicationResourcesPath(Path& path)
{
	path = Path(FileUtil::GetApplicationPath() + TEXT("/res"));
}

} // namespace FileUtil
} // namespace Zephyros
<|endoftext|>


<commit_before>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/xla/service/mlir_gpu/kernel_lowering.h"

#include "absl/memory/memory.h"
#include "mlir/Conversion/AffineToStandard/AffineToStandard.h"  // from @llvm-project
#include "mlir/Conversion/GPUToNVVM/GPUToNVVMPass.h"  // from @llvm-project
#include "mlir/Conversion/GPUToROCDL/GPUToROCDLPass.h"  // from @llvm-project
#include "mlir/Conversion/LinalgToLLVM/LinalgToLLVM.h"  // from @llvm-project
#include "mlir/Conversion/SCFToGPU/SCFToGPUPass.h"  // from @llvm-project
#include "mlir/Conversion/SCFToStandard/SCFToStandard.h"  // from @llvm-project
#include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"  // from @llvm-project
#include "mlir/Dialect/GPU/GPUDialect.h"  // from @llvm-project
#include "mlir/Dialect/GPU/Passes.h"  // from @llvm-project
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"  // from @llvm-project
#include "mlir/Dialect/LLVMIR/NVVMDialect.h"  // from @llvm-project
#include "mlir/Dialect/LLVMIR/ROCDLDialect.h"  // from @llvm-project
#include "mlir/Dialect/Linalg/Passes.h"  // from @llvm-project
#include "mlir/Dialect/SCF/Passes.h"  // from @llvm-project
#include "mlir/Dialect/SCF/Transforms.h"  // from @llvm-project
#include "mlir/IR/Dialect.h"  // from @llvm-project
#include "mlir/Pass/Pass.h"  // from @llvm-project
#include "mlir/Pass/PassManager.h"  // from @llvm-project
#include "mlir/Transforms/Bufferize.h"  // from @llvm-project
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"  // from @llvm-project
#include "mlir/Transforms/Passes.h"  // from @llvm-project
#include "tensorflow/compiler/mlir/hlo/include/mlir-hlo/Dialect/mhlo/IR/lhlo_ops.h"
#include "tensorflow/compiler/mlir/hlo/include/mlir-hlo/Dialect/mhlo/transforms/passes.h"
#include "tensorflow/compiler/mlir/hlo/include/mlir-hlo/Dialect/mhlo/transforms/rewriters.h"
#include "tensorflow/compiler/mlir/tensorflow/utils/dump_mlir_util.h"
#include "tensorflow/compiler/xla/service/mlir_gpu/passes.h"
#include "tensorflow/compiler/xla/util.h"

namespace xla {
namespace mlir_gpu {

Status LowerLHLOToGPU(mlir::ModuleOp module, LowerLHLOToGPUOptions options) {
  mlir::PassManager pm(module.getContext());
  tensorflow::applyTensorflowAndCLOptions(pm);

  // We have to anticipate later unrolling in tiling to make sure that we get
  // the requested tiling after unrolling. Compute the new tiling here if
  // needed.
  llvm::SmallVector<unsigned, 4> tiling_for_unrolling;
  llvm::SmallVector<int64_t, 4> as_int64;
  if (!options.unroll_factors.empty()) {
    tiling_for_unrolling.reserve(options.tile_sizes.size());
    for (auto pair : llvm::zip(options.tile_sizes, options.unroll_factors)) {
      tiling_for_unrolling.push_back(std::get<0>(pair) * std::get<1>(pair));
      as_int64.push_back(std::get<1>(pair));
    }
  } else {
    tiling_for_unrolling.append(options.tile_sizes.begin(),
                                options.tile_sizes.end());
  }

  // Legalize from HLO to LHLO.
  pm.addPass(::mlir::mhlo::createLegalizeToLhloPass());
  // Moving `AllocOp`s and inserting missing `DeallocOp`s
  pm.addNestedPass<mlir::FuncOp>(::mlir::createBufferHoistingPass());
  pm.addNestedPass<mlir::FuncOp>(::mlir::createBufferDeallocationPass());
  // Next, we can strip the outer fusion operation.
  pm.addNestedPass<mlir::FuncOp>(createFusionOpRemoverPass());
  // Remove unnecessary LHLO copies.
  pm.addNestedPass<mlir::FuncOp>(::mlir::createCopyRemovalPass());
  // Legalize reduce operations directly to GPU dialect.
  pm.addNestedPass<mlir::FuncOp>(::mlir::lmhlo::createLegalizeToGpuPass());
  // Transform LHLO operations to LinAlg.
  pm.addNestedPass<mlir::FuncOp>(
      ::mlir::lmhlo::createLegalizeLhloToLinalgPass());
  // Fuse linalg operations.
  pm.addNestedPass<mlir::FuncOp>(::mlir::lmhlo::createLhloFuseLinalgPass(
      /*use_parallel_loops=*/true, tiling_for_unrolling));
  // Transform the Linalg operations inside of the loop nest into parallel
  // loops.
  pm.addNestedPass<mlir::FuncOp>(
      ::mlir::createConvertLinalgToParallelLoopsPass());
  // Canonicalize the code to simplify index computations. This is needed so
  // that loop bounds have the same value.
  pm.addNestedPass<::mlir::FuncOp>(::mlir::createCanonicalizerPass());
  pm.addNestedPass<::mlir::FuncOp>(::mlir::createCSEPass());
  // Fuse the inner-most loops.
  pm.addNestedPass<mlir::FuncOp>(createFuseInnerParallelLoopsPass());
  // Run CSE to ensure that loads and stores to the same subview get
  // recognized as such.
  pm.addNestedPass<::mlir::FuncOp>(::mlir::createCSEPass());
  // Forward stores to buffers to loads.
  pm.addNestedPass<mlir::FuncOp>(createStoreForwardingPass());
  // Remove now unused temporary buffers.
  pm.addNestedPass<mlir::FuncOp>(createDeadTempBufferRemovalPass());
  if (!options.unroll_factors.empty()) {
    pm.addNestedPass<mlir::FuncOp>(
        ::mlir::createParallelLoopTilingPass(as_int64));
  }
  // Project all loop dimensions to X if necessary.
  if (options.collapse_parallel_loops) {
    pm.addNestedPass<mlir::FuncOp>(
        createParallelLoopCollapsingToFirstDimPass());
  }
  // Some basic cleanup.
  pm.addNestedPass<::mlir::FuncOp>(::mlir::createCanonicalizerPass());
  pm.addNestedPass<::mlir::FuncOp>(::mlir::createCSEPass());
  // Greedily map the remaining loop to GPU hardware dimensions.
  pm.addNestedPass<::mlir::FuncOp>(createMapParallelLoopsPass());
  // Apply the mapping.
  pm.addNestedPass<::mlir::FuncOp>(mlir::createParallelLoopToGpuPass());
  // Some basic cleanup.
  pm.addNestedPass<::mlir::FuncOp>(::mlir::createCanonicalizerPass());
  pm.addNestedPass<::mlir::FuncOp>(::mlir::createCSEPass());
  // Make loops with min bounds into a conditional plus static bounds.
  // Only do this if we unrolled in the first place.
  if (!options.unroll_factors.empty()) {
    pm.addNestedPass<::mlir::FuncOp>(mlir::createForLoopSpecializationPass());
  }
  // Approximate of requested.
  if (options.use_approximations) {
    pm.addNestedPass<::mlir::FuncOp>(
        ::mlir::mhlo::createLegalizeTrigonometricToApproximationPass());
  }
  // Take launches to launches with kernels.
  pm.addPass(::mlir::createGpuKernelOutliningPass());
  // Make sure the kernel signature resembled the original function's
  // signature
  if (options.rewrite_signature) {
    pm.addNestedPass<::mlir::FuncOp>(createRewriteKernelSignaturePass());
  }
  if (failed(pm.run(module))) {
    return InternalError("Lowering to GPU kernels failed.");
  }
  return Status::OK();
}

namespace {

/// A pass that does the final lowering to NVVM. It collects all the patterns
/// that are currently required, currently mixing std, linalg and gpu.
class LowerToNVVMPass
    : public ::mlir::PassWrapper<
          LowerToNVVMPass, ::mlir::OperationPass<::mlir::gpu::GPUModuleOp>> {
  void getDependentDialects(mlir::DialectRegistry& registry) const override {
    registry.insert<mlir::NVVM::NVVMDialect, mlir::LLVM::LLVMDialect>();
  }

 public:
  void runOnOperation() override {
    ::mlir::gpu::GPUModuleOp m = getOperation();

    ::mlir::OwningRewritePatternList patterns;
    ::mlir::LLVMTypeConverter converter(m.getContext());
    ::mlir::populateStdToLLVMConversionPatterns(converter, patterns);
    // TODO(b/145824979) Remove linalg once sliceop is in std.
    ::mlir::populateLinalgToLLVMConversionPatterns(converter, patterns);
    ::mlir::populateGpuToNVVMConversionPatterns(converter, patterns);
    ::mlir::populateAffineToStdConversionPatterns(patterns, m.getContext());
    ::mlir::ConversionTarget target(getContext());
    ::mlir::configureGpuToNVVMConversionLegality(target);
    if (failed(mlir::applyFullConversion(m, target, std::move(patterns)))) {
      signalPassFailure();
    }
  }
};

}  // namespace

Status LowerKernelBodiesToNVVM(mlir::ModuleOp module) {
  ::mlir::PassManager pm(module.getContext());
  // We cannot verify as the signature of the kernel is rewritten.
  pm.enableVerifier(false);
  tensorflow::applyTensorflowAndCLOptions(pm);

  // Rewrite kernel functions to LLVM IR.
  auto& kernelPm = pm.nest<::mlir::gpu::GPUModuleOp>();
  kernelPm.addPass(::mlir::createLowerToCFGPass());
  kernelPm.addPass(absl::make_unique<LowerToNVVMPass>());
  // Some basic cleanup.
  kernelPm.addNestedPass<::mlir::FuncOp>(::mlir::createCanonicalizerPass());
  kernelPm.addNestedPass<::mlir::FuncOp>(::mlir::createCSEPass());
  // Remove all location information to prevent a debug build.
  pm.addPass(::mlir::createStripDebugInfoPass());

  if (failed(pm.run(module))) {
    return InternalError("Lowering to NVVM IR failed.");
  }
  return Status::OK();
}

namespace {

/// A pass that does the final lowering to ROCDL. It collects all the patterns
/// that are currently required, currently mixing std, linalg and gpu.
class LowerToROCDLPass
    : public ::mlir::PassWrapper<
          LowerToROCDLPass, ::mlir::OperationPass<::mlir::gpu::GPUModuleOp>> {
  void getDependentDialects(mlir::DialectRegistry& registry) const override {
    registry.insert<mlir::ROCDL::ROCDLDialect, mlir::LLVM::LLVMDialect>();
  }

 public:
  void runOnOperation() override {
    ::mlir::gpu::GPUModuleOp m = getOperation();

    {
      ::mlir::OwningRewritePatternList patterns;
      ::mlir::populateGpuRewritePatterns(m.getContext(), patterns);
      ::mlir::applyPatternsAndFoldGreedily(m, std::move(patterns));
    }

    ::mlir::OwningRewritePatternList patterns;
    ::mlir::LLVMTypeConverter converter(m.getContext());
    ::mlir::populateStdToLLVMConversionPatterns(converter, patterns);
    // TODO(b/145824979) Remove linalg once sliceop is in std.
    ::mlir::populateLinalgToLLVMConversionPatterns(converter, patterns);
    ::mlir::populateGpuToROCDLConversionPatterns(converter, patterns);
    ::mlir::populateAffineToStdConversionPatterns(patterns, m.getContext());

    ::mlir::ConversionTarget target(getContext());
    target.addIllegalDialect<::mlir::gpu::GPUDialect>();
    target.addIllegalOp<mlir::LLVM::CosOp, mlir::LLVM::ExpOp,
                        mlir::LLVM::FAbsOp, mlir::LLVM::FCeilOp,
                        mlir::LLVM::LogOp, mlir::LLVM::Log10Op,
                        mlir::LLVM::Log2Op, mlir::LLVM::SinOp>();
    target.addIllegalOp<mlir::FuncOp>();
    target.addLegalDialect<::mlir::LLVM::LLVMDialect>();
    target.addLegalDialect<::mlir::ROCDL::ROCDLDialect>();
    // TODO(csigg): Remove once we support replacing non-root ops.
    target.addLegalOp<::mlir::gpu::GPUModuleOp, ::mlir::gpu::ModuleEndOp,
                      ::mlir::gpu::YieldOp>();
    if (failed(mlir::applyFullConversion(m, target, std::move(patterns)))) {
      signalPassFailure();
    }
  }
};

}  // namespace

Status LowerKernelBodiesToROCDL(mlir::ModuleOp module) {
  ::mlir::PassManager pm(module.getContext());
  // We cannot verify as the signature of the kernel is rewritten.
  pm.enableVerifier(false);
  tensorflow::applyTensorflowAndCLOptions(pm);

  auto enable_if_vlog_is_on = [](mlir::Pass*, mlir::Operation*) {
    return VLOG_IS_ON(1);
  };
  pm.enableIRPrinting(/*shouldPrintBeforePass=*/{},
                      /*shouldPrintAfterPass=*/enable_if_vlog_is_on,
                      /*printModuleScope=*/false,
                      /*printAfterOnlyOnChange=*/false,
                      /*out=*/llvm::dbgs());

  // Rewrite kernel functions to LLVM IR.
  auto& kernelPm = pm.nest<::mlir::gpu::GPUModuleOp>();
  kernelPm.addPass(::mlir::createLowerToCFGPass());
  kernelPm.addPass(absl::make_unique<LowerToROCDLPass>());

  // Some basic cleanup.
  kernelPm.addNestedPass<::mlir::FuncOp>(::mlir::createCanonicalizerPass());
  kernelPm.addNestedPass<::mlir::FuncOp>(::mlir::createCSEPass());
  // Remove all location information to prevent a debug build.
  kernelPm.addPass(::mlir::createStripDebugInfoPass());

  if (failed(pm.run(module))) {
    return InternalError("Lowering to ROCDL IR failed.");
  }
  return Status::OK();
}

StatusOr<mlir::ModuleOp> ExtractKernelModule(mlir::ModuleOp module) {
  auto kernelModule = ::mlir::ModuleOp::create(module.getLoc());
  // TODO(b/137624192): This also needs to resolve naming conflicts.
  module.walk([&kernelModule](mlir::gpu::GPUModuleOp nestedModule) {
    for (auto& fn : nestedModule.body().front()) {
      kernelModule.push_back(fn.clone());
    }
  });
  return kernelModule;
}

}  // namespace mlir_gpu
}  // namespace xla
<commit_msg>Use MLIR target configuration for lowering to ROCDL.<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/xla/service/mlir_gpu/kernel_lowering.h"

#include "absl/memory/memory.h"
#include "mlir/Conversion/AffineToStandard/AffineToStandard.h"  // from @llvm-project
#include "mlir/Conversion/GPUToNVVM/GPUToNVVMPass.h"  // from @llvm-project
#include "mlir/Conversion/GPUToROCDL/GPUToROCDLPass.h"  // from @llvm-project
#include "mlir/Conversion/LinalgToLLVM/LinalgToLLVM.h"  // from @llvm-project
#include "mlir/Conversion/SCFToGPU/SCFToGPUPass.h"  // from @llvm-project
#include "mlir/Conversion/SCFToStandard/SCFToStandard.h"  // from @llvm-project
#include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"  // from @llvm-project
#include "mlir/Dialect/GPU/GPUDialect.h"  // from @llvm-project
#include "mlir/Dialect/GPU/Passes.h"  // from @llvm-project
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"  // from @llvm-project
#include "mlir/Dialect/LLVMIR/NVVMDialect.h"  // from @llvm-project
#include "mlir/Dialect/LLVMIR/ROCDLDialect.h"  // from @llvm-project
#include "mlir/Dialect/Linalg/Passes.h"  // from @llvm-project
#include "mlir/Dialect/SCF/Passes.h"  // from @llvm-project
#include "mlir/Dialect/SCF/Transforms.h"  // from @llvm-project
#include "mlir/IR/Dialect.h"  // from @llvm-project
#include "mlir/Pass/Pass.h"  // from @llvm-project
#include "mlir/Pass/PassManager.h"  // from @llvm-project
#include "mlir/Transforms/Bufferize.h"  // from @llvm-project
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"  // from @llvm-project
#include "mlir/Transforms/Passes.h"  // from @llvm-project
#include "tensorflow/compiler/mlir/hlo/include/mlir-hlo/Dialect/mhlo/IR/lhlo_ops.h"
#include "tensorflow/compiler/mlir/hlo/include/mlir-hlo/Dialect/mhlo/transforms/passes.h"
#include "tensorflow/compiler/mlir/hlo/include/mlir-hlo/Dialect/mhlo/transforms/rewriters.h"
#include "tensorflow/compiler/mlir/tensorflow/utils/dump_mlir_util.h"
#include "tensorflow/compiler/xla/service/mlir_gpu/passes.h"
#include "tensorflow/compiler/xla/util.h"

namespace xla {
namespace mlir_gpu {

Status LowerLHLOToGPU(mlir::ModuleOp module, LowerLHLOToGPUOptions options) {
  mlir::PassManager pm(module.getContext());
  tensorflow::applyTensorflowAndCLOptions(pm);

  // We have to anticipate later unrolling in tiling to make sure that we get
  // the requested tiling after unrolling. Compute the new tiling here if
  // needed.
  llvm::SmallVector<unsigned, 4> tiling_for_unrolling;
  llvm::SmallVector<int64_t, 4> as_int64;
  if (!options.unroll_factors.empty()) {
    tiling_for_unrolling.reserve(options.tile_sizes.size());
    for (auto pair : llvm::zip(options.tile_sizes, options.unroll_factors)) {
      tiling_for_unrolling.push_back(std::get<0>(pair) * std::get<1>(pair));
      as_int64.push_back(std::get<1>(pair));
    }
  } else {
    tiling_for_unrolling.append(options.tile_sizes.begin(),
                                options.tile_sizes.end());
  }

  // Legalize from HLO to LHLO.
  pm.addPass(::mlir::mhlo::createLegalizeToLhloPass());
  // Moving `AllocOp`s and inserting missing `DeallocOp`s
  pm.addNestedPass<mlir::FuncOp>(::mlir::createBufferHoistingPass());
  pm.addNestedPass<mlir::FuncOp>(::mlir::createBufferDeallocationPass());
  // Next, we can strip the outer fusion operation.
  pm.addNestedPass<mlir::FuncOp>(createFusionOpRemoverPass());
  // Remove unnecessary LHLO copies.
  pm.addNestedPass<mlir::FuncOp>(::mlir::createCopyRemovalPass());
  // Legalize reduce operations directly to GPU dialect.
  pm.addNestedPass<mlir::FuncOp>(::mlir::lmhlo::createLegalizeToGpuPass());
  // Transform LHLO operations to LinAlg.
  pm.addNestedPass<mlir::FuncOp>(
      ::mlir::lmhlo::createLegalizeLhloToLinalgPass());
  // Fuse linalg operations.
  pm.addNestedPass<mlir::FuncOp>(::mlir::lmhlo::createLhloFuseLinalgPass(
      /*use_parallel_loops=*/true, tiling_for_unrolling));
  // Transform the Linalg operations inside of the loop nest into parallel
  // loops.
  pm.addNestedPass<mlir::FuncOp>(
      ::mlir::createConvertLinalgToParallelLoopsPass());
  // Canonicalize the code to simplify index computations. This is needed so
  // that loop bounds have the same value.
  pm.addNestedPass<::mlir::FuncOp>(::mlir::createCanonicalizerPass());
  pm.addNestedPass<::mlir::FuncOp>(::mlir::createCSEPass());
  // Fuse the inner-most loops.
  pm.addNestedPass<mlir::FuncOp>(createFuseInnerParallelLoopsPass());
  // Run CSE to ensure that loads and stores to the same subview get
  // recognized as such.
  pm.addNestedPass<::mlir::FuncOp>(::mlir::createCSEPass());
  // Forward stores to buffers to loads.
  pm.addNestedPass<mlir::FuncOp>(createStoreForwardingPass());
  // Remove now unused temporary buffers.
  pm.addNestedPass<mlir::FuncOp>(createDeadTempBufferRemovalPass());
  if (!options.unroll_factors.empty()) {
    pm.addNestedPass<mlir::FuncOp>(
        ::mlir::createParallelLoopTilingPass(as_int64));
  }
  // Project all loop dimensions to X if necessary.
  if (options.collapse_parallel_loops) {
    pm.addNestedPass<mlir::FuncOp>(
        createParallelLoopCollapsingToFirstDimPass());
  }
  // Some basic cleanup.
  pm.addNestedPass<::mlir::FuncOp>(::mlir::createCanonicalizerPass());
  pm.addNestedPass<::mlir::FuncOp>(::mlir::createCSEPass());
  // Greedily map the remaining loop to GPU hardware dimensions.
  pm.addNestedPass<::mlir::FuncOp>(createMapParallelLoopsPass());
  // Apply the mapping.
  pm.addNestedPass<::mlir::FuncOp>(mlir::createParallelLoopToGpuPass());
  // Some basic cleanup.
  pm.addNestedPass<::mlir::FuncOp>(::mlir::createCanonicalizerPass());
  pm.addNestedPass<::mlir::FuncOp>(::mlir::createCSEPass());
  // Make loops with min bounds into a conditional plus static bounds.
  // Only do this if we unrolled in the first place.
  if (!options.unroll_factors.empty()) {
    pm.addNestedPass<::mlir::FuncOp>(mlir::createForLoopSpecializationPass());
  }
  // Approximate of requested.
  if (options.use_approximations) {
    pm.addNestedPass<::mlir::FuncOp>(
        ::mlir::mhlo::createLegalizeTrigonometricToApproximationPass());
  }
  // Take launches to launches with kernels.
  pm.addPass(::mlir::createGpuKernelOutliningPass());
  // Make sure the kernel signature resembled the original function's
  // signature
  if (options.rewrite_signature) {
    pm.addNestedPass<::mlir::FuncOp>(createRewriteKernelSignaturePass());
  }
  if (failed(pm.run(module))) {
    return InternalError("Lowering to GPU kernels failed.");
  }
  return Status::OK();
}

namespace {

/// A pass that does the final lowering to NVVM. It collects all the patterns
/// that are currently required, currently mixing std, linalg and gpu.
class LowerToNVVMPass
    : public ::mlir::PassWrapper<
          LowerToNVVMPass, ::mlir::OperationPass<::mlir::gpu::GPUModuleOp>> {
  void getDependentDialects(mlir::DialectRegistry& registry) const override {
    registry.insert<mlir::NVVM::NVVMDialect, mlir::LLVM::LLVMDialect>();
  }

 public:
  void runOnOperation() override {
    ::mlir::gpu::GPUModuleOp m = getOperation();

    ::mlir::OwningRewritePatternList patterns;
    ::mlir::LLVMTypeConverter converter(m.getContext());
    ::mlir::populateStdToLLVMConversionPatterns(converter, patterns);
    // TODO(b/145824979) Remove linalg once sliceop is in std.
    ::mlir::populateLinalgToLLVMConversionPatterns(converter, patterns);
    ::mlir::populateGpuToNVVMConversionPatterns(converter, patterns);
    ::mlir::populateAffineToStdConversionPatterns(patterns, m.getContext());
    ::mlir::ConversionTarget target(getContext());
    ::mlir::configureGpuToNVVMConversionLegality(target);
    if (failed(mlir::applyFullConversion(m, target, std::move(patterns)))) {
      signalPassFailure();
    }
  }
};

}  // namespace

Status LowerKernelBodiesToNVVM(mlir::ModuleOp module) {
  ::mlir::PassManager pm(module.getContext());
  // We cannot verify as the signature of the kernel is rewritten.
  pm.enableVerifier(false);
  tensorflow::applyTensorflowAndCLOptions(pm);

  // Rewrite kernel functions to LLVM IR.
  auto& kernelPm = pm.nest<::mlir::gpu::GPUModuleOp>();
  kernelPm.addPass(::mlir::createLowerToCFGPass());
  kernelPm.addPass(absl::make_unique<LowerToNVVMPass>());
  // Some basic cleanup.
  kernelPm.addNestedPass<::mlir::FuncOp>(::mlir::createCanonicalizerPass());
  kernelPm.addNestedPass<::mlir::FuncOp>(::mlir::createCSEPass());
  // Remove all location information to prevent a debug build.
  pm.addPass(::mlir::createStripDebugInfoPass());

  if (failed(pm.run(module))) {
    return InternalError("Lowering to NVVM IR failed.");
  }
  return Status::OK();
}

namespace {

/// A pass that does the final lowering to ROCDL. It collects all the patterns
/// that are currently required, currently mixing std, linalg and gpu.
class LowerToROCDLPass
    : public ::mlir::PassWrapper<
          LowerToROCDLPass, ::mlir::OperationPass<::mlir::gpu::GPUModuleOp>> {
  void getDependentDialects(mlir::DialectRegistry& registry) const override {
    registry.insert<mlir::ROCDL::ROCDLDialect, mlir::LLVM::LLVMDialect>();
  }

 public:
  void runOnOperation() override {
    ::mlir::gpu::GPUModuleOp m = getOperation();

    {
      ::mlir::OwningRewritePatternList patterns;
      ::mlir::populateGpuRewritePatterns(m.getContext(), patterns);
      ::mlir::applyPatternsAndFoldGreedily(m, std::move(patterns));
    }

    ::mlir::OwningRewritePatternList patterns;
    ::mlir::LLVMTypeConverter converter(m.getContext());
    ::mlir::populateStdToLLVMConversionPatterns(converter, patterns);
    // TODO(b/145824979) Remove linalg once sliceop is in std.
    ::mlir::populateLinalgToLLVMConversionPatterns(converter, patterns);
    ::mlir::populateGpuToROCDLConversionPatterns(converter, patterns);
    ::mlir::populateAffineToStdConversionPatterns(patterns, m.getContext());

    ::mlir::ConversionTarget target(getContext());
    ::mlir::configureGpuToROCDLConversionLegality(target);
    if (failed(mlir::applyFullConversion(m, target, std::move(patterns)))) {
      signalPassFailure();
    }
  }
};

}  // namespace

Status LowerKernelBodiesToROCDL(mlir::ModuleOp module) {
  ::mlir::PassManager pm(module.getContext());
  // We cannot verify as the signature of the kernel is rewritten.
  pm.enableVerifier(false);
  tensorflow::applyTensorflowAndCLOptions(pm);

  auto enable_if_vlog_is_on = [](mlir::Pass*, mlir::Operation*) {
    return VLOG_IS_ON(1);
  };
  pm.enableIRPrinting(/*shouldPrintBeforePass=*/{},
                      /*shouldPrintAfterPass=*/enable_if_vlog_is_on,
                      /*printModuleScope=*/false,
                      /*printAfterOnlyOnChange=*/false,
                      /*out=*/llvm::dbgs());

  // Rewrite kernel functions to LLVM IR.
  auto& kernelPm = pm.nest<::mlir::gpu::GPUModuleOp>();
  kernelPm.addPass(::mlir::createLowerToCFGPass());
  kernelPm.addPass(absl::make_unique<LowerToROCDLPass>());

  // Some basic cleanup.
  kernelPm.addNestedPass<::mlir::FuncOp>(::mlir::createCanonicalizerPass());
  kernelPm.addNestedPass<::mlir::FuncOp>(::mlir::createCSEPass());
  // Remove all location information to prevent a debug build.
  kernelPm.addPass(::mlir::createStripDebugInfoPass());

  if (failed(pm.run(module))) {
    return InternalError("Lowering to ROCDL IR failed.");
  }
  return Status::OK();
}

StatusOr<mlir::ModuleOp> ExtractKernelModule(mlir::ModuleOp module) {
  auto kernelModule = ::mlir::ModuleOp::create(module.getLoc());
  // TODO(b/137624192): This also needs to resolve naming conflicts.
  module.walk([&kernelModule](mlir::gpu::GPUModuleOp nestedModule) {
    for (auto& fn : nestedModule.body().front()) {
      kernelModule.push_back(fn.clone());
    }
  });
  return kernelModule;
}

}  // namespace mlir_gpu
}  // namespace xla
<|endoftext|>