<commit_before>/*
 * Copyright 2011, 2012 Esrille Inc.
 *
 * 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 "URI.h"

#include <assert.h>
#include <unicode/uidna.h>

#include "utf.h"

namespace org { namespace w3c { namespace dom { namespace bootstrap {

std::string URI::percentEncode(const std::u16string& string, size_t pos, size_t n)
{
    std::string encoding;
    if (n == std::string::npos)
        n = string.length();
    const char16_t* p = string.c_str() + pos;
    for (const char16_t* s = p; s < p + n; ) {
        char32_t utf32;
        s = utf16to32(s, &utf32);
        assert(s);
        char utf8[5];
        char* end = utf32to8(utf32, utf8);
        assert(end);
        for (const char* p = utf8; p < end; ++p) {
            if (*p <= 0x20 || (*p < 127 && strchr("\"#%<>[\\]^{|}", *p))) {
                encoding += '%';
                char hex[3];
                sprintf(hex, "%02X", *p & 0xff);
                encoding += hex;
            } else
                encoding += *p;
        }
    }
    return encoding;
}

std::string URI::percentDecode(const std::string& string, size_t pos, size_t n)
{
    std::string decoding;
    if (n == std::string::npos)
        n = string.length();
    const char* p = string.c_str() + pos;
    const char* end = p + n;
    while (p < end) {
        char c = *p++;
        if (c == '%' && p + 2 <= end) {
            int x0 = isHexDigit(p[0]);
            int x1 = isHexDigit(p[1]);
            if (x0 && x1)
                decoding += static_cast<char>(((p[0] - x0) << 4) | (p[1] - x1));
            else {
                decoding += '%';
                decoding += p[0];
                decoding += p[1];
            }
            p += 2;
        } else
            decoding += c;
    }
    return decoding;
}

void URI::clear()
{
    protocolEnd = 0;
    hostStart = hostEnd = 0;
    hostnameStart = hostnameEnd = 0;
    portStart = portEnd = 0;
    pathnameStart = pathnameEnd = 0;
    searchStart = searchEnd = 0;
    hashStart = hashEnd = 0;
    uri.clear();
}

URI::URI(const URL& url)
{
    if (url.isEmpty()) {
        protocolEnd = 0;
        hostStart = hostEnd = 0;
        hostnameStart = hostnameEnd = 0;
        portStart = portEnd = 0;
        pathnameStart = pathnameEnd = 0;
        searchStart = searchEnd = 0;
        hashStart = hashEnd = 0;
        return;
    }

    uri += percentEncode(url.url, 0, url.protocolEnd);
    protocolEnd = uri.length();

    if (url.hostnameStart == url.hostnameEnd)
        hostStart = hostnameStart = 0;
    else {
        uri += "//";
        hostStart = hostnameStart = uri.length();
        UChar idn[256];
        int32_t len;
        UErrorCode status = U_ZERO_ERROR;
        len = uidna_IDNToASCII(reinterpret_cast<const UChar*>(url.url.c_str()) + url.hostnameStart, url.hostnameEnd - url.hostnameStart,
                               idn, 256, UIDNA_DEFAULT, 0, &status);
        if (status != U_ZERO_ERROR) {
            // TODO: error
            clear();
            return;
        }
        for (int32_t i = 0; i < len; ++i)
            uri += static_cast<char>(idn[i]);
    }
    hostnameEnd = uri.length();
    if (url.portStart < url.portEnd) {
        uri += ':';
        portStart = uri.length();
        uri += percentEncode(url.url, url.portStart, url.portEnd - url.portStart);
        portEnd = uri.length();
    } else
        portStart = portEnd = 0;
    pathnameStart = hostEnd = uri.length();
    uri += percentEncode(url.url, url.pathnameStart, url.pathnameEnd - url.pathnameStart);
    pathnameEnd = uri.length();
    if (url.searchStart < url.searchEnd) {
        searchStart = uri.length();
        uri += percentEncode(url.url, url.searchStart, url.searchEnd - url.searchStart);
        searchEnd = uri.length();
    } else
        searchStart = searchEnd = 0;
    if (url.hashStart < url.hashEnd) {
        hashStart = uri.length();
        uri += percentEncode(url.url, url.hashStart, url.hashEnd - url.hashStart);
        hashEnd = uri.length();
    } else
        hashStart = hashEnd = 0;
}

std::string URI::getPort() const
{
    if (portStart < portEnd)
        return uri.substr(portStart, portEnd - portStart);
    if (!uri.compare(0, 5, "http:"))
        return "80";
    if (!uri.compare(0, 6, "https:"))
        return "443";
    return "";
}

}}}}  // org::w3c::dom::bootstrap
<commit_msg>(URI::percentEncode) : Fix a bug.<commit_after>/*
 * Copyright 2011, 2012 Esrille Inc.
 *
 * 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 "URI.h"

#include <assert.h>
#include <unicode/uidna.h>

#include "utf.h"

namespace org { namespace w3c { namespace dom { namespace bootstrap {

std::string URI::percentEncode(const std::u16string& string, size_t pos, size_t n)
{
    std::string encoding;
    if (n == std::string::npos)
        n = string.length();
    const char16_t* p = string.c_str() + pos;
    for (const char16_t* s = p; s < p + n; ) {
        char32_t utf32;
        s = utf16to32(s, &utf32);
        assert(s);
        char utf8[5];
        char* end = utf32to8(utf32, utf8);
        assert(end);
        for (const char* p = utf8; p < end; ++p) {
            // Note percent-encoding characters in the original URL value must be preserved.
            if (isalnum(*p) || strchr("%" "!*'();:@&=+$,/?#[]-_.~", *p))
                encoding += *p;
            else {
                encoding += '%';
                char hex[3];
                sprintf(hex, "%02X", *p & 0xff);
                encoding += hex;
            }
        }
    }
    return encoding;
}

std::string URI::percentDecode(const std::string& string, size_t pos, size_t n)
{
    std::string decoding;
    if (n == std::string::npos)
        n = string.length();
    const char* p = string.c_str() + pos;
    const char* end = p + n;
    while (p < end) {
        char c = *p++;
        if (c == '%' && p + 2 <= end) {
            int x0 = isHexDigit(p[0]);
            int x1 = isHexDigit(p[1]);
            if (x0 && x1)
                decoding += static_cast<char>(((p[0] - x0) << 4) | (p[1] - x1));
            else {
                decoding += '%';
                decoding += p[0];
                decoding += p[1];
            }
            p += 2;
        } else
            decoding += c;
    }
    return decoding;
}

void URI::clear()
{
    protocolEnd = 0;
    hostStart = hostEnd = 0;
    hostnameStart = hostnameEnd = 0;
    portStart = portEnd = 0;
    pathnameStart = pathnameEnd = 0;
    searchStart = searchEnd = 0;
    hashStart = hashEnd = 0;
    uri.clear();
}

URI::URI(const URL& url)
{
    if (url.isEmpty()) {
        protocolEnd = 0;
        hostStart = hostEnd = 0;
        hostnameStart = hostnameEnd = 0;
        portStart = portEnd = 0;
        pathnameStart = pathnameEnd = 0;
        searchStart = searchEnd = 0;
        hashStart = hashEnd = 0;
        return;
    }

    uri += percentEncode(url.url, 0, url.protocolEnd);
    protocolEnd = uri.length();

    if (url.hostnameStart == url.hostnameEnd)
        hostStart = hostnameStart = 0;
    else {
        uri += "//";
        hostStart = hostnameStart = uri.length();
        UChar idn[256];
        int32_t len;
        UErrorCode status = U_ZERO_ERROR;
        len = uidna_IDNToASCII(reinterpret_cast<const UChar*>(url.url.c_str()) + url.hostnameStart, url.hostnameEnd - url.hostnameStart,
                               idn, 256, UIDNA_DEFAULT, 0, &status);
        if (status != U_ZERO_ERROR) {
            // TODO: error
            clear();
            return;
        }
        for (int32_t i = 0; i < len; ++i)
            uri += static_cast<char>(idn[i]);
    }
    hostnameEnd = uri.length();
    if (url.portStart < url.portEnd) {
        uri += ':';
        portStart = uri.length();
        uri += percentEncode(url.url, url.portStart, url.portEnd - url.portStart);
        portEnd = uri.length();
    } else
        portStart = portEnd = 0;
    pathnameStart = hostEnd = uri.length();
    uri += percentEncode(url.url, url.pathnameStart, url.pathnameEnd - url.pathnameStart);
    pathnameEnd = uri.length();
    if (url.searchStart < url.searchEnd) {
        searchStart = uri.length();
        uri += percentEncode(url.url, url.searchStart, url.searchEnd - url.searchStart);
        searchEnd = uri.length();
    } else
        searchStart = searchEnd = 0;
    if (url.hashStart < url.hashEnd) {
        hashStart = uri.length();
        uri += percentEncode(url.url, url.hashStart, url.hashEnd - url.hashStart);
        hashEnd = uri.length();
    } else
        hashStart = hashEnd = 0;
}

std::string URI::getPort() const
{
    if (portStart < portEnd)
        return uri.substr(portStart, portEnd - portStart);
    if (!uri.compare(0, 5, "http:"))
        return "80";
    if (!uri.compare(0, 6, "https:"))
        return "443";
    return "";
}

}}}}  // org::w3c::dom::bootstrap
<|endoftext|>


<commit_before>// @(#)root/pyroot:$Id$
// Author: Wim Lavrijsen, May 2004

// Bindings
#include "PyROOT.h"
#include "TPyClassGenerator.h"
#include "Utility.h"
#include "TPyReturn.h"

// ROOT
#include "TClass.h"

// CINT
#include "Api.h"

// Standard
#include <string>

//- private helpers ----------------------------------------------------------
namespace {

   //_________________________________________________________________________
   int PyCtorCallback( G__value* res, G__CONST char*, struct G__param* libp, int hash )
   {
      PyObject* pyclass = PyROOT::Utility::GetInstalledMethod( G__value_get_tagnum(res) );
      if ( ! pyclass )
         return 0;

      PyObject* args = PyTuple_New( 0 );
      PyObject* result =  PyObject_Call( pyclass, args, NULL );
      if ( ! result )
         PyErr_Print();
      Py_DECREF( args );

      G__letint(res,'u',(Long_t)result);
      res->ref   = (Long_t)result;

      G__linked_taginfo pti;
      pti.tagnum = -1;
      pti.tagtype = 'c';

      PyObject* str = PyObject_Str( pyclass );
      std::string clName = PyString_AS_STRING( str );
      Py_DECREF( str );

      clName = clName.substr( clName.rfind( '.' )+1, std::string::npos );
      pti.tagname = clName.c_str();

      G__set_tagnum(res,G__get_linked_tagnum( &pti ));

      return ( 1 || hash || res || libp );
   }

   //_________________________________________________________________________
   int PyMemFuncCallback( G__value* res, G__CONST char*, struct G__param* libp, int hash )
   {
      PyObject* pyfunc = PyROOT::Utility::GetInstalledMethod( G__value_get_tagnum(res) );
      if ( ! pyfunc )
         return 0;

      PyObject* self = (PyObject*)G__getstructoffset();
      Py_INCREF( self );

      PyObject* args = PyTuple_New( 1 + libp->paran );
      PyTuple_SetItem( args, 0, self );
      for ( int i = 0; i < libp->paran; ++i ) {
         PyObject* arg = 0;
         switch ( G__value_get_type(&libp->para[i]) ) {
         case 'd':
            arg = PyFloat_FromDouble( G__Mdouble(libp->para[i]) );
            break;
         case 'f':
            arg = PyFloat_FromDouble( (double)G__Mfloat(libp->para[i]) );
            break;
         case 'l':
            arg = PyLong_FromLong( G__Mlong(libp->para[i]) );
            break;
         case 'k':
            arg = PyLong_FromUnsignedLong( G__Mulong(libp->para[i] ) );
            break;
         case 'i':
            arg = PyInt_FromLong( (Long_t)G__Mint(libp->para[i]) );
            break;
         case 'h':
            //arg = PyLong_FromUnsignedLong( (UInt_t)G__Muint(libp->para[i]) );
            arg = PyLong_FromUnsignedLong( *(ULong_t*)((void*)G__Mlong(libp->para[i])) );
            break;
         case 's':
            arg = PyInt_FromLong( (Long_t)G__Mshort(libp->para[i]) );
            break;
         case 'r':
            arg = PyInt_FromLong( (Long_t)G__Mushort(libp->para[i]) );
            break;
         case 'u':
         // longlong, ulonglong, longdouble
            break;
         case 'c':
            char cc[2]; cc[0] = G__Mchar(libp->para[i]); cc[1] = '\0';
            arg = PyString_FromString( cc );
            break;
         case 'b':
         // unsigned char
            break;
         case 'C':
            arg = PyString_FromString( (char*)G__Mlong(libp->para[i]) );
            break;
         }

         if ( arg != 0 )
            PyTuple_SetItem( args, i+1, arg );         // steals ref to arg
         else {
            PyErr_Format( PyExc_TypeError,
               "error converting parameter: %d (type: %c)", i, G__value_get_type(&libp->para[i]) );
            break;
         }

      }

      PyObject* result = 0;
      if ( ! PyErr_Occurred() )
         result =  PyObject_Call( pyfunc, args, NULL );
      Py_DECREF( args );

      if ( ! result )
         PyErr_Print();

      TPyReturn* retval = new TPyReturn( result );
      res->obj.i  = (Long_t)retval;
      res->ref    = (Long_t)retval;
      G__set_tagnum( res, ((G__ClassInfo*)TPyReturn::Class()->GetClassInfo())->Tagnum() );

      return ( 1 || hash || res || libp );
   }

} // unnamed namespace

//- public members -----------------------------------------------------------
TClass* TPyClassGenerator::GetClass( const char* name, Bool_t load )
{
   GetClass( name, load, kFALSE );
}

//- public members -----------------------------------------------------------
TClass* TPyClassGenerator::GetClass( const char* name, Bool_t load, Bool_t silent )
{
   // called if all other class generators failed, attempt to build from python class
   if ( PyROOT::gDictLookupActive == kTRUE )
      return 0;                              // call originated from python

   if ( ! load || ! name )
      return 0;

// determine module and class name part
   std::string clName = name;
   std::string::size_type pos = clName.rfind( '.' );

   if ( pos == std::string::npos )
      return 0;                              // this isn't a python style class

   std::string mdName = clName.substr( 0, pos );
   clName = clName.substr( pos+1, std::string::npos );

// ROOT doesn't know about python modules; the class may exist (TODO: add scopes)
   if ( TClass::GetClass( clName.c_str(), load, silent ) )
      return TClass::GetClass( clName.c_str(), load, silent );

// locate and get class
   PyObject* mod = PyImport_AddModule( const_cast< char* >( mdName.c_str() ) );
   if ( ! mod ) {
      PyErr_Clear();
      return 0;                              // module apparently disappeared
   }

   Py_INCREF( mod );
   PyObject* pyclass =
      PyDict_GetItemString( PyModule_GetDict( mod ), const_cast< char* >( clName.c_str() ) );
   Py_XINCREF( pyclass );
   Py_DECREF( mod );

   if ( ! pyclass ) {
      PyErr_Clear();                         // the class is no longer available?!
      return 0;
   }

// get a listing of all python-side members
   PyObject* attrs = PyObject_Dir( pyclass );
   if ( ! attrs ) {
      PyErr_Clear();
      Py_DECREF( pyclass );
      return 0;
   }

// build CINT class placeholder
   G__linked_taginfo pti;
   pti.tagnum = -1;
   pti.tagtype = 'c';
   pti.tagname = clName.c_str();
   G__add_compiledheader( (clName+".h").c_str() );

   int tagnum = G__get_linked_tagnum( &pti );

   G__tagtable_setup(
      tagnum, sizeof(PyObject), G__CPPLINK, 0x00020000, "", 0, 0 );

   G__ClassInfo gcl( tagnum );

   G__tag_memfunc_setup( tagnum );

// special case: constructor; add method and store callback
   PyROOT::Utility::InstallMethod( &gcl, pyclass, clName, "ellipsis", (void*)PyCtorCallback );

// loop over and add member functions
   for ( int i = 0; i < PyList_GET_SIZE( attrs ); ++i ) {
      PyObject* label = PyList_GET_ITEM( attrs, i );
      Py_INCREF( label );
      PyObject* attr = PyObject_GetAttr( pyclass, label );

   // collect only member functions (i.e. callable elements in __dict__)
      if ( PyCallable_Check( attr ) ) {
         std::string mtName = PyString_AS_STRING( label );

      // add method and store callback
         PyROOT::Utility::InstallMethod( &gcl, attr, mtName, "ellipsis", (void*)PyMemFuncCallback );
      }

      Py_DECREF( attr );
      Py_DECREF( label );
   }

   G__tag_memfunc_reset();

// done, let ROOT manage the new class
   Py_DECREF( pyclass );

   TClass* klass = new TClass( clName.c_str(), silent );
   TClass::AddClass( klass );

   return klass;
}

//____________________________________________________________________________
TClass* TPyClassGenerator::GetClass( const type_info& typeinfo, Bool_t load, Bool_t silent )
{
   return GetClass( typeinfo.name(), load, silent );
}
//____________________________________________________________________________
TClass* TPyClassGenerator::GetClass( const type_info& typeinfo, Bool_t load )
{
// just forward, based on name only
   return GetClass( typeinfo.name(), load );
}
<commit_msg>Add missing return keyword<commit_after>// @(#)root/pyroot:$Id$
// Author: Wim Lavrijsen, May 2004

// Bindings
#include "PyROOT.h"
#include "TPyClassGenerator.h"
#include "Utility.h"
#include "TPyReturn.h"

// ROOT
#include "TClass.h"

// CINT
#include "Api.h"

// Standard
#include <string>

//- private helpers ----------------------------------------------------------
namespace {

   //_________________________________________________________________________
   int PyCtorCallback( G__value* res, G__CONST char*, struct G__param* libp, int hash )
   {
      PyObject* pyclass = PyROOT::Utility::GetInstalledMethod( G__value_get_tagnum(res) );
      if ( ! pyclass )
         return 0;

      PyObject* args = PyTuple_New( 0 );
      PyObject* result =  PyObject_Call( pyclass, args, NULL );
      if ( ! result )
         PyErr_Print();
      Py_DECREF( args );

      G__letint(res,'u',(Long_t)result);
      res->ref   = (Long_t)result;

      G__linked_taginfo pti;
      pti.tagnum = -1;
      pti.tagtype = 'c';

      PyObject* str = PyObject_Str( pyclass );
      std::string clName = PyString_AS_STRING( str );
      Py_DECREF( str );

      clName = clName.substr( clName.rfind( '.' )+1, std::string::npos );
      pti.tagname = clName.c_str();

      G__set_tagnum(res,G__get_linked_tagnum( &pti ));

      return ( 1 || hash || res || libp );
   }

   //_________________________________________________________________________
   int PyMemFuncCallback( G__value* res, G__CONST char*, struct G__param* libp, int hash )
   {
      PyObject* pyfunc = PyROOT::Utility::GetInstalledMethod( G__value_get_tagnum(res) );
      if ( ! pyfunc )
         return 0;

      PyObject* self = (PyObject*)G__getstructoffset();
      Py_INCREF( self );

      PyObject* args = PyTuple_New( 1 + libp->paran );
      PyTuple_SetItem( args, 0, self );
      for ( int i = 0; i < libp->paran; ++i ) {
         PyObject* arg = 0;
         switch ( G__value_get_type(&libp->para[i]) ) {
         case 'd':
            arg = PyFloat_FromDouble( G__Mdouble(libp->para[i]) );
            break;
         case 'f':
            arg = PyFloat_FromDouble( (double)G__Mfloat(libp->para[i]) );
            break;
         case 'l':
            arg = PyLong_FromLong( G__Mlong(libp->para[i]) );
            break;
         case 'k':
            arg = PyLong_FromUnsignedLong( G__Mulong(libp->para[i] ) );
            break;
         case 'i':
            arg = PyInt_FromLong( (Long_t)G__Mint(libp->para[i]) );
            break;
         case 'h':
            //arg = PyLong_FromUnsignedLong( (UInt_t)G__Muint(libp->para[i]) );
            arg = PyLong_FromUnsignedLong( *(ULong_t*)((void*)G__Mlong(libp->para[i])) );
            break;
         case 's':
            arg = PyInt_FromLong( (Long_t)G__Mshort(libp->para[i]) );
            break;
         case 'r':
            arg = PyInt_FromLong( (Long_t)G__Mushort(libp->para[i]) );
            break;
         case 'u':
         // longlong, ulonglong, longdouble
            break;
         case 'c':
            char cc[2]; cc[0] = G__Mchar(libp->para[i]); cc[1] = '\0';
            arg = PyString_FromString( cc );
            break;
         case 'b':
         // unsigned char
            break;
         case 'C':
            arg = PyString_FromString( (char*)G__Mlong(libp->para[i]) );
            break;
         }

         if ( arg != 0 )
            PyTuple_SetItem( args, i+1, arg );         // steals ref to arg
         else {
            PyErr_Format( PyExc_TypeError,
               "error converting parameter: %d (type: %c)", i, G__value_get_type(&libp->para[i]) );
            break;
         }

      }

      PyObject* result = 0;
      if ( ! PyErr_Occurred() )
         result =  PyObject_Call( pyfunc, args, NULL );
      Py_DECREF( args );

      if ( ! result )
         PyErr_Print();

      TPyReturn* retval = new TPyReturn( result );
      res->obj.i  = (Long_t)retval;
      res->ref    = (Long_t)retval;
      G__set_tagnum( res, ((G__ClassInfo*)TPyReturn::Class()->GetClassInfo())->Tagnum() );

      return ( 1 || hash || res || libp );
   }

} // unnamed namespace

//- public members -----------------------------------------------------------
TClass* TPyClassGenerator::GetClass( const char* name, Bool_t load )
{
   return GetClass( name, load, kFALSE );
}

//- public members -----------------------------------------------------------
TClass* TPyClassGenerator::GetClass( const char* name, Bool_t load, Bool_t silent )
{
   // called if all other class generators failed, attempt to build from python class
   if ( PyROOT::gDictLookupActive == kTRUE )
      return 0;                              // call originated from python

   if ( ! load || ! name )
      return 0;

// determine module and class name part
   std::string clName = name;
   std::string::size_type pos = clName.rfind( '.' );

   if ( pos == std::string::npos )
      return 0;                              // this isn't a python style class

   std::string mdName = clName.substr( 0, pos );
   clName = clName.substr( pos+1, std::string::npos );

// ROOT doesn't know about python modules; the class may exist (TODO: add scopes)
   if ( TClass::GetClass( clName.c_str(), load, silent ) )
      return TClass::GetClass( clName.c_str(), load, silent );

// locate and get class
   PyObject* mod = PyImport_AddModule( const_cast< char* >( mdName.c_str() ) );
   if ( ! mod ) {
      PyErr_Clear();
      return 0;                              // module apparently disappeared
   }

   Py_INCREF( mod );
   PyObject* pyclass =
      PyDict_GetItemString( PyModule_GetDict( mod ), const_cast< char* >( clName.c_str() ) );
   Py_XINCREF( pyclass );
   Py_DECREF( mod );

   if ( ! pyclass ) {
      PyErr_Clear();                         // the class is no longer available?!
      return 0;
   }

// get a listing of all python-side members
   PyObject* attrs = PyObject_Dir( pyclass );
   if ( ! attrs ) {
      PyErr_Clear();
      Py_DECREF( pyclass );
      return 0;
   }

// build CINT class placeholder
   G__linked_taginfo pti;
   pti.tagnum = -1;
   pti.tagtype = 'c';
   pti.tagname = clName.c_str();
   G__add_compiledheader( (clName+".h").c_str() );

   int tagnum = G__get_linked_tagnum( &pti );

   G__tagtable_setup(
      tagnum, sizeof(PyObject), G__CPPLINK, 0x00020000, "", 0, 0 );

   G__ClassInfo gcl( tagnum );

   G__tag_memfunc_setup( tagnum );

// special case: constructor; add method and store callback
   PyROOT::Utility::InstallMethod( &gcl, pyclass, clName, "ellipsis", (void*)PyCtorCallback );

// loop over and add member functions
   for ( int i = 0; i < PyList_GET_SIZE( attrs ); ++i ) {
      PyObject* label = PyList_GET_ITEM( attrs, i );
      Py_INCREF( label );
      PyObject* attr = PyObject_GetAttr( pyclass, label );

   // collect only member functions (i.e. callable elements in __dict__)
      if ( PyCallable_Check( attr ) ) {
         std::string mtName = PyString_AS_STRING( label );

      // add method and store callback
         PyROOT::Utility::InstallMethod( &gcl, attr, mtName, "ellipsis", (void*)PyMemFuncCallback );
      }

      Py_DECREF( attr );
      Py_DECREF( label );
   }

   G__tag_memfunc_reset();

// done, let ROOT manage the new class
   Py_DECREF( pyclass );

   TClass* klass = new TClass( clName.c_str(), silent );
   TClass::AddClass( klass );

   return klass;
}

//____________________________________________________________________________
TClass* TPyClassGenerator::GetClass( const type_info& typeinfo, Bool_t load, Bool_t silent )
{
   return GetClass( typeinfo.name(), load, silent );
}
//____________________________________________________________________________
TClass* TPyClassGenerator::GetClass( const type_info& typeinfo, Bool_t load )
{
// just forward, based on name only
   return GetClass( typeinfo.name(), load );
}
<|endoftext|>


<commit_before>//===-- GCNSchedStrategy.cpp - GCN Scheduler Strategy ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file
/// This contains a MachineSchedStrategy implementation for maximizing wave
/// occupancy on GCN hardware.
//===----------------------------------------------------------------------===//

#include "GCNSchedStrategy.h"
#include "AMDGPUSubtarget.h"
#include "SIInstrInfo.h"
#include "SIMachineFunctionInfo.h"
#include "SIRegisterInfo.h"
#include "llvm/CodeGen/RegisterClassInfo.h"

#define DEBUG_TYPE "misched"

using namespace llvm;

GCNMaxOccupancySchedStrategy::GCNMaxOccupancySchedStrategy(
    const MachineSchedContext *C) :
    GenericScheduler(C) { }

static unsigned getMaxWaves(unsigned SGPRs, unsigned VGPRs,
                            const MachineFunction &MF) {

  const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
  const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
  unsigned MinRegOccupancy = std::min(ST.getOccupancyWithNumSGPRs(SGPRs),
                                      ST.getOccupancyWithNumVGPRs(VGPRs));
  return std::min(MinRegOccupancy,
                  ST.getOccupancyWithLocalMemSize(MFI->getLDSSize(),
                                                  *MF.getFunction()));
}

void GCNMaxOccupancySchedStrategy::initCandidate(SchedCandidate &Cand, SUnit *SU,
                                     bool AtTop, const RegPressureTracker &RPTracker,
                                     const SIRegisterInfo *SRI,
                                     int SGPRPressure,
                                     int VGPRPressure,
                                     int SGPRExcessLimit,
                                     int VGPRExcessLimit,
                                     int SGPRCriticalLimit,
                                     int VGPRCriticalLimit) {

  Cand.SU = SU;
  Cand.AtTop = AtTop;

  // getDownwardPressure() and getUpwardPressure() make temporary changes to
  // the the tracker, so we need to pass those function a non-const copy.
  RegPressureTracker &TempTracker = const_cast<RegPressureTracker&>(RPTracker);

  std::vector<unsigned> Pressure;
  std::vector<unsigned> MaxPressure;

  if (AtTop)
    TempTracker.getDownwardPressure(SU->getInstr(), Pressure, MaxPressure);
  else {
    // FIXME: I think for bottom up scheduling, the register pressure is cached
    // and can be retrieved by DAG->getPressureDif(SU).
    TempTracker.getUpwardPressure(SU->getInstr(), Pressure, MaxPressure);
  }

  int NewSGPRPressure = Pressure[SRI->getSGPRPressureSet()];
  int NewVGPRPressure = Pressure[SRI->getVGPRPressureSet()];

  // If two instructions increase the pressure of different register sets
  // by the same amount, the generic scheduler will prefer to schedule the
  // instruction that increases the set with the least amount of registers,
  // which in our case would be SGPRs.  This is rarely what we want, so
  // when we report excess/critical register pressure, we do it either
  // only for VGPRs or only for SGPRs.

  // FIXME: Better heuristics to determine whether to prefer SGPRs or VGPRs.
  const int MaxVGPRPressureInc = 16;
  bool ShouldTrackVGPRs = VGPRPressure + MaxVGPRPressureInc >= VGPRExcessLimit;
  bool ShouldTrackSGPRs = !ShouldTrackVGPRs && SGPRPressure >= SGPRExcessLimit;

  // FIXME: We have to enter REG-EXCESS before we reach the actual threshold
  // to increase the likelihood we don't go over the limits.  We should improve
  // the analysis to look through dependencies to find the path with the least
  // register pressure.
  // FIXME: This is also necessary, because some passes that run after
  // scheduling and before regalloc increase register pressure.
  const int ErrorMargin = 3;
  VGPRExcessLimit -= ErrorMargin;
  SGPRExcessLimit -= ErrorMargin;

  // We only need to update the RPDelata for instructions that increase
  // register pressure.  Instructions that decrease or keep reg pressure
  // the same will be marked as RegExcess in tryCandidate() when they
  // are compared with instructions that increase the register pressure.
  if (ShouldTrackVGPRs && NewVGPRPressure >= VGPRExcessLimit) {
    Cand.RPDelta.Excess = PressureChange(SRI->getVGPRPressureSet());
    Cand.RPDelta.Excess.setUnitInc(NewVGPRPressure - VGPRExcessLimit);
  }

  if (ShouldTrackSGPRs && NewSGPRPressure >= SGPRExcessLimit) {
    Cand.RPDelta.Excess = PressureChange(SRI->getSGPRPressureSet());
    Cand.RPDelta.Excess.setUnitInc(NewSGPRPressure - SGPRExcessLimit);
  }

  // Register pressure is considered 'CRITICAL' if it is approaching a value
  // that would reduce the wave occupancy for the execution unit.  When
  // register pressure is 'CRITICAL', increading SGPR and VGPR pressure both
  // has the same cost, so we don't need to prefer one over the other.

  VGPRCriticalLimit -= ErrorMargin;
  SGPRCriticalLimit -= ErrorMargin;

  int SGPRDelta = NewSGPRPressure - SGPRCriticalLimit;
  int VGPRDelta = NewVGPRPressure - VGPRCriticalLimit;

  if (SGPRDelta >= 0 || VGPRDelta >= 0) {
    if (SGPRDelta > VGPRDelta) {
      Cand.RPDelta.CriticalMax = PressureChange(SRI->getSGPRPressureSet());
      Cand.RPDelta.CriticalMax.setUnitInc(SGPRDelta);
    } else {
      Cand.RPDelta.CriticalMax = PressureChange(SRI->getVGPRPressureSet());
      Cand.RPDelta.CriticalMax.setUnitInc(VGPRDelta);
    }
  }
}

// This function is mostly cut and pasted from
// GenericScheduler::pickNodeFromQueue()
void GCNMaxOccupancySchedStrategy::pickNodeFromQueue(SchedBoundary &Zone,
                                         const CandPolicy &ZonePolicy,
                                         const RegPressureTracker &RPTracker,
                                         SchedCandidate &Cand) {
  const SISubtarget &ST = DAG->MF.getSubtarget<SISubtarget>();
  const SIRegisterInfo *SRI = static_cast<const SIRegisterInfo*>(TRI);
  ArrayRef<unsigned> Pressure = RPTracker.getRegSetPressureAtPos();
  unsigned SGPRPressure = Pressure[SRI->getSGPRPressureSet()];
  unsigned VGPRPressure = Pressure[SRI->getVGPRPressureSet()];
  unsigned SGPRExcessLimit =
      Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::SGPR_32RegClass);
  unsigned VGPRExcessLimit =
      Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::VGPR_32RegClass);
  unsigned MaxWaves = getMaxWaves(SGPRPressure, VGPRPressure, DAG->MF);
  unsigned SGPRCriticalLimit = SRI->getMaxNumSGPRs(ST, MaxWaves, true);
  unsigned VGPRCriticalLimit = SRI->getMaxNumVGPRs(MaxWaves);

  ReadyQueue &Q = Zone.Available;
  for (SUnit *SU : Q) {

    SchedCandidate TryCand(ZonePolicy);
    initCandidate(TryCand, SU, Zone.isTop(), RPTracker, SRI,
                  SGPRPressure, VGPRPressure,
                  SGPRExcessLimit, VGPRExcessLimit,
                  SGPRCriticalLimit, VGPRCriticalLimit);
    // Pass SchedBoundary only when comparing nodes from the same boundary.
    SchedBoundary *ZoneArg = Cand.AtTop == TryCand.AtTop ? &Zone : nullptr;
    GenericScheduler::tryCandidate(Cand, TryCand, ZoneArg);
    if (TryCand.Reason != NoCand) {
      // Initialize resource delta if needed in case future heuristics query it.
      if (TryCand.ResDelta == SchedResourceDelta())
        TryCand.initResourceDelta(Zone.DAG, SchedModel);
      Cand.setBest(TryCand);
    }
  }
}

static int getBidirectionalReasonRank(GenericSchedulerBase::CandReason Reason) {
  switch (Reason) {
  default:
    return Reason;
  case GenericSchedulerBase::RegCritical:
  case GenericSchedulerBase::RegExcess:
    return -Reason;
 }
}

// This function is mostly cut and pasted from
// GenericScheduler::pickNodeBidirectional()
SUnit *GCNMaxOccupancySchedStrategy::pickNodeBidirectional(bool &IsTopNode) {
  // Schedule as far as possible in the direction of no choice. This is most
  // efficient, but also provides the best heuristics for CriticalPSets.
  if (SUnit *SU = Bot.pickOnlyChoice()) {
    IsTopNode = false;
    return SU;
  }
  if (SUnit *SU = Top.pickOnlyChoice()) {
    IsTopNode = true;
    return SU;
  }
  // Set the bottom-up policy based on the state of the current bottom zone and
  // the instructions outside the zone, including the top zone.
  CandPolicy BotPolicy;
  setPolicy(BotPolicy, /*IsPostRA=*/false, Bot, &Top);
  // Set the top-down policy based on the state of the current top zone and
  // the instructions outside the zone, including the bottom zone.
  CandPolicy TopPolicy;
  setPolicy(TopPolicy, /*IsPostRA=*/false, Top, &Bot);

  // See if BotCand is still valid (because we previously scheduled from Top).
  DEBUG(dbgs() << "Picking from Bot:\n");
  if (!BotCand.isValid() || BotCand.SU->isScheduled ||
      BotCand.Policy != BotPolicy) {
    BotCand.reset(CandPolicy());
    pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), BotCand);
    assert(BotCand.Reason != NoCand && "failed to find the first candidate");
  } else {
    DEBUG(traceCandidate(BotCand));
  }

  // Check if the top Q has a better candidate.
  DEBUG(dbgs() << "Picking from Top:\n");
  if (!TopCand.isValid() || TopCand.SU->isScheduled ||
      TopCand.Policy != TopPolicy) {
    TopCand.reset(CandPolicy());
    pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TopCand);
    assert(TopCand.Reason != NoCand && "failed to find the first candidate");
  } else {
    DEBUG(traceCandidate(TopCand));
  }

  // Pick best from BotCand and TopCand.
  DEBUG(
    dbgs() << "Top Cand: ";
    traceCandidate(BotCand);
    dbgs() << "Bot Cand: ";
    traceCandidate(TopCand);
  );
  SchedCandidate Cand;
  if (TopCand.Reason == BotCand.Reason) {
    Cand = BotCand;
    GenericSchedulerBase::CandReason TopReason = TopCand.Reason;
    TopCand.Reason = NoCand;
    GenericScheduler::tryCandidate(Cand, TopCand, nullptr);
    if (TopCand.Reason != NoCand) {
      Cand.setBest(TopCand);
    } else {
      TopCand.Reason = TopReason;
    }
  } else {
    if (TopCand.Reason == RegExcess && TopCand.RPDelta.Excess.getUnitInc() <= 0) {
      Cand = TopCand;
    } else if (BotCand.Reason == RegExcess && BotCand.RPDelta.Excess.getUnitInc() <= 0) {
      Cand = BotCand;
    } else if (TopCand.Reason == RegCritical && TopCand.RPDelta.CriticalMax.getUnitInc() <= 0) {
      Cand = TopCand;
    } else if (BotCand.Reason == RegCritical && BotCand.RPDelta.CriticalMax.getUnitInc() <= 0) {
      Cand = BotCand;
    } else {
      int TopRank = getBidirectionalReasonRank(TopCand.Reason);
      int BotRank = getBidirectionalReasonRank(BotCand.Reason);
      if (TopRank > BotRank) {
        Cand = TopCand;
      } else {
        Cand = BotCand;
      }
    }
  }
  DEBUG(
    dbgs() << "Picking: ";
    traceCandidate(Cand);
  );

  IsTopNode = Cand.AtTop;
  return Cand.SU;
}

// This function is mostly cut and pasted from
// GenericScheduler::pickNode()
SUnit *GCNMaxOccupancySchedStrategy::pickNode(bool &IsTopNode) {
  if (DAG->top() == DAG->bottom()) {
    assert(Top.Available.empty() && Top.Pending.empty() &&
           Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage");
    return nullptr;
  }
  SUnit *SU;
  do {
    if (RegionPolicy.OnlyTopDown) {
      SU = Top.pickOnlyChoice();
      if (!SU) {
        CandPolicy NoPolicy;
        TopCand.reset(NoPolicy);
        pickNodeFromQueue(Top, NoPolicy, DAG->getTopRPTracker(), TopCand);
        assert(TopCand.Reason != NoCand && "failed to find a candidate");
        SU = TopCand.SU;
      }
      IsTopNode = true;
    } else if (RegionPolicy.OnlyBottomUp) {
      SU = Bot.pickOnlyChoice();
      if (!SU) {
        CandPolicy NoPolicy;
        BotCand.reset(NoPolicy);
        pickNodeFromQueue(Bot, NoPolicy, DAG->getBotRPTracker(), BotCand);
        assert(BotCand.Reason != NoCand && "failed to find a candidate");
        SU = BotCand.SU;
      }
      IsTopNode = false;
    } else {
      SU = pickNodeBidirectional(IsTopNode);
    }
  } while (SU->isScheduled);

  if (SU->isTopReady())
    Top.removeReady(SU);
  if (SU->isBottomReady())
    Bot.removeReady(SU);

  DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") " << *SU->getInstr());
  return SU;
}
<commit_msg>[AMDGPU] Fix GCNSchedStrategy.cpp debug output<commit_after>//===-- GCNSchedStrategy.cpp - GCN Scheduler Strategy ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file
/// This contains a MachineSchedStrategy implementation for maximizing wave
/// occupancy on GCN hardware.
//===----------------------------------------------------------------------===//

#include "GCNSchedStrategy.h"
#include "AMDGPUSubtarget.h"
#include "SIInstrInfo.h"
#include "SIMachineFunctionInfo.h"
#include "SIRegisterInfo.h"
#include "llvm/CodeGen/RegisterClassInfo.h"

#define DEBUG_TYPE "misched"

using namespace llvm;

GCNMaxOccupancySchedStrategy::GCNMaxOccupancySchedStrategy(
    const MachineSchedContext *C) :
    GenericScheduler(C) { }

static unsigned getMaxWaves(unsigned SGPRs, unsigned VGPRs,
                            const MachineFunction &MF) {

  const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
  const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
  unsigned MinRegOccupancy = std::min(ST.getOccupancyWithNumSGPRs(SGPRs),
                                      ST.getOccupancyWithNumVGPRs(VGPRs));
  return std::min(MinRegOccupancy,
                  ST.getOccupancyWithLocalMemSize(MFI->getLDSSize(),
                                                  *MF.getFunction()));
}

void GCNMaxOccupancySchedStrategy::initCandidate(SchedCandidate &Cand, SUnit *SU,
                                     bool AtTop, const RegPressureTracker &RPTracker,
                                     const SIRegisterInfo *SRI,
                                     int SGPRPressure,
                                     int VGPRPressure,
                                     int SGPRExcessLimit,
                                     int VGPRExcessLimit,
                                     int SGPRCriticalLimit,
                                     int VGPRCriticalLimit) {

  Cand.SU = SU;
  Cand.AtTop = AtTop;

  // getDownwardPressure() and getUpwardPressure() make temporary changes to
  // the the tracker, so we need to pass those function a non-const copy.
  RegPressureTracker &TempTracker = const_cast<RegPressureTracker&>(RPTracker);

  std::vector<unsigned> Pressure;
  std::vector<unsigned> MaxPressure;

  if (AtTop)
    TempTracker.getDownwardPressure(SU->getInstr(), Pressure, MaxPressure);
  else {
    // FIXME: I think for bottom up scheduling, the register pressure is cached
    // and can be retrieved by DAG->getPressureDif(SU).
    TempTracker.getUpwardPressure(SU->getInstr(), Pressure, MaxPressure);
  }

  int NewSGPRPressure = Pressure[SRI->getSGPRPressureSet()];
  int NewVGPRPressure = Pressure[SRI->getVGPRPressureSet()];

  // If two instructions increase the pressure of different register sets
  // by the same amount, the generic scheduler will prefer to schedule the
  // instruction that increases the set with the least amount of registers,
  // which in our case would be SGPRs.  This is rarely what we want, so
  // when we report excess/critical register pressure, we do it either
  // only for VGPRs or only for SGPRs.

  // FIXME: Better heuristics to determine whether to prefer SGPRs or VGPRs.
  const int MaxVGPRPressureInc = 16;
  bool ShouldTrackVGPRs = VGPRPressure + MaxVGPRPressureInc >= VGPRExcessLimit;
  bool ShouldTrackSGPRs = !ShouldTrackVGPRs && SGPRPressure >= SGPRExcessLimit;

  // FIXME: We have to enter REG-EXCESS before we reach the actual threshold
  // to increase the likelihood we don't go over the limits.  We should improve
  // the analysis to look through dependencies to find the path with the least
  // register pressure.
  // FIXME: This is also necessary, because some passes that run after
  // scheduling and before regalloc increase register pressure.
  const int ErrorMargin = 3;
  VGPRExcessLimit -= ErrorMargin;
  SGPRExcessLimit -= ErrorMargin;

  // We only need to update the RPDelata for instructions that increase
  // register pressure.  Instructions that decrease or keep reg pressure
  // the same will be marked as RegExcess in tryCandidate() when they
  // are compared with instructions that increase the register pressure.
  if (ShouldTrackVGPRs && NewVGPRPressure >= VGPRExcessLimit) {
    Cand.RPDelta.Excess = PressureChange(SRI->getVGPRPressureSet());
    Cand.RPDelta.Excess.setUnitInc(NewVGPRPressure - VGPRExcessLimit);
  }

  if (ShouldTrackSGPRs && NewSGPRPressure >= SGPRExcessLimit) {
    Cand.RPDelta.Excess = PressureChange(SRI->getSGPRPressureSet());
    Cand.RPDelta.Excess.setUnitInc(NewSGPRPressure - SGPRExcessLimit);
  }

  // Register pressure is considered 'CRITICAL' if it is approaching a value
  // that would reduce the wave occupancy for the execution unit.  When
  // register pressure is 'CRITICAL', increading SGPR and VGPR pressure both
  // has the same cost, so we don't need to prefer one over the other.

  VGPRCriticalLimit -= ErrorMargin;
  SGPRCriticalLimit -= ErrorMargin;

  int SGPRDelta = NewSGPRPressure - SGPRCriticalLimit;
  int VGPRDelta = NewVGPRPressure - VGPRCriticalLimit;

  if (SGPRDelta >= 0 || VGPRDelta >= 0) {
    if (SGPRDelta > VGPRDelta) {
      Cand.RPDelta.CriticalMax = PressureChange(SRI->getSGPRPressureSet());
      Cand.RPDelta.CriticalMax.setUnitInc(SGPRDelta);
    } else {
      Cand.RPDelta.CriticalMax = PressureChange(SRI->getVGPRPressureSet());
      Cand.RPDelta.CriticalMax.setUnitInc(VGPRDelta);
    }
  }
}

// This function is mostly cut and pasted from
// GenericScheduler::pickNodeFromQueue()
void GCNMaxOccupancySchedStrategy::pickNodeFromQueue(SchedBoundary &Zone,
                                         const CandPolicy &ZonePolicy,
                                         const RegPressureTracker &RPTracker,
                                         SchedCandidate &Cand) {
  const SISubtarget &ST = DAG->MF.getSubtarget<SISubtarget>();
  const SIRegisterInfo *SRI = static_cast<const SIRegisterInfo*>(TRI);
  ArrayRef<unsigned> Pressure = RPTracker.getRegSetPressureAtPos();
  unsigned SGPRPressure = Pressure[SRI->getSGPRPressureSet()];
  unsigned VGPRPressure = Pressure[SRI->getVGPRPressureSet()];
  unsigned SGPRExcessLimit =
      Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::SGPR_32RegClass);
  unsigned VGPRExcessLimit =
      Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::VGPR_32RegClass);
  unsigned MaxWaves = getMaxWaves(SGPRPressure, VGPRPressure, DAG->MF);
  unsigned SGPRCriticalLimit = SRI->getMaxNumSGPRs(ST, MaxWaves, true);
  unsigned VGPRCriticalLimit = SRI->getMaxNumVGPRs(MaxWaves);

  ReadyQueue &Q = Zone.Available;
  for (SUnit *SU : Q) {

    SchedCandidate TryCand(ZonePolicy);
    initCandidate(TryCand, SU, Zone.isTop(), RPTracker, SRI,
                  SGPRPressure, VGPRPressure,
                  SGPRExcessLimit, VGPRExcessLimit,
                  SGPRCriticalLimit, VGPRCriticalLimit);
    // Pass SchedBoundary only when comparing nodes from the same boundary.
    SchedBoundary *ZoneArg = Cand.AtTop == TryCand.AtTop ? &Zone : nullptr;
    GenericScheduler::tryCandidate(Cand, TryCand, ZoneArg);
    if (TryCand.Reason != NoCand) {
      // Initialize resource delta if needed in case future heuristics query it.
      if (TryCand.ResDelta == SchedResourceDelta())
        TryCand.initResourceDelta(Zone.DAG, SchedModel);
      Cand.setBest(TryCand);
    }
  }
}

static int getBidirectionalReasonRank(GenericSchedulerBase::CandReason Reason) {
  switch (Reason) {
  default:
    return Reason;
  case GenericSchedulerBase::RegCritical:
  case GenericSchedulerBase::RegExcess:
    return -Reason;
 }
}

// This function is mostly cut and pasted from
// GenericScheduler::pickNodeBidirectional()
SUnit *GCNMaxOccupancySchedStrategy::pickNodeBidirectional(bool &IsTopNode) {
  // Schedule as far as possible in the direction of no choice. This is most
  // efficient, but also provides the best heuristics for CriticalPSets.
  if (SUnit *SU = Bot.pickOnlyChoice()) {
    IsTopNode = false;
    return SU;
  }
  if (SUnit *SU = Top.pickOnlyChoice()) {
    IsTopNode = true;
    return SU;
  }
  // Set the bottom-up policy based on the state of the current bottom zone and
  // the instructions outside the zone, including the top zone.
  CandPolicy BotPolicy;
  setPolicy(BotPolicy, /*IsPostRA=*/false, Bot, &Top);
  // Set the top-down policy based on the state of the current top zone and
  // the instructions outside the zone, including the bottom zone.
  CandPolicy TopPolicy;
  setPolicy(TopPolicy, /*IsPostRA=*/false, Top, &Bot);

  // See if BotCand is still valid (because we previously scheduled from Top).
  DEBUG(dbgs() << "Picking from Bot:\n");
  if (!BotCand.isValid() || BotCand.SU->isScheduled ||
      BotCand.Policy != BotPolicy) {
    BotCand.reset(CandPolicy());
    pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), BotCand);
    assert(BotCand.Reason != NoCand && "failed to find the first candidate");
  } else {
    DEBUG(traceCandidate(BotCand));
  }

  // Check if the top Q has a better candidate.
  DEBUG(dbgs() << "Picking from Top:\n");
  if (!TopCand.isValid() || TopCand.SU->isScheduled ||
      TopCand.Policy != TopPolicy) {
    TopCand.reset(CandPolicy());
    pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TopCand);
    assert(TopCand.Reason != NoCand && "failed to find the first candidate");
  } else {
    DEBUG(traceCandidate(TopCand));
  }

  // Pick best from BotCand and TopCand.
  DEBUG(
    dbgs() << "Top Cand: ";
    traceCandidate(TopCand);
    dbgs() << "Bot Cand: ";
    traceCandidate(BotCand);
  );
  SchedCandidate Cand;
  if (TopCand.Reason == BotCand.Reason) {
    Cand = BotCand;
    GenericSchedulerBase::CandReason TopReason = TopCand.Reason;
    TopCand.Reason = NoCand;
    GenericScheduler::tryCandidate(Cand, TopCand, nullptr);
    if (TopCand.Reason != NoCand) {
      Cand.setBest(TopCand);
    } else {
      TopCand.Reason = TopReason;
    }
  } else {
    if (TopCand.Reason == RegExcess && TopCand.RPDelta.Excess.getUnitInc() <= 0) {
      Cand = TopCand;
    } else if (BotCand.Reason == RegExcess && BotCand.RPDelta.Excess.getUnitInc() <= 0) {
      Cand = BotCand;
    } else if (TopCand.Reason == RegCritical && TopCand.RPDelta.CriticalMax.getUnitInc() <= 0) {
      Cand = TopCand;
    } else if (BotCand.Reason == RegCritical && BotCand.RPDelta.CriticalMax.getUnitInc() <= 0) {
      Cand = BotCand;
    } else {
      int TopRank = getBidirectionalReasonRank(TopCand.Reason);
      int BotRank = getBidirectionalReasonRank(BotCand.Reason);
      if (TopRank > BotRank) {
        Cand = TopCand;
      } else {
        Cand = BotCand;
      }
    }
  }
  DEBUG(
    dbgs() << "Picking: ";
    traceCandidate(Cand);
  );

  IsTopNode = Cand.AtTop;
  return Cand.SU;
}

// This function is mostly cut and pasted from
// GenericScheduler::pickNode()
SUnit *GCNMaxOccupancySchedStrategy::pickNode(bool &IsTopNode) {
  if (DAG->top() == DAG->bottom()) {
    assert(Top.Available.empty() && Top.Pending.empty() &&
           Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage");
    return nullptr;
  }
  SUnit *SU;
  do {
    if (RegionPolicy.OnlyTopDown) {
      SU = Top.pickOnlyChoice();
      if (!SU) {
        CandPolicy NoPolicy;
        TopCand.reset(NoPolicy);
        pickNodeFromQueue(Top, NoPolicy, DAG->getTopRPTracker(), TopCand);
        assert(TopCand.Reason != NoCand && "failed to find a candidate");
        SU = TopCand.SU;
      }
      IsTopNode = true;
    } else if (RegionPolicy.OnlyBottomUp) {
      SU = Bot.pickOnlyChoice();
      if (!SU) {
        CandPolicy NoPolicy;
        BotCand.reset(NoPolicy);
        pickNodeFromQueue(Bot, NoPolicy, DAG->getBotRPTracker(), BotCand);
        assert(BotCand.Reason != NoCand && "failed to find a candidate");
        SU = BotCand.SU;
      }
      IsTopNode = false;
    } else {
      SU = pickNodeBidirectional(IsTopNode);
    }
  } while (SU->isScheduled);

  if (SU->isTopReady())
    Top.removeReady(SU);
  if (SU->isBottomReady())
    Bot.removeReady(SU);

  DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") " << *SU->getInstr());
  return SU;
}
<|endoftext|>


<commit_before>//===- AlphaRegisterInfo.cpp - Alpha Register Information -------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Alpha implementation of the MRegisterInfo class.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "reginfo"
#include "Alpha.h"
#include "AlphaRegisterInfo.h"
#include "llvm/Constants.h"
#include "llvm/Type.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineLocation.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/STLExtras.h"
#include <cstdlib>
#include <iostream>
using namespace llvm;

//These describe LDAx
static const int IMM_LOW  = -32768;
static const int IMM_HIGH = 32767;
static const int IMM_MULT = 65536;

static long getUpper16(long l)
{
  long y = l / IMM_MULT;
  if (l % IMM_MULT > IMM_HIGH)
    ++y;
  return y;
}

static long getLower16(long l)
{
  long h = getUpper16(l);
  return l - h * IMM_MULT;
}

static int getUID()
{
  static int id = 0;
  return ++id;
}

AlphaRegisterInfo::AlphaRegisterInfo()
  : AlphaGenRegisterInfo(Alpha::ADJUSTSTACKDOWN, Alpha::ADJUSTSTACKUP)
{
}

void
AlphaRegisterInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
                                       MachineBasicBlock::iterator MI,
                                       unsigned SrcReg, int FrameIdx,
                                       const TargetRegisterClass *RC) const {
  //std::cerr << "Trying to store " << getPrettyName(SrcReg) << " to " << FrameIdx << "\n";
  //BuildMI(MBB, MI, Alpha::WTF, 0).addReg(SrcReg);
  if (RC == Alpha::F4RCRegisterClass)
    BuildMI(MBB, MI, Alpha::STS, 3).addReg(SrcReg).addFrameIndex(FrameIdx).addReg(Alpha::F31);
  else if (RC == Alpha::F8RCRegisterClass)
    BuildMI(MBB, MI, Alpha::STT, 3).addReg(SrcReg).addFrameIndex(FrameIdx).addReg(Alpha::F31);
  else if (RC == Alpha::GPRCRegisterClass)
    BuildMI(MBB, MI, Alpha::STQ, 3).addReg(SrcReg).addFrameIndex(FrameIdx).addReg(Alpha::F31);
  else
    abort();
}

void
AlphaRegisterInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
                                        MachineBasicBlock::iterator MI,
                                        unsigned DestReg, int FrameIdx,
                                        const TargetRegisterClass *RC) const {
  //std::cerr << "Trying to load " << getPrettyName(DestReg) << " to " << FrameIdx << "\n";
  if (RC == Alpha::F4RCRegisterClass)
    BuildMI(MBB, MI, Alpha::LDS, 2, DestReg).addFrameIndex(FrameIdx).addReg(Alpha::F31);
  else if (RC == Alpha::F8RCRegisterClass)
    BuildMI(MBB, MI, Alpha::LDT, 2, DestReg).addFrameIndex(FrameIdx).addReg(Alpha::F31);
  else if (RC == Alpha::GPRCRegisterClass)
    BuildMI(MBB, MI, Alpha::LDQ, 2, DestReg).addFrameIndex(FrameIdx).addReg(Alpha::F31);
  else
    abort();
}

MachineInstr *AlphaRegisterInfo::foldMemoryOperand(MachineInstr *MI,
                                                 unsigned OpNum,
                                                 int FrameIndex) const {
   // Make sure this is a reg-reg copy.
   unsigned Opc = MI->getOpcode();

   switch(Opc) {
   default:
     break;
   case Alpha::BIS:
   case Alpha::CPYSS:
   case Alpha::CPYST:
     if (MI->getOperand(1).getReg() == MI->getOperand(2).getReg()) {
       if (OpNum == 0) {  // move -> store
	 unsigned InReg = MI->getOperand(1).getReg();
	 Opc = (Opc == Alpha::BIS) ? Alpha::STQ :
	   ((Opc == Alpha::CPYSS) ? Alpha::STS : Alpha::STT);
	 return BuildMI(Opc, 3).addReg(InReg).addFrameIndex(FrameIndex)
	   .addReg(Alpha::F31);
       } else {           // load -> move
	 unsigned OutReg = MI->getOperand(0).getReg();
	 Opc = (Opc == Alpha::BIS) ? Alpha::LDQ :
	   ((Opc == Alpha::CPYSS) ? Alpha::LDS : Alpha::LDT);
	 return BuildMI(Opc, 2, OutReg).addFrameIndex(FrameIndex)
	   .addReg(Alpha::F31);
       }
     }
     break;
   }
  return 0;
}

void AlphaRegisterInfo::copyRegToReg(MachineBasicBlock &MBB,
                                     MachineBasicBlock::iterator MI,
                                     unsigned DestReg, unsigned SrcReg,
                                     const TargetRegisterClass *RC) const {
  //  std::cerr << "copyRegToReg " << DestReg << " <- " << SrcReg << "\n";
  if (RC == Alpha::GPRCRegisterClass) {
    BuildMI(MBB, MI, Alpha::BIS, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
  } else if (RC == Alpha::F4RCRegisterClass) {
    BuildMI(MBB, MI, Alpha::CPYSS, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
  } else if (RC == Alpha::F8RCRegisterClass) {
    BuildMI(MBB, MI, Alpha::CPYST, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
  } else {
    std::cerr << "Attempt to copy register that is not GPR or FPR";
     abort();
  }
}

//===----------------------------------------------------------------------===//
// Stack Frame Processing methods
//===----------------------------------------------------------------------===//

// hasFP - Return true if the specified function should have a dedicated frame
// pointer register.  This is true if the function has variable sized allocas or
// if frame pointer elimination is disabled.
//
static bool hasFP(MachineFunction &MF) {
  MachineFrameInfo *MFI = MF.getFrameInfo();
  return MFI->hasVarSizedObjects();
}

void AlphaRegisterInfo::
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
                              MachineBasicBlock::iterator I) const {
  if (hasFP(MF)) {
    // If we have a frame pointer, turn the adjcallstackup instruction into a
    // 'sub ESP, <amt>' and the adjcallstackdown instruction into 'add ESP,
    // <amt>'
    MachineInstr *Old = I;
    unsigned Amount = Old->getOperand(0).getImmedValue();
    if (Amount != 0) {
      // We need to keep the stack aligned properly.  To do this, we round the
      // amount of space needed for the outgoing arguments up to the next
      // alignment boundary.
      unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
      Amount = (Amount+Align-1)/Align*Align;

      MachineInstr *New;
      if (Old->getOpcode() == Alpha::ADJUSTSTACKDOWN) {
         New=BuildMI(Alpha::LDA, 2, Alpha::R30)
          .addImm(-Amount).addReg(Alpha::R30);
      } else {
         assert(Old->getOpcode() == Alpha::ADJUSTSTACKUP);
         New=BuildMI(Alpha::LDA, 2, Alpha::R30)
          .addImm(Amount).addReg(Alpha::R30);
      }

      // Replace the pseudo instruction with a new instruction...
      MBB.insert(I, New);
    }
  }

  MBB.erase(I);
}

//Alpha has a slightly funny stack:
//Args
//<- incoming SP
//fixed locals (and spills, callee saved, etc)
//<- FP
//variable locals
//<- SP

void
AlphaRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II) const {
  unsigned i = 0;
  MachineInstr &MI = *II;
  MachineBasicBlock &MBB = *MI.getParent();
  MachineFunction &MF = *MBB.getParent();
  bool FP = hasFP(MF);

  while (!MI.getOperand(i).isFrameIndex()) {
    ++i;
    assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!");
  }

  int FrameIndex = MI.getOperand(i).getFrameIndex();

  // Add the base register of R30 (SP) or R15 (FP).
  MI.getOperand(i + 1).ChangeToRegister(FP ? Alpha::R15 : Alpha::R30);

  // Now add the frame object offset to the offset from the virtual frame index.
  int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex);

  DEBUG(std::cerr << "FI: " << FrameIndex << " Offset: " << Offset << "\n");

  Offset += MF.getFrameInfo()->getStackSize();

  DEBUG(std::cerr << "Corrected Offset " << Offset <<
        " for stack size: " << MF.getFrameInfo()->getStackSize() << "\n");

  if (Offset > IMM_HIGH || Offset < IMM_LOW) {
    DEBUG(std::cerr << "Unconditionally using R28 for evil purposes Offset: " << Offset << "\n");
    //so in this case, we need to use a temporary register, and move the original
    //inst off the SP/FP
    //fix up the old:
    MI.getOperand(i + 1).ChangeToRegister(Alpha::R28);
    MI.getOperand(i).ChangeToImmediate(getLower16(Offset));
    //insert the new
    MachineInstr* nMI=BuildMI(Alpha::LDAH, 2, Alpha::R28)
      .addImm(getUpper16(Offset)).addReg(FP ? Alpha::R15 : Alpha::R30);
    MBB.insert(II, nMI);
  } else {
    MI.getOperand(i).ChangeToImmediate(Offset);
  }
}

void AlphaRegisterInfo::emitPrologue(MachineFunction &MF) const {
  MachineBasicBlock &MBB = MF.front();   // Prolog goes in entry BB
  MachineBasicBlock::iterator MBBI = MBB.begin();
  MachineFrameInfo *MFI = MF.getFrameInfo();
  bool FP = hasFP(MF);

  static int curgpdist = 0;

  //handle GOP offset
  BuildMI(MBB, MBBI, Alpha::LDAHg, 3, Alpha::R29)
    .addGlobalAddress(const_cast<Function*>(MF.getFunction()))
    .addReg(Alpha::R27).addImm(++curgpdist);
  BuildMI(MBB, MBBI, Alpha::LDAg, 3, Alpha::R29)
    .addGlobalAddress(const_cast<Function*>(MF.getFunction()))
    .addReg(Alpha::R29).addImm(curgpdist);

  //evil const_cast until MO stuff setup to handle const
  BuildMI(MBB, MBBI, Alpha::ALTENT, 1)
    .addGlobalAddress(const_cast<Function*>(MF.getFunction()));

  // Get the number of bytes to allocate from the FrameInfo
  long NumBytes = MFI->getStackSize();

  if (MFI->hasCalls() && !FP) {
    // We reserve argument space for call sites in the function immediately on
    // entry to the current function.  This eliminates the need for add/sub
    // brackets around call sites.
    //If there is a frame pointer, then we don't do this
    NumBytes += MFI->getMaxCallFrameSize();
    DEBUG(std::cerr << "Added " << MFI->getMaxCallFrameSize()
          << " to the stack due to calls\n");
  }

  if (FP)
    NumBytes += 8; //reserve space for the old FP

  // Do we need to allocate space on the stack?
  if (NumBytes == 0) return;

  unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
  NumBytes = (NumBytes+Align-1)/Align*Align;

  // Update frame info to pretend that this is part of the stack...
  MFI->setStackSize(NumBytes);

  // adjust stack pointer: r30 -= numbytes
  NumBytes = -NumBytes;
  if (NumBytes >= IMM_LOW) {
    BuildMI(MBB, MBBI, Alpha::LDA, 2, Alpha::R30).addImm(NumBytes)
      .addReg(Alpha::R30);
  } else if (getUpper16(NumBytes) >= IMM_LOW) {
    BuildMI(MBB, MBBI, Alpha::LDAH, 2, Alpha::R30).addImm(getUpper16(NumBytes))
      .addReg(Alpha::R30);
    BuildMI(MBB, MBBI, Alpha::LDA, 2, Alpha::R30).addImm(getLower16(NumBytes))
      .addReg(Alpha::R30);
  } else {
    std::cerr << "Too big a stack frame at " << NumBytes << "\n";
    abort();
  }

  //now if we need to, save the old FP and set the new
  if (FP)
  {
    BuildMI(MBB, MBBI, Alpha::STQ, 3).addReg(Alpha::R15).addImm(0).addReg(Alpha::R30);
    //this must be the last instr in the prolog
    BuildMI(MBB, MBBI, Alpha::BIS, 2, Alpha::R15).addReg(Alpha::R30).addReg(Alpha::R30);
  }

}

void AlphaRegisterInfo::emitEpilogue(MachineFunction &MF,
                                     MachineBasicBlock &MBB) const {
  const MachineFrameInfo *MFI = MF.getFrameInfo();
  MachineBasicBlock::iterator MBBI = prior(MBB.end());
  assert(MBBI->getOpcode() == Alpha::RETDAG
         && "Can only insert epilog into returning blocks");

  bool FP = hasFP(MF);

  // Get the number of bytes allocated from the FrameInfo...
  long NumBytes = MFI->getStackSize();

  //now if we need to, restore the old FP
  if (FP)
  {
    //copy the FP into the SP (discards allocas)
    BuildMI(MBB, MBBI, Alpha::BIS, 2, Alpha::R30).addReg(Alpha::R15)
      .addReg(Alpha::R15);
    //restore the FP
    BuildMI(MBB, MBBI, Alpha::LDQ, 2, Alpha::R15).addImm(0).addReg(Alpha::R15);
  }

   if (NumBytes != 0)
     {
       if (NumBytes <= IMM_HIGH) {
         BuildMI(MBB, MBBI, Alpha::LDA, 2, Alpha::R30).addImm(NumBytes)
           .addReg(Alpha::R30);
       } else if (getUpper16(NumBytes) <= IMM_HIGH) {
         BuildMI(MBB, MBBI, Alpha::LDAH, 2, Alpha::R30)
           .addImm(getUpper16(NumBytes)).addReg(Alpha::R30);
         BuildMI(MBB, MBBI, Alpha::LDA, 2, Alpha::R30)
           .addImm(getLower16(NumBytes)).addReg(Alpha::R30);
       } else {
         std::cerr << "Too big a stack frame at " << NumBytes << "\n";
         abort();
       }
     }
}

unsigned AlphaRegisterInfo::getRARegister() const {
  assert(0 && "What is the return address register");
  return 0;
}

unsigned AlphaRegisterInfo::getFrameRegister(MachineFunction &MF) const {
  return hasFP(MF) ? Alpha::R15 : Alpha::R30;
}

#include "AlphaGenRegisterInfo.inc"

std::string AlphaRegisterInfo::getPrettyName(unsigned reg)
{
  std::string s(RegisterDescriptors[reg].Name);
  return s;
}
<commit_msg>Fix call_adj.ll<commit_after>//===- AlphaRegisterInfo.cpp - Alpha Register Information -------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Alpha implementation of the MRegisterInfo class.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "reginfo"
#include "Alpha.h"
#include "AlphaRegisterInfo.h"
#include "llvm/Constants.h"
#include "llvm/Type.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineLocation.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/STLExtras.h"
#include <cstdlib>
#include <iostream>
using namespace llvm;

//These describe LDAx
static const int IMM_LOW  = -32768;
static const int IMM_HIGH = 32767;
static const int IMM_MULT = 65536;

static long getUpper16(long l)
{
  long y = l / IMM_MULT;
  if (l % IMM_MULT > IMM_HIGH)
    ++y;
  return y;
}

static long getLower16(long l)
{
  long h = getUpper16(l);
  return l - h * IMM_MULT;
}

static int getUID()
{
  static int id = 0;
  return ++id;
}

AlphaRegisterInfo::AlphaRegisterInfo()
  : AlphaGenRegisterInfo(Alpha::ADJUSTSTACKDOWN, Alpha::ADJUSTSTACKUP)
{
}

void
AlphaRegisterInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
                                       MachineBasicBlock::iterator MI,
                                       unsigned SrcReg, int FrameIdx,
                                       const TargetRegisterClass *RC) const {
  //std::cerr << "Trying to store " << getPrettyName(SrcReg) << " to " << FrameIdx << "\n";
  //BuildMI(MBB, MI, Alpha::WTF, 0).addReg(SrcReg);
  if (RC == Alpha::F4RCRegisterClass)
    BuildMI(MBB, MI, Alpha::STS, 3).addReg(SrcReg).addFrameIndex(FrameIdx).addReg(Alpha::F31);
  else if (RC == Alpha::F8RCRegisterClass)
    BuildMI(MBB, MI, Alpha::STT, 3).addReg(SrcReg).addFrameIndex(FrameIdx).addReg(Alpha::F31);
  else if (RC == Alpha::GPRCRegisterClass)
    BuildMI(MBB, MI, Alpha::STQ, 3).addReg(SrcReg).addFrameIndex(FrameIdx).addReg(Alpha::F31);
  else
    abort();
}

void
AlphaRegisterInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
                                        MachineBasicBlock::iterator MI,
                                        unsigned DestReg, int FrameIdx,
                                        const TargetRegisterClass *RC) const {
  //std::cerr << "Trying to load " << getPrettyName(DestReg) << " to " << FrameIdx << "\n";
  if (RC == Alpha::F4RCRegisterClass)
    BuildMI(MBB, MI, Alpha::LDS, 2, DestReg).addFrameIndex(FrameIdx).addReg(Alpha::F31);
  else if (RC == Alpha::F8RCRegisterClass)
    BuildMI(MBB, MI, Alpha::LDT, 2, DestReg).addFrameIndex(FrameIdx).addReg(Alpha::F31);
  else if (RC == Alpha::GPRCRegisterClass)
    BuildMI(MBB, MI, Alpha::LDQ, 2, DestReg).addFrameIndex(FrameIdx).addReg(Alpha::F31);
  else
    abort();
}

MachineInstr *AlphaRegisterInfo::foldMemoryOperand(MachineInstr *MI,
                                                 unsigned OpNum,
                                                 int FrameIndex) const {
   // Make sure this is a reg-reg copy.
   unsigned Opc = MI->getOpcode();

   switch(Opc) {
   default:
     break;
   case Alpha::BIS:
   case Alpha::CPYSS:
   case Alpha::CPYST:
     if (MI->getOperand(1).getReg() == MI->getOperand(2).getReg()) {
       if (OpNum == 0) {  // move -> store
	 unsigned InReg = MI->getOperand(1).getReg();
	 Opc = (Opc == Alpha::BIS) ? Alpha::STQ :
	   ((Opc == Alpha::CPYSS) ? Alpha::STS : Alpha::STT);
	 return BuildMI(Opc, 3).addReg(InReg).addFrameIndex(FrameIndex)
	   .addReg(Alpha::F31);
       } else {           // load -> move
	 unsigned OutReg = MI->getOperand(0).getReg();
	 Opc = (Opc == Alpha::BIS) ? Alpha::LDQ :
	   ((Opc == Alpha::CPYSS) ? Alpha::LDS : Alpha::LDT);
	 return BuildMI(Opc, 2, OutReg).addFrameIndex(FrameIndex)
	   .addReg(Alpha::F31);
       }
     }
     break;
   }
  return 0;
}

void AlphaRegisterInfo::copyRegToReg(MachineBasicBlock &MBB,
                                     MachineBasicBlock::iterator MI,
                                     unsigned DestReg, unsigned SrcReg,
                                     const TargetRegisterClass *RC) const {
  //  std::cerr << "copyRegToReg " << DestReg << " <- " << SrcReg << "\n";
  if (RC == Alpha::GPRCRegisterClass) {
    BuildMI(MBB, MI, Alpha::BIS, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
  } else if (RC == Alpha::F4RCRegisterClass) {
    BuildMI(MBB, MI, Alpha::CPYSS, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
  } else if (RC == Alpha::F8RCRegisterClass) {
    BuildMI(MBB, MI, Alpha::CPYST, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
  } else {
    std::cerr << "Attempt to copy register that is not GPR or FPR";
     abort();
  }
}

//===----------------------------------------------------------------------===//
// Stack Frame Processing methods
//===----------------------------------------------------------------------===//

// hasFP - Return true if the specified function should have a dedicated frame
// pointer register.  This is true if the function has variable sized allocas or
// if frame pointer elimination is disabled.
//
static bool hasFP(MachineFunction &MF) {
  MachineFrameInfo *MFI = MF.getFrameInfo();
  return MFI->hasVarSizedObjects();
}

void AlphaRegisterInfo::
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
                              MachineBasicBlock::iterator I) const {
  if (hasFP(MF)) {
    // If we have a frame pointer, turn the adjcallstackup instruction into a
    // 'sub ESP, <amt>' and the adjcallstackdown instruction into 'add ESP,
    // <amt>'
    MachineInstr *Old = I;
    uint64_t Amount = Old->getOperand(0).getImmedValue();
    if (Amount != 0) {
      // We need to keep the stack aligned properly.  To do this, we round the
      // amount of space needed for the outgoing arguments up to the next
      // alignment boundary.
      unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
      Amount = (Amount+Align-1)/Align*Align;

      MachineInstr *New;
      if (Old->getOpcode() == Alpha::ADJUSTSTACKDOWN) {
         New=BuildMI(Alpha::LDA, 2, Alpha::R30)
          .addImm(-Amount).addReg(Alpha::R30);
      } else {
         assert(Old->getOpcode() == Alpha::ADJUSTSTACKUP);
         New=BuildMI(Alpha::LDA, 2, Alpha::R30)
          .addImm(Amount).addReg(Alpha::R30);
      }

      // Replace the pseudo instruction with a new instruction...
      MBB.insert(I, New);
    }
  }

  MBB.erase(I);
}

//Alpha has a slightly funny stack:
//Args
//<- incoming SP
//fixed locals (and spills, callee saved, etc)
//<- FP
//variable locals
//<- SP

void
AlphaRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II) const {
  unsigned i = 0;
  MachineInstr &MI = *II;
  MachineBasicBlock &MBB = *MI.getParent();
  MachineFunction &MF = *MBB.getParent();
  bool FP = hasFP(MF);

  while (!MI.getOperand(i).isFrameIndex()) {
    ++i;
    assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!");
  }

  int FrameIndex = MI.getOperand(i).getFrameIndex();

  // Add the base register of R30 (SP) or R15 (FP).
  MI.getOperand(i + 1).ChangeToRegister(FP ? Alpha::R15 : Alpha::R30);

  // Now add the frame object offset to the offset from the virtual frame index.
  int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex);

  DEBUG(std::cerr << "FI: " << FrameIndex << " Offset: " << Offset << "\n");

  Offset += MF.getFrameInfo()->getStackSize();

  DEBUG(std::cerr << "Corrected Offset " << Offset <<
        " for stack size: " << MF.getFrameInfo()->getStackSize() << "\n");

  if (Offset > IMM_HIGH || Offset < IMM_LOW) {
    DEBUG(std::cerr << "Unconditionally using R28 for evil purposes Offset: " << Offset << "\n");
    //so in this case, we need to use a temporary register, and move the original
    //inst off the SP/FP
    //fix up the old:
    MI.getOperand(i + 1).ChangeToRegister(Alpha::R28);
    MI.getOperand(i).ChangeToImmediate(getLower16(Offset));
    //insert the new
    MachineInstr* nMI=BuildMI(Alpha::LDAH, 2, Alpha::R28)
      .addImm(getUpper16(Offset)).addReg(FP ? Alpha::R15 : Alpha::R30);
    MBB.insert(II, nMI);
  } else {
    MI.getOperand(i).ChangeToImmediate(Offset);
  }
}

void AlphaRegisterInfo::emitPrologue(MachineFunction &MF) const {
  MachineBasicBlock &MBB = MF.front();   // Prolog goes in entry BB
  MachineBasicBlock::iterator MBBI = MBB.begin();
  MachineFrameInfo *MFI = MF.getFrameInfo();
  bool FP = hasFP(MF);

  static int curgpdist = 0;

  //handle GOP offset
  BuildMI(MBB, MBBI, Alpha::LDAHg, 3, Alpha::R29)
    .addGlobalAddress(const_cast<Function*>(MF.getFunction()))
    .addReg(Alpha::R27).addImm(++curgpdist);
  BuildMI(MBB, MBBI, Alpha::LDAg, 3, Alpha::R29)
    .addGlobalAddress(const_cast<Function*>(MF.getFunction()))
    .addReg(Alpha::R29).addImm(curgpdist);

  //evil const_cast until MO stuff setup to handle const
  BuildMI(MBB, MBBI, Alpha::ALTENT, 1)
    .addGlobalAddress(const_cast<Function*>(MF.getFunction()));

  // Get the number of bytes to allocate from the FrameInfo
  long NumBytes = MFI->getStackSize();

  if (MFI->hasCalls() && !FP) {
    // We reserve argument space for call sites in the function immediately on
    // entry to the current function.  This eliminates the need for add/sub
    // brackets around call sites.
    //If there is a frame pointer, then we don't do this
    NumBytes += MFI->getMaxCallFrameSize();
    DEBUG(std::cerr << "Added " << MFI->getMaxCallFrameSize()
          << " to the stack due to calls\n");
  }

  if (FP)
    NumBytes += 8; //reserve space for the old FP

  // Do we need to allocate space on the stack?
  if (NumBytes == 0) return;

  unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
  NumBytes = (NumBytes+Align-1)/Align*Align;

  // Update frame info to pretend that this is part of the stack...
  MFI->setStackSize(NumBytes);

  // adjust stack pointer: r30 -= numbytes
  NumBytes = -NumBytes;
  if (NumBytes >= IMM_LOW) {
    BuildMI(MBB, MBBI, Alpha::LDA, 2, Alpha::R30).addImm(NumBytes)
      .addReg(Alpha::R30);
  } else if (getUpper16(NumBytes) >= IMM_LOW) {
    BuildMI(MBB, MBBI, Alpha::LDAH, 2, Alpha::R30).addImm(getUpper16(NumBytes))
      .addReg(Alpha::R30);
    BuildMI(MBB, MBBI, Alpha::LDA, 2, Alpha::R30).addImm(getLower16(NumBytes))
      .addReg(Alpha::R30);
  } else {
    std::cerr << "Too big a stack frame at " << NumBytes << "\n";
    abort();
  }

  //now if we need to, save the old FP and set the new
  if (FP)
  {
    BuildMI(MBB, MBBI, Alpha::STQ, 3).addReg(Alpha::R15).addImm(0).addReg(Alpha::R30);
    //this must be the last instr in the prolog
    BuildMI(MBB, MBBI, Alpha::BIS, 2, Alpha::R15).addReg(Alpha::R30).addReg(Alpha::R30);
  }

}

void AlphaRegisterInfo::emitEpilogue(MachineFunction &MF,
                                     MachineBasicBlock &MBB) const {
  const MachineFrameInfo *MFI = MF.getFrameInfo();
  MachineBasicBlock::iterator MBBI = prior(MBB.end());
  assert(MBBI->getOpcode() == Alpha::RETDAG
         && "Can only insert epilog into returning blocks");

  bool FP = hasFP(MF);

  // Get the number of bytes allocated from the FrameInfo...
  long NumBytes = MFI->getStackSize();

  //now if we need to, restore the old FP
  if (FP)
  {
    //copy the FP into the SP (discards allocas)
    BuildMI(MBB, MBBI, Alpha::BIS, 2, Alpha::R30).addReg(Alpha::R15)
      .addReg(Alpha::R15);
    //restore the FP
    BuildMI(MBB, MBBI, Alpha::LDQ, 2, Alpha::R15).addImm(0).addReg(Alpha::R15);
  }

   if (NumBytes != 0)
     {
       if (NumBytes <= IMM_HIGH) {
         BuildMI(MBB, MBBI, Alpha::LDA, 2, Alpha::R30).addImm(NumBytes)
           .addReg(Alpha::R30);
       } else if (getUpper16(NumBytes) <= IMM_HIGH) {
         BuildMI(MBB, MBBI, Alpha::LDAH, 2, Alpha::R30)
           .addImm(getUpper16(NumBytes)).addReg(Alpha::R30);
         BuildMI(MBB, MBBI, Alpha::LDA, 2, Alpha::R30)
           .addImm(getLower16(NumBytes)).addReg(Alpha::R30);
       } else {
         std::cerr << "Too big a stack frame at " << NumBytes << "\n";
         abort();
       }
     }
}

unsigned AlphaRegisterInfo::getRARegister() const {
  assert(0 && "What is the return address register");
  return 0;
}

unsigned AlphaRegisterInfo::getFrameRegister(MachineFunction &MF) const {
  return hasFP(MF) ? Alpha::R15 : Alpha::R30;
}

#include "AlphaGenRegisterInfo.inc"

std::string AlphaRegisterInfo::getPrettyName(unsigned reg)
{
  std::string s(RegisterDescriptors[reg].Name);
  return s;
}
<|endoftext|>


<commit_before>#include <string>
#include <stdexcept>
#include <cassert>
namespace workspace {

class Amount {
public:
	Amount(const int value) : value_(value) {}

private:
	const int value_;
};

class Currency {
public:
	Currency(const std::string& value) : value_(value) {}

private:
	const std::string value_;
};

class Money {
public:
	static Money create(const int amount, const std::string& currency) {
		return Money(Amount(amount), Currency(currency));
	}

private:
    Money(const Amount& amount, const Currency& currency)
        : amount_(amount), currency_(currency) {}

    const Amount amount_;
    const Currency currency_;
};

class Product {
public:
    Product(const Money& money) : money_(money) {}

private:
    Money money_;
};

class Converter {
public:
    Money convert(const Money& money) const {
        return Money::create(100, "EUR");
    }
};

void run() {
    {
        Money::create(100, "USD");
    }

    {
        Product(Money::create(100, "USD"));
    }

    {
        Converter().convert(Money::create(100, "USD"));
    }
}

} // workspace

int main() {
    workspace::run();
    return 0;
}
<commit_msg>[m_noback-object_design_style_guide][ch 03] slighlty change the 1-st example for creating new objects for composite values<commit_after>#include <string>
#include <stdexcept>
#include <cassert>
namespace workspace {

class Amount {
public:
	Amount(const int value) : value_(value) {}

private:
	const int value_;
};

class Currency {
public:
	Currency(const std::string& value) : value_(value) {}

private:
	const std::string value_;
};

class Money {
public:
	static Money create(const int amount, const std::string& currency) {
		return Money(Amount(amount), Currency(currency));
	}

private:
    Money(const Amount& amount, const Currency& currency)
        : amount_(amount), currency_(currency) {}

    const Amount amount_;
    const Currency currency_;
};

class Product {
public:
    Product(const Money& money) : money_(money) {}

private:
    Money money_;
};

class Converter {
public:
    Money convert(const Money& money) const {
        return Money::create(100, "EUR");
    }
};

void run() {
    {
        Money::create(100, "USD");
    }

    {
        Product(Money::create(100, "USD"));
    }

    {
        Converter().convert(Money::create(100, "USD"));
    }
}

} // workspace

int main() {
    workspace::run();

    return 0;
}
<|endoftext|>


<commit_before>#ifndef _SDD_HOM_SUM_HH_
#define _SDD_HOM_SUM_HH_

#include <algorithm>  // all_of, equal
#include <initializer_list>

#include <boost/container/flat_set.hpp>

#include "sdd/dd/definition.hh"
#include "sdd/hom/context_fwd.hh"
#include "sdd/hom/definition_fwd.hh"
#include "sdd/hom/identity.hh"

namespace sdd { namespace hom {

/*-------------------------------------------------------------------------------------------*/

/// @cond INTERNAL_DOC

/// @brief Sum homomorphism.
template <typename C>
class sum
{
public:

  /// @brief The set of homomorphism operands
  typedef boost::container::flat_set<homomorphism<C>> operands_type;

private:

  const operands_type operands_;

public:

  /// @brief Constructor.
  sum(operands_type&& operands)
    : operands_(std::move(operands))
  {
  }

  /// @brief Evaluation.
  SDD<C>
  operator()(context<C>& cxt, const SDD<C>& x)
  const
  {
    sum_builder<C, SDD<C>> sum_operands(operands_.size());
    for (const auto& op : operands_)
    {
      sum_operands.add(op(cxt, x));
    }
    return sdd::sum(cxt.sdd_context(), std::move(sum_operands));
  }

  /// @brief Skip variable predicate.
  bool
  skip(const typename C::Variable& v)
  const noexcept
  {
    return std::all_of( operands_.begin(), operands_.end()
                      , [&](const homomorphism<C>& h){return h.skip(v);});
  }

  const operands_type&
  operands()
  const noexcept
  {
    return operands_;
  }
};

/*-------------------------------------------------------------------------------------------*/

/// @brief Equality of two Sum homomorphisms.
/// @related Sum
template <typename C>
inline
bool
operator==(const sum<C>& lhs, const sum<C>& rhs)
noexcept
{
  return lhs.operands().size() == rhs.operands().size()
     and std::equal(lhs.operands().begin(), lhs.operands().end(), rhs.operands().begin());
}

/// @endcond

/*-------------------------------------------------------------------------------------------*/

/// @brief Create the Sum homomorphism.
/// @related homomorphism
template <typename C, typename InputIterator>
homomorphism<C>
Sum(InputIterator begin, InputIterator end)
{
  const std::size_t size = std::distance(begin, end);

  if (size == 0)
  {
    return Id<C>();
  }

  typename sum<C>::operands_type operands;
  operands.reserve(size);

  for (; begin != end; ++begin)
  {
    operands.insert(*begin);
  }

  if (operands.size() == 1)
  {
    return *operands.begin();
  }
  else
  {
    return homomorphism<C>::create(internal::mem::construct<sum<C>>(), std::move(operands));
  }
}

/*-------------------------------------------------------------------------------------------*/

/// @brief Create the Sum homomorphism.
/// @related homomorphism
template <typename C>
homomorphism<C>
Sum(std::initializer_list<homomorphism<C>> operands)
{
  return Sum<C>(operands.begin(), operands.end());
}

/*-------------------------------------------------------------------------------------------*/

}} // namespace sdd::hom

namespace std {

/*-------------------------------------------------------------------------------------------*/

/// @cond INTERNAL_DOC

/// @brief Hash specialization for sdd::hom::sum.
template <typename C>
struct hash<sdd::hom::sum<C>>
{
  std::size_t
  operator()(const sdd::hom::sum<C>& s)
  const noexcept
  {
    std::size_t seed = 0;
    for (const auto& op : s.operands())
    {
      sdd::internal::util::hash_combine(seed, op);
    }
    return seed;
  }
};

/// @endcond

/*-------------------------------------------------------------------------------------------*/

} // namespace std

#endif // _SDD_HOM_SUM_HH_
<commit_msg>Optimize sum at creation.<commit_after>#ifndef _SDD_HOM_SUM_HH_
#define _SDD_HOM_SUM_HH_

#include <algorithm>  // all_of, copy, equal
#include <initializer_list>
#include <iosfwd>
#include <unordered_map>
#include <vector>

#include <boost/container/flat_set.hpp>

#include "sdd/dd/definition.hh"
#include "sdd/hom/context_fwd.hh"
#include "sdd/hom/definition_fwd.hh"
#include "sdd/hom/identity.hh"
#include "sdd/hom/local.hh"

namespace sdd { namespace hom {

/*-------------------------------------------------------------------------------------------*/

/// @cond INTERNAL_DOC

/// @brief Sum homomorphism.
template <typename C>
class sum
{
public:

  /// @brief The set of homomorphism operands
  typedef boost::container::flat_set<homomorphism<C>> operands_type;

private:

  const operands_type operands_;

public:

  /// @brief Constructor.
  sum(operands_type&& operands)
    : operands_(std::move(operands))
  {
  }

  /// @brief Evaluation.
  SDD<C>
  operator()(context<C>& cxt, const SDD<C>& x)
  const
  {
    sum_builder<C, SDD<C>> sum_operands(operands_.size());
    for (const auto& op : operands_)
    {
      sum_operands.add(op(cxt, x));
    }
    return sdd::sum(cxt.sdd_context(), std::move(sum_operands));
  }

  /// @brief Skip variable predicate.
  bool
  skip(const typename C::Variable& v)
  const noexcept
  {
    return std::all_of( operands_.begin(), operands_.end()
                      , [&](const homomorphism<C>& h){return h.skip(v);});
  }

  const operands_type&
  operands()
  const noexcept
  {
    return operands_;
  }
};

/*-------------------------------------------------------------------------------------------*/

/// @brief Equality of two sum.
/// @related sum
template <typename C>
inline
bool
operator==(const sum<C>& lhs, const sum<C>& rhs)
noexcept
{
  return lhs.operands().size() == rhs.operands().size()
     and std::equal(lhs.operands().begin(), lhs.operands().end(), rhs.operands().begin());
}

/// @related sum
template <typename C>
std::ostream&
operator<<(std::ostream& os, const sum<C>& s)
{
  os << "(";
  std::copy( s.operands().begin(), std::prev(s.operands().end())
           , std::ostream_iterator<homomorphism<C>>(os, " + "));
  return os << *std::prev(s.operands().end()) << ")";
}

/*-------------------------------------------------------------------------------------------*/

/// @brief Help optimize an union's operands.
template <typename C>
struct sum_builder_helper
{
  typedef void result_type;
  typedef typename sum<C>::operands_type operands_type;
  typedef std::vector<homomorphism<C>> hom_list_type;
  typedef std::unordered_map<typename C::Variable, hom_list_type> locals_type;

  /// @brief Flatten nested sums.
  void
  operator()( const sum<C>& s
            , const homomorphism<C>& h, operands_type& operands, locals_type& locals)
  const
  {
    for (const auto& op : s.operands())
    {
      apply_visitor(*this, op->data(), op, operands, locals);
    }
  }

  /// @brief Regroup locals.
  void
  operator()( const local<C>& l
            , const homomorphism<C>& h, operands_type& operands, locals_type& locals)
  const
  {
    auto insertion = locals.emplace(l.variable(), hom_list_type());
    insertion.first->second.emplace_back(l.hom());
  }

  /// @brief Insert normally all other operands.
  template <typename T>
  void
  operator()(const T&, const homomorphism<C>& h, operands_type& operands, locals_type&)
  const
  {
    operands.insert(h);
  }

};

/// @endcond

/*-------------------------------------------------------------------------------------------*/

/// @brief Create the Sum homomorphism.
/// @related homomorphism
template <typename C, typename InputIterator>
homomorphism<C>
Sum(InputIterator begin, InputIterator end)
{
  const std::size_t size = std::distance(begin, end);

  if (size == 0)
  {
    return Id<C>();
  }

  typename sum<C>::operands_type operands;
  operands.reserve(size);

  sum_builder_helper<C> sbv;
  typename sum_builder_helper<C>::locals_type locals;
  for (; begin != end; ++begin)
  {
    apply_visitor(sbv, (*begin)->data(), *begin, operands, locals);
  }

  // insert remaining locals
  for (const auto& l : locals)
  {
    operands.insert(Local<C>(l.first, Sum<C>(l.second.begin(), l.second.end())));
  }

  if (operands.size() == 1)
  {
    return *operands.begin();
  }
  else
  {
    operands.shrink_to_fit();
    return homomorphism<C>::create(internal::mem::construct<sum<C>>(), std::move(operands));
  }
}

/*-------------------------------------------------------------------------------------------*/

/// @brief Create the Sum homomorphism.
/// @related homomorphism
template <typename C>
homomorphism<C>
Sum(std::initializer_list<homomorphism<C>> operands)
{
  return Sum<C>(operands.begin(), operands.end());
}

/*-------------------------------------------------------------------------------------------*/

}} // namespace sdd::hom

namespace std {

/*-------------------------------------------------------------------------------------------*/

/// @cond INTERNAL_DOC

/// @brief Hash specialization for sdd::hom::sum.
template <typename C>
struct hash<sdd::hom::sum<C>>
{
  std::size_t
  operator()(const sdd::hom::sum<C>& s)
  const noexcept
  {
    std::size_t seed = 0;
    for (const auto& op : s.operands())
    {
      sdd::internal::util::hash_combine(seed, op);
    }
    return seed;
  }
};

/// @endcond

/*-------------------------------------------------------------------------------------------*/

} // namespace std

#endif // _SDD_HOM_SUM_HH_
<|endoftext|>