<commit_before>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

//
// Code that is used by both the Unix corerun and coreconsole.
//

#include <cstdlib>
#include <assert.h>
#include <dirent.h>
#include <dlfcn.h>
#include <limits.h>
#include <set>
#include <string>
#include <string.h>
#include <sys/stat.h>
#include "coreruncommon.h"
#include <unistd.h>

#define SUCCEEDED(Status) ((Status) >= 0)

// Name of the environment variable controlling server GC.
// If set to 1, server GC is enabled on startup. If 0, server GC is
// disabled. Server GC is off by default.
static const char* serverGcVar = "CORECLR_SERVER_GC";

// Name of the environment variable controlling concurrent GC,
// used in the same way as serverGcVar. Concurrent GC is on by default.
static const char* concurrentGcVar = "CORECLR_CONCURRENT_GC";

// Prototype of the coreclr_initialize function from the libcoreclr.so
typedef int (*InitializeCoreCLRFunction)(
            const char* exePath,
            const char* appDomainFriendlyName,
            int propertyCount,
            const char** propertyKeys,
            const char** propertyValues,
            void** hostHandle,
            unsigned int* domainId);

// Prototype of the coreclr_shutdown function from the libcoreclr.so
typedef int (*ShutdownCoreCLRFunction)(
            void* hostHandle,
            unsigned int domainId);

// Prototype of the coreclr_execute_assembly function from the libcoreclr.so
typedef int (*ExecuteAssemblyFunction)(
            void* hostHandle,
            unsigned int domainId,
            int argc,
            const char** argv,
            const char* managedAssemblyPath,
            unsigned int* exitCode);

#if defined(__LINUX__)
#define symlinkEntrypointExecutable "/proc/self/exe"
#elif !defined(__APPLE__)
#define symlinkEntrypointExecutable "/proc/curproc/exe"
#endif

bool GetEntrypointExecutableAbsolutePath(std::string& entrypointExecutable)
{
    bool result = false;

    entrypointExecutable.clear();

    // Get path to the executable for the current process using
    // platform specific means.
#if defined(__LINUX__)
    // On Linux, fetch the entry point EXE absolute path, inclusive of filename.
    char exe[PATH_MAX];
    ssize_t res = readlink(symlinkEntrypointExecutable, exe, PATH_MAX - 1);
    if (res != -1)
    {
        exe[res] = '\0';
        entrypointExecutable.assign(exe);
        result = true;
    }
    else
    {
        result = false;
    }
#elif defined(__APPLE__)

    // On Mac, we ask the OS for the absolute path to the entrypoint executable
    uint32_t lenActualPath = 0;
    if (_NSGetExecutablePath(nullptr, &lenActualPath) == -1)
    {
        // OSX has placed the actual path length in lenActualPath,
        // so re-attempt the operation
        std::string resizedPath(lenActualPath, '\0');
        char *pResizedPath = const_cast<char *>(resizedPath.c_str());
        if (_NSGetExecutablePath(pResizedPath, &lenActualPath) == 0)
        {
            entrypointExecutable.assign(pResizedPath);
            result = true;
        }
    }
#else
    // On non-Mac OS, return the symlink that will be resolved by GetAbsolutePath
    // to fetch the entrypoint EXE absolute path, inclusive of filename.
    entrypointExecutable.assign(symlinkEntrypointExecutable);
    result = true;
#endif

    return result;
}

bool GetAbsolutePath(const char* path, std::string& absolutePath)
{
    bool result = false;

    char realPath[PATH_MAX];
    if (realpath(path, realPath) != nullptr && realPath[0] != '\0')
    {
        absolutePath.assign(realPath);
        // realpath should return canonicalized path without the trailing slash
        assert(absolutePath.back() != '/');

        result = true;
    }

    return result;
}

bool GetDirectory(const char* absolutePath, std::string& directory)
{
    directory.assign(absolutePath);
    size_t lastSlash = directory.rfind('/');
    if (lastSlash != std::string::npos)
    {
        directory.erase(lastSlash);
        return true;
    }

    return false;
}

bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath)
{
    std::string clrFilesRelativePath;
    const char* clrFilesPathLocal = clrFilesPath;
    if (clrFilesPathLocal == nullptr)
    {
        // There was no CLR files path specified, use the folder of the corerun/coreconsole
        if (!GetDirectory(currentExePath, clrFilesRelativePath))
        {
            perror("Failed to get directory from argv[0]");
            return false;
        }

        clrFilesPathLocal = clrFilesRelativePath.c_str();

        // TODO: consider using an env variable (if defined) as a fall-back.
        // The windows version of the corerun uses core_root env variable
    }

    if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath))
    {
        perror("Failed to convert CLR files path to absolute path");
        return false;
    }

    return true;
}

void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList)
{
    const char * const tpaExtensions[] = {
                ".ni.dll",      // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir
                ".dll",
                ".ni.exe",
                ".exe",
                };

    DIR* dir = opendir(directory);
    if (dir == nullptr)
    {
        return;
    }

    std::set<std::string> addedAssemblies;

    // Walk the directory for each extension separately so that we first get files with .ni.dll extension,
    // then files with .dll extension, etc.
    for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++)
    {
        const char* ext = tpaExtensions[extIndex];
        int extLength = strlen(ext);

        struct dirent* entry;

        // For all entries in the directory
        while ((entry = readdir(dir)) != nullptr)
        {
            // We are interested in files only
            switch (entry->d_type)
            {
            case DT_REG:
                break;

            // Handle symlinks and file systems that do not support d_type
            case DT_LNK:
            case DT_UNKNOWN:
                {
                    std::string fullFilename;

                    fullFilename.append(directory);
                    fullFilename.append("/");
                    fullFilename.append(entry->d_name);

                    struct stat sb;
                    if (stat(fullFilename.c_str(), &sb) == -1)
                    {
                        continue;
                    }

                    if (!S_ISREG(sb.st_mode))
                    {
                        continue;
                    }
                }
                break;

            default:
                continue;
            }

            std::string filename(entry->d_name);

            // Check if the extension matches the one we are looking for
            int extPos = filename.length() - extLength;
            if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0))
            {
                continue;
            }

            std::string filenameWithoutExt(filename.substr(0, extPos));

            // Make sure if we have an assembly with multiple extensions present,
            // we insert only one version of it.
            if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end())
            {
                addedAssemblies.insert(filenameWithoutExt);

                tpaList.append(directory);
                tpaList.append("/");
                tpaList.append(filename);
                tpaList.append(":");
            }
        }

        // Rewind the directory stream to be able to iterate over it for the next extension
        rewinddir(dir);
    }

    closedir(dir);
}

int ExecuteManagedAssembly(
            const char* currentExeAbsolutePath,
            const char* clrFilesAbsolutePath,
            const char* managedAssemblyAbsolutePath,
            int managedAssemblyArgc,
            const char** managedAssemblyArgv)
{
    // Indicates failure
    int exitCode = -1;

    std::string coreClrDllPath(clrFilesAbsolutePath);
    coreClrDllPath.append("/");
    coreClrDllPath.append(coreClrDll);

    if (coreClrDllPath.length() >= PATH_MAX)
    {
        fprintf(stderr, "Absolute path to libcoreclr.so too long\n");
        return -1;
    }

    // Get just the path component of the managed assembly path
    std::string appPath;
    GetDirectory(managedAssemblyAbsolutePath, appPath);

    std::string nativeDllSearchDirs(appPath);
    nativeDllSearchDirs.append(":");
    nativeDllSearchDirs.append(clrFilesAbsolutePath);

    std::string tpaList;
    AddFilesFromDirectoryToTpaList(clrFilesAbsolutePath, tpaList);

    void* coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW | RTLD_LOCAL);
    if (coreclrLib != nullptr)
    {
        InitializeCoreCLRFunction initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib, "coreclr_initialize");
        ExecuteAssemblyFunction executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib, "coreclr_execute_assembly");
        ShutdownCoreCLRFunction shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib, "coreclr_shutdown");

        if (initializeCoreCLR == nullptr)
        {
            fprintf(stderr, "Function coreclr_initialize not found in the libcoreclr.so\n");
        }
        else if (executeAssembly == nullptr)
        {
            fprintf(stderr, "Function coreclr_execute_assembly not found in the libcoreclr.so\n");
        }
        else if (shutdownCoreCLR == nullptr)
        {
            fprintf(stderr, "Function coreclr_shutdown not found in the libcoreclr.so\n");
        }
        else
        {
            // check if we are enabling server GC or concurrent GC.
            // Server GC is off by default, while concurrent GC is on by default.
            // Actual checking of these string values is done in coreclr_initialize.
            const char* useServerGc = std::getenv(serverGcVar);
            if (useServerGc == nullptr)
            {
                useServerGc = "0";
            }

            const char* useConcurrentGc = std::getenv(concurrentGcVar);
            if (useConcurrentGc == nullptr)
            {
                useConcurrentGc = "1";
            }

            // Allowed property names:
            // APPBASE
            // - The base path of the application from which the exe and other assemblies will be loaded
            //
            // TRUSTED_PLATFORM_ASSEMBLIES
            // - The list of complete paths to each of the fully trusted assemblies
            //
            // APP_PATHS
            // - The list of paths which will be probed by the assembly loader
            //
            // APP_NI_PATHS
            // - The list of additional paths that the assembly loader will probe for ngen images
            //
            // NATIVE_DLL_SEARCH_DIRECTORIES
            // - The list of paths that will be probed for native DLLs called by PInvoke
            //
            const char *propertyKeys[] = {
                "TRUSTED_PLATFORM_ASSEMBLIES",
                "APP_PATHS",
                "APP_NI_PATHS",
                "NATIVE_DLL_SEARCH_DIRECTORIES",
                "AppDomainCompatSwitch",
                "SERVER_GC",
                "CONCURRENT_GC"
            };
            const char *propertyValues[] = {
                // TRUSTED_PLATFORM_ASSEMBLIES
                tpaList.c_str(),
                // APP_PATHS
                appPath.c_str(),
                // APP_NI_PATHS
                appPath.c_str(),
                // NATIVE_DLL_SEARCH_DIRECTORIES
                nativeDllSearchDirs.c_str(),
                // AppDomainCompatSwitch
                "UseLatestBehaviorWhenTFMNotSpecified",
                // SERVER_GC
                useServerGc,
                // CONCURRENT_GC
                useConcurrentGc
            };

            void* hostHandle;
            unsigned int domainId;

            int st = initializeCoreCLR(
                        currentExeAbsolutePath,
                        "unixcorerun",
                        sizeof(propertyKeys) / sizeof(propertyKeys[0]),
                        propertyKeys,
                        propertyValues,
                        &hostHandle,
                        &domainId);

            if (!SUCCEEDED(st))
            {
                fprintf(stderr, "coreclr_initialize failed - status: 0x%08x\n", st);
                exitCode = -1;
            }
            else
            {
                st = executeAssembly(
                        hostHandle,
                        domainId,
                        managedAssemblyArgc,
                        managedAssemblyArgv,
                        managedAssemblyAbsolutePath,
                        (unsigned int*)&exitCode);

                if (!SUCCEEDED(st))
                {
                    fprintf(stderr, "coreclr_execute_assembly failed - status: 0x%08x\n", st);
                    exitCode = -1;
                }

                st = shutdownCoreCLR(hostHandle, domainId);
                if (!SUCCEEDED(st))
                {
                    fprintf(stderr, "coreclr_shutdown failed - status: 0x%08x\n", st);
                    exitCode = -1;
                }
            }
        }

        if (dlclose(coreclrLib) != 0)
        {
            fprintf(stderr, "Warning - dlclose failed\n");
        }
    }
    else
    {
        char* error = dlerror();
        fprintf(stderr, "dlopen failed to open the libcoreclr.so with error %s\n", error);
    }

    return exitCode;
}
<commit_msg>Fix Stack Unwind Behavior of Libunwind-ARM<commit_after>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

//
// Code that is used by both the Unix corerun and coreconsole.
//

#include <cstdlib>
#include <assert.h>
#include <dirent.h>
#include <dlfcn.h>
#include <limits.h>
#include <set>
#include <string>
#include <string.h>
#include <sys/stat.h>
#include "coreruncommon.h"
#include <unistd.h>

#define SUCCEEDED(Status) ((Status) >= 0)

// Name of the environment variable controlling server GC.
// If set to 1, server GC is enabled on startup. If 0, server GC is
// disabled. Server GC is off by default.
static const char* serverGcVar = "CORECLR_SERVER_GC";

// Name of the environment variable controlling concurrent GC,
// used in the same way as serverGcVar. Concurrent GC is on by default.
static const char* concurrentGcVar = "CORECLR_CONCURRENT_GC";

// Prototype of the coreclr_initialize function from the libcoreclr.so
typedef int (*InitializeCoreCLRFunction)(
            const char* exePath,
            const char* appDomainFriendlyName,
            int propertyCount,
            const char** propertyKeys,
            const char** propertyValues,
            void** hostHandle,
            unsigned int* domainId);

// Prototype of the coreclr_shutdown function from the libcoreclr.so
typedef int (*ShutdownCoreCLRFunction)(
            void* hostHandle,
            unsigned int domainId);

// Prototype of the coreclr_execute_assembly function from the libcoreclr.so
typedef int (*ExecuteAssemblyFunction)(
            void* hostHandle,
            unsigned int domainId,
            int argc,
            const char** argv,
            const char* managedAssemblyPath,
            unsigned int* exitCode);

#if defined(__LINUX__)
#define symlinkEntrypointExecutable "/proc/self/exe"
#elif !defined(__APPLE__)
#define symlinkEntrypointExecutable "/proc/curproc/exe"
#endif

bool GetEntrypointExecutableAbsolutePath(std::string& entrypointExecutable)
{
    bool result = false;

    entrypointExecutable.clear();

    // Get path to the executable for the current process using
    // platform specific means.
#if defined(__LINUX__)
    // On Linux, fetch the entry point EXE absolute path, inclusive of filename.
    char exe[PATH_MAX];
    ssize_t res = readlink(symlinkEntrypointExecutable, exe, PATH_MAX - 1);
    if (res != -1)
    {
        exe[res] = '\0';
        entrypointExecutable.assign(exe);
        result = true;
    }
    else
    {
        result = false;
    }
#elif defined(__APPLE__)

    // On Mac, we ask the OS for the absolute path to the entrypoint executable
    uint32_t lenActualPath = 0;
    if (_NSGetExecutablePath(nullptr, &lenActualPath) == -1)
    {
        // OSX has placed the actual path length in lenActualPath,
        // so re-attempt the operation
        std::string resizedPath(lenActualPath, '\0');
        char *pResizedPath = const_cast<char *>(resizedPath.c_str());
        if (_NSGetExecutablePath(pResizedPath, &lenActualPath) == 0)
        {
            entrypointExecutable.assign(pResizedPath);
            result = true;
        }
    }
#else
    // On non-Mac OS, return the symlink that will be resolved by GetAbsolutePath
    // to fetch the entrypoint EXE absolute path, inclusive of filename.
    entrypointExecutable.assign(symlinkEntrypointExecutable);
    result = true;
#endif

    return result;
}

bool GetAbsolutePath(const char* path, std::string& absolutePath)
{
    bool result = false;

    char realPath[PATH_MAX];
    if (realpath(path, realPath) != nullptr && realPath[0] != '\0')
    {
        absolutePath.assign(realPath);
        // realpath should return canonicalized path without the trailing slash
        assert(absolutePath.back() != '/');

        result = true;
    }

    return result;
}

bool GetDirectory(const char* absolutePath, std::string& directory)
{
    directory.assign(absolutePath);
    size_t lastSlash = directory.rfind('/');
    if (lastSlash != std::string::npos)
    {
        directory.erase(lastSlash);
        return true;
    }

    return false;
}

bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath)
{
    std::string clrFilesRelativePath;
    const char* clrFilesPathLocal = clrFilesPath;
    if (clrFilesPathLocal == nullptr)
    {
        // There was no CLR files path specified, use the folder of the corerun/coreconsole
        if (!GetDirectory(currentExePath, clrFilesRelativePath))
        {
            perror("Failed to get directory from argv[0]");
            return false;
        }

        clrFilesPathLocal = clrFilesRelativePath.c_str();

        // TODO: consider using an env variable (if defined) as a fall-back.
        // The windows version of the corerun uses core_root env variable
    }

    if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath))
    {
        perror("Failed to convert CLR files path to absolute path");
        return false;
    }

    return true;
}

void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList)
{
    const char * const tpaExtensions[] = {
                ".ni.dll",      // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir
                ".dll",
                ".ni.exe",
                ".exe",
                };

    DIR* dir = opendir(directory);
    if (dir == nullptr)
    {
        return;
    }

    std::set<std::string> addedAssemblies;

    // Walk the directory for each extension separately so that we first get files with .ni.dll extension,
    // then files with .dll extension, etc.
    for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++)
    {
        const char* ext = tpaExtensions[extIndex];
        int extLength = strlen(ext);

        struct dirent* entry;

        // For all entries in the directory
        while ((entry = readdir(dir)) != nullptr)
        {
            // We are interested in files only
            switch (entry->d_type)
            {
            case DT_REG:
                break;

            // Handle symlinks and file systems that do not support d_type
            case DT_LNK:
            case DT_UNKNOWN:
                {
                    std::string fullFilename;

                    fullFilename.append(directory);
                    fullFilename.append("/");
                    fullFilename.append(entry->d_name);

                    struct stat sb;
                    if (stat(fullFilename.c_str(), &sb) == -1)
                    {
                        continue;
                    }

                    if (!S_ISREG(sb.st_mode))
                    {
                        continue;
                    }
                }
                break;

            default:
                continue;
            }

            std::string filename(entry->d_name);

            // Check if the extension matches the one we are looking for
            int extPos = filename.length() - extLength;
            if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0))
            {
                continue;
            }

            std::string filenameWithoutExt(filename.substr(0, extPos));

            // Make sure if we have an assembly with multiple extensions present,
            // we insert only one version of it.
            if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end())
            {
                addedAssemblies.insert(filenameWithoutExt);

                tpaList.append(directory);
                tpaList.append("/");
                tpaList.append(filename);
                tpaList.append(":");
            }
        }

        // Rewind the directory stream to be able to iterate over it for the next extension
        rewinddir(dir);
    }

    closedir(dir);
}

int ExecuteManagedAssembly(
            const char* currentExeAbsolutePath,
            const char* clrFilesAbsolutePath,
            const char* managedAssemblyAbsolutePath,
            int managedAssemblyArgc,
            const char** managedAssemblyArgv)
{
    // Indicates failure
    int exitCode = -1;

#ifdef _ARM_
    // LIBUNWIND-ARM has a bug of side effect with DWARF mode
    // Ref: https://github.com/dotnet/coreclr/issues/3462
    // This is why Fedora is disabling it by default as well.
    // Assuming that we cannot enforce the user to set
    // environmental variables for third party packages,
    // we set the environmental variable of libunwind locally here.

    // Without this, any exception handling will fail, so let's do this
    // as early as possible.
    // 0x1: DWARF / 0x2: FRAME / 0x4: EXIDX
    putenv("UNW_ARM_UNWIND_METHOD=6");
#endif // _ARM_

    std::string coreClrDllPath(clrFilesAbsolutePath);
    coreClrDllPath.append("/");
    coreClrDllPath.append(coreClrDll);

    if (coreClrDllPath.length() >= PATH_MAX)
    {
        fprintf(stderr, "Absolute path to libcoreclr.so too long\n");
        return -1;
    }

    // Get just the path component of the managed assembly path
    std::string appPath;
    GetDirectory(managedAssemblyAbsolutePath, appPath);

    std::string nativeDllSearchDirs(appPath);
    nativeDllSearchDirs.append(":");
    nativeDllSearchDirs.append(clrFilesAbsolutePath);

    std::string tpaList;
    AddFilesFromDirectoryToTpaList(clrFilesAbsolutePath, tpaList);

    void* coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW | RTLD_LOCAL);
    if (coreclrLib != nullptr)
    {
        InitializeCoreCLRFunction initializeCoreCLR = (InitializeCoreCLRFunction)dlsym(coreclrLib, "coreclr_initialize");
        ExecuteAssemblyFunction executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib, "coreclr_execute_assembly");
        ShutdownCoreCLRFunction shutdownCoreCLR = (ShutdownCoreCLRFunction)dlsym(coreclrLib, "coreclr_shutdown");

        if (initializeCoreCLR == nullptr)
        {
            fprintf(stderr, "Function coreclr_initialize not found in the libcoreclr.so\n");
        }
        else if (executeAssembly == nullptr)
        {
            fprintf(stderr, "Function coreclr_execute_assembly not found in the libcoreclr.so\n");
        }
        else if (shutdownCoreCLR == nullptr)
        {
            fprintf(stderr, "Function coreclr_shutdown not found in the libcoreclr.so\n");
        }
        else
        {
            // check if we are enabling server GC or concurrent GC.
            // Server GC is off by default, while concurrent GC is on by default.
            // Actual checking of these string values is done in coreclr_initialize.
            const char* useServerGc = std::getenv(serverGcVar);
            if (useServerGc == nullptr)
            {
                useServerGc = "0";
            }

            const char* useConcurrentGc = std::getenv(concurrentGcVar);
            if (useConcurrentGc == nullptr)
            {
                useConcurrentGc = "1";
            }

            // Allowed property names:
            // APPBASE
            // - The base path of the application from which the exe and other assemblies will be loaded
            //
            // TRUSTED_PLATFORM_ASSEMBLIES
            // - The list of complete paths to each of the fully trusted assemblies
            //
            // APP_PATHS
            // - The list of paths which will be probed by the assembly loader
            //
            // APP_NI_PATHS
            // - The list of additional paths that the assembly loader will probe for ngen images
            //
            // NATIVE_DLL_SEARCH_DIRECTORIES
            // - The list of paths that will be probed for native DLLs called by PInvoke
            //
            const char *propertyKeys[] = {
                "TRUSTED_PLATFORM_ASSEMBLIES",
                "APP_PATHS",
                "APP_NI_PATHS",
                "NATIVE_DLL_SEARCH_DIRECTORIES",
                "AppDomainCompatSwitch",
                "SERVER_GC",
                "CONCURRENT_GC"
            };
            const char *propertyValues[] = {
                // TRUSTED_PLATFORM_ASSEMBLIES
                tpaList.c_str(),
                // APP_PATHS
                appPath.c_str(),
                // APP_NI_PATHS
                appPath.c_str(),
                // NATIVE_DLL_SEARCH_DIRECTORIES
                nativeDllSearchDirs.c_str(),
                // AppDomainCompatSwitch
                "UseLatestBehaviorWhenTFMNotSpecified",
                // SERVER_GC
                useServerGc,
                // CONCURRENT_GC
                useConcurrentGc
            };

            void* hostHandle;
            unsigned int domainId;

            int st = initializeCoreCLR(
                        currentExeAbsolutePath,
                        "unixcorerun",
                        sizeof(propertyKeys) / sizeof(propertyKeys[0]),
                        propertyKeys,
                        propertyValues,
                        &hostHandle,
                        &domainId);

            if (!SUCCEEDED(st))
            {
                fprintf(stderr, "coreclr_initialize failed - status: 0x%08x\n", st);
                exitCode = -1;
            }
            else
            {
                st = executeAssembly(
                        hostHandle,
                        domainId,
                        managedAssemblyArgc,
                        managedAssemblyArgv,
                        managedAssemblyAbsolutePath,
                        (unsigned int*)&exitCode);

                if (!SUCCEEDED(st))
                {
                    fprintf(stderr, "coreclr_execute_assembly failed - status: 0x%08x\n", st);
                    exitCode = -1;
                }

                st = shutdownCoreCLR(hostHandle, domainId);
                if (!SUCCEEDED(st))
                {
                    fprintf(stderr, "coreclr_shutdown failed - status: 0x%08x\n", st);
                    exitCode = -1;
                }
            }
        }

        if (dlclose(coreclrLib) != 0)
        {
            fprintf(stderr, "Warning - dlclose failed\n");
        }
    }
    else
    {
        char* error = dlerror();
        fprintf(stderr, "dlopen failed to open the libcoreclr.so with error %s\n", error);
    }

    return exitCode;
}
<|endoftext|>


<commit_before>#include "Mesh.h"
#include "Director.h"
//#include "TransformPipelineParam.h"

namespace Rendering
{
	using namespace Manager;
	namespace Mesh
	{
		Mesh::Mesh() :
			_filter(nullptr), _renderer(nullptr),
			_selectMaterialIndex(0), _transformConstBuffer(nullptr)
		{
			_updateType = MaterialUpdateType::All;
		}

		Mesh::~Mesh()
		{
			OnDestroy();
		}

		bool Mesh::Initialize(const CreateFuncArguments& args)
		{
			_filter = new MeshFilter;
			if(_filter->CreateBuffer(args) == false)
			{
				ASSERT_MSG("Error, filter->cratebuffer");
				SAFE_DELETE(_filter);
				return false;
			}

			_renderer = new MeshRenderer;
			if(_renderer->AddMaterial(args.material) == false)
			{
				ASSERT_MSG("Error, renderer addmaterial");
				return false;
			}

			_transformConstBuffer = new Buffer::ConstBuffer;
			if(_transformConstBuffer->Initialize(sizeof(Core::TransformPipelineShaderInput)) == false)
			{
				ASSERT_MSG("Error, transformBuffer->Initialize");
				return false;
			}

			ClassifyRenderMeshType();
			return true;
		}

		void Mesh::OnInitialize()
		{
		}

		void Mesh::OnUpdate(float deltaTime)
		{
		}

		void Mesh::OnUpdateTransformCB(const Core::TransformPipelineShaderInput& transpose_Transform)
		{
			//Ʈ    δ, Object Ǵ
			ID3D11DeviceContext* context = Device::Director::GetInstance()->GetDirectX()->GetContext();
			_transformConstBuffer->UpdateSubResource(context, &transpose_Transform);
		}

		void Mesh::OnDestroy()
		{
			SAFE_DELETE(_filter);
			SAFE_DELETE(_renderer);
			SAFE_DELETE(_transformConstBuffer);
		}

		void Mesh::ClassifyRenderMeshType()
		{
			Manager::RenderManager* renderMgr = Device::Director::GetInstance()->GetCurrentScene()->GetRenderManager();
			if(_renderer)
			{
				bool isTransparentMesh = _renderer->IsTransparent();
				RenderManager::MeshType type = isTransparentMesh ?
					RenderManager::MeshType::Transparent : RenderManager::MeshType::Opaque;

				renderMgr->UpdateRenderList(this, type);
			}
		}

		void Mesh::OnRenderPreview()
		{
			ClassifyRenderMeshType();
		}

		Core::Component* Mesh::Clone() const
		{
			Mesh* newMesh = new Mesh;
			{
				newMesh->_filter = new MeshFilter(*_filter);
				newMesh->_renderer = new MeshRenderer(*_renderer);
				newMesh->_transformConstBuffer = new Buffer::ConstBuffer;
				newMesh->_transformConstBuffer->Initialize(sizeof(Core::TransformPipelineShaderInput));
				newMesh->ClassifyRenderMeshType();

				newMesh->_owner = _owner;
			}

			return newMesh;
		}
	}
}<commit_msg>Mesh - 코드 정리 #64<commit_after>#include "Mesh.h"
#include "Director.h"
//#include "TransformPipelineParam.h"

using namespace Rendering::Manager;
using namespace Rendering::Mesh;

Mesh::Mesh() :
	_filter(nullptr), _renderer(nullptr),
	_selectMaterialIndex(0), _transformConstBuffer(nullptr)
{
	_updateType = MaterialUpdateType::All;
}

Mesh::~Mesh()
{
	OnDestroy();
}

bool Mesh::Initialize(const CreateFuncArguments& args)
{
	_filter = new MeshFilter;
	if(_filter->CreateBuffer(args) == false)
	{
		ASSERT_MSG("Error, filter->cratebuffer");
		SAFE_DELETE(_filter);
		return false;
	}

	_renderer = new MeshRenderer;
	if(_renderer->AddMaterial(args.material) == false)
	{
		ASSERT_MSG("Error, renderer addmaterial");
		return false;
	}

	_transformConstBuffer = new Buffer::ConstBuffer;
	if(_transformConstBuffer->Initialize(sizeof(Core::TransformPipelineShaderInput)) == false)
	{
		ASSERT_MSG("Error, transformBuffer->Initialize");
		return false;
	}

	ClassifyRenderMeshType();
	return true;
}

void Mesh::OnInitialize()
{
}

void Mesh::OnUpdate(float deltaTime)
{
}

void Mesh::OnUpdateTransformCB(const Core::TransformPipelineShaderInput& transpose_Transform)
{
	//Ʈ    δ, Object Ǵ
	ID3D11DeviceContext* context = Device::Director::GetInstance()->GetDirectX()->GetContext();
	_transformConstBuffer->UpdateSubResource(context, &transpose_Transform);
}

void Mesh::OnDestroy()
{
	SAFE_DELETE(_filter);
	SAFE_DELETE(_renderer);
	SAFE_DELETE(_transformConstBuffer);
}

void Mesh::ClassifyRenderMeshType()
{
	Manager::RenderManager* renderMgr = Device::Director::GetInstance()->GetCurrentScene()->GetRenderManager();
	if(_renderer)
	{
		bool isTransparentMesh = _renderer->IsTransparent();
		RenderManager::MeshType type = isTransparentMesh ?
			RenderManager::MeshType::Transparent : RenderManager::MeshType::Opaque;

		renderMgr->UpdateRenderList(this, type);
	}
}

void Mesh::OnRenderPreview()
{
	ClassifyRenderMeshType();
}

Core::Component* Mesh::Clone() const
{
	Mesh* newMesh = new Mesh;
	{
		newMesh->_filter = new MeshFilter(*_filter);
		newMesh->_renderer = new MeshRenderer(*_renderer);
		newMesh->_transformConstBuffer = new Buffer::ConstBuffer;
		newMesh->_transformConstBuffer->Initialize(sizeof(Core::TransformPipelineShaderInput));
		newMesh->ClassifyRenderMeshType();

		newMesh->_owner = _owner;
	}

	return newMesh;
}
<|endoftext|>


<commit_before>#include "Light.h"
#include <ctime>
#include <wiringPi.h>
#include <softPwm.h>
#include <thread>
#include <chrono>

using namespace std;

void TurnOn(int pin){
	int Value=0;
	while(Value<100){
		Value+=1;
		softPwmWrite(pin,Value);
		this_thread::sleep_for(chrono::milliseconds(20));
	}
	return;
}

void TurnOff(int pin){
	int Value=100;
	while(Value>0){
		Value-=1;
		softPwmWrite(pin,Value);
		this_thread::sleep_for(chrono::milliseconds(20));
	}
	return;
}

Light::Light(int pin):Pin(pin){

	softPwmCreate(pin,0,100);

}

bool Light::Check(){
	if((time(0) > Timer)&&(Active)){
		Active=false;
		thread turnoff(TurnOff, Pin);
		turnoff.detach();
		return 0;
	}
	else if(Active)
		return 1;
	else
		return 0;
}

void Light::Set_Light(bool x){
	if((x) && (!Active)){
		Timer = time(0) + TimeOut;
		Active=true;
		thread turnon(TurnOn, Pin);
		turnon.detach();
	}
	else if(!x)
		Timer=time(0)+3; //3 seconds till lights turn off
}<commit_msg>Update Light.cpp<commit_after>#include "Light.h"
#include <ctime>
#include <wiringPi.h>
#include <softPwm.h>
#include <thread>
#include <chrono>

/* Program runs on the principle of a dead-timer
   Once the dead timer is reached, the lights turn off
   Once motion is detected, the timers will update itself.
*/

using namespace std;

void TurnOn(int pin){	// Turn on Light on pin
	int Value=0;
	while(Value<100){  // Fade in lights with a 100 x 20ms loop. Meaning over 2 seconds the light will fade in
		Value+=1;
		softPwmWrite(pin,Value); // PWM write to slowly increase brightness
		this_thread::sleep_for(chrono::milliseconds(20)); // time-delay (20ms)
	}
	return;
}

void TurnOff(int pin) { // Turn off Light on pin
	int Value=100;
	while(Value>0){ // Fade out lights with a 100 x 20ms loop. Meaning the light will fade out over the span of 2 seconds
		Value-=1;
		softPwmWrite(pin,Value); // PWM write to slowly decrease brightness
		this_thread::sleep_for(chrono::milliseconds(20)); // time-delay (20ms)
	}
	return;
}

Light::Light(int pin):Pin(pin){
	softPwmCreate(pin,0,100); // Create a PWM instance for pin with a value between 0 and 100
}

bool Light::Check(){
	if((time(0) > Timer)&&(Active)){ // if the current time is less than the Timer (for expiry)
		Active=false; //(meaning the dead-timer for the light has expired) and the Light is still active.
		thread turnoff(TurnOff, Pin); // Turn off the lights.
		turnoff.detach();
		return 0; // Return 0 because the timer expired.
	}
	else if(Active) {
		return 1; // If light is still active (and on), return a 1
	}
	else
		return 0; // If the light is out, return 0
}

void Light::Set_Light(bool x) {
	if((x) && (!Active)) { // If x is true and the lights are off. Turn on the lights
		Timer = time(0) + TimeOut; // current time + the time after which the lights will turn off sets the dead-time
		Active=true;
		thread turnon(TurnOn, Pin);
		turnon.detach();
	}
	else if((x) && (Active)) { // If x is true and the lights are on. Update the dead-timer (if lights are on, no need to turn them on)
		Timer = time(0) + TimeOut; // current time + the time after which the lights will turn off sets the dead-time
	}
	else if(!x)
		Timer=time(0)+3; // 3 seconds till lights turn off
}
<|endoftext|>


<commit_before>//
// Copyright 2012 Francisco Jerez
//
// 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.
//

#include "core/compiler.hpp"

#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/TextDiagnosticBuffer.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <clang/CodeGen/CodeGenAction.h>
#include <clang/Basic/TargetInfo.h>
#include <llvm/Bitcode/BitstreamWriter.h>
#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/Linker.h>
#if HAVE_LLVM < 0x0303
#include <llvm/DerivedTypes.h>
#include <llvm/LLVMContext.h>
#include <llvm/Module.h>
#else
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/IRReader/IRReader.h>
#endif
#include <llvm/PassManager.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/MemoryBuffer.h>
#if HAVE_LLVM < 0x0303
#include <llvm/Support/PathV1.h>
#endif
#include <llvm/Transforms/IPO.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h>

#if HAVE_LLVM < 0x0302
#include <llvm/Target/TargetData.h>
#elif HAVE_LLVM < 0x0303
#include <llvm/DataLayout.h>
#else
#include <llvm/IR/DataLayout.h>
#endif

#include "pipe/p_state.h"
#include "util/u_memory.h"

#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstdio>
#include <sstream>

using namespace clover;

namespace {
#if 0
   void
   build_binary(const std::string &source, const std::string &target,
                const std::string &name) {
      clang::CompilerInstance c;
      clang::EmitObjAction act(&llvm::getGlobalContext());
      std::string log;
      llvm::raw_string_ostream s_log(log);

      LLVMInitializeTGSITarget();
      LLVMInitializeTGSITargetInfo();
      LLVMInitializeTGSITargetMC();
      LLVMInitializeTGSIAsmPrinter();

      c.getFrontendOpts().Inputs.push_back(
         std::make_pair(clang::IK_OpenCL, name));
      c.getHeaderSearchOpts().UseBuiltinIncludes = false;
      c.getHeaderSearchOpts().UseStandardIncludes = false;
      c.getLangOpts().NoBuiltin = true;
      c.getTargetOpts().Triple = target;
      c.getInvocation().setLangDefaults(clang::IK_OpenCL);
      c.createDiagnostics(0, NULL, new clang::TextDiagnosticPrinter(
                             s_log, c.getDiagnosticOpts()));

      c.getPreprocessorOpts().addRemappedFile(
         name, llvm::MemoryBuffer::getMemBuffer(source));

      if (!c.ExecuteAction(act))
         throw build_error(log);
   }

   module
   load_binary(const char *name) {
      std::ifstream fs((name));
      std::vector<unsigned char> str((std::istreambuf_iterator<char>(fs)),
                                     (std::istreambuf_iterator<char>()));
      compat::istream cs(str);
      return module::deserialize(cs);
   }
#endif

   llvm::Module *
   compile(const std::string &source, const std::string &name,
           const std::string &triple, const std::string &processor,
           const std::string &opts, clang::LangAS::Map& address_spaces) {

      clang::CompilerInstance c;
      clang::EmitLLVMOnlyAction act(&llvm::getGlobalContext());
      std::string log;
      llvm::raw_string_ostream s_log(log);
      std::string libclc_path = LIBCLC_LIBEXECDIR + processor + "-"
                                                  + triple + ".bc";

      // Parse the compiler options:
      std::vector<std::string> opts_array;
      std::istringstream ss(opts);

      while (!ss.eof()) {
         std::string opt;
         getline(ss, opt, ' ');
         opts_array.push_back(opt);
      }

      opts_array.push_back(name);

      std::vector<const char *> opts_carray;
      for (unsigned i = 0; i < opts_array.size(); i++) {
         opts_carray.push_back(opts_array.at(i).c_str());
      }

      llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagID;
      llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts;
      clang::TextDiagnosticBuffer *DiagsBuffer;

      DiagID = new clang::DiagnosticIDs();
      DiagOpts = new clang::DiagnosticOptions();
      DiagsBuffer = new clang::TextDiagnosticBuffer();

      clang::DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
      bool Success;

      Success = clang::CompilerInvocation::CreateFromArgs(c.getInvocation(),
                                        opts_carray.data(),
                                        opts_carray.data() + opts_carray.size(),
                                        Diags);
      if (!Success) {
         throw error(CL_INVALID_BUILD_OPTIONS);
      }
      c.getFrontendOpts().ProgramAction = clang::frontend::EmitLLVMOnly;
      c.getHeaderSearchOpts().UseBuiltinIncludes = true;
      c.getHeaderSearchOpts().UseStandardSystemIncludes = true;
      c.getHeaderSearchOpts().ResourceDir = CLANG_RESOURCE_DIR;

      // Add libclc generic search path
      c.getHeaderSearchOpts().AddPath(LIBCLC_INCLUDEDIR,
                                      clang::frontend::Angled,
                                      false, false
#if HAVE_LLVM < 0x0303
                                      , false
#endif
                                      );

      // Add libclc include
      c.getPreprocessorOpts().Includes.push_back("clc/clc.h");

      // clc.h requires that this macro be defined:
      c.getPreprocessorOpts().addMacroDef("cl_clang_storage_class_specifiers");
      c.getPreprocessorOpts().addMacroDef("cl_khr_fp64");

      c.getLangOpts().NoBuiltin = true;
      c.getTargetOpts().Triple = triple;
      c.getTargetOpts().CPU = processor;
#if HAVE_LLVM <= 0x0301
      c.getInvocation().setLangDefaults(clang::IK_OpenCL);
#else
      c.getInvocation().setLangDefaults(c.getLangOpts(), clang::IK_OpenCL,
                                        clang::LangStandard::lang_opencl11);
#endif
      c.createDiagnostics(
#if HAVE_LLVM < 0x0303
                          0, NULL,
#endif
                          new clang::TextDiagnosticPrinter(
                                 s_log,
#if HAVE_LLVM <= 0x0301
                                 c.getDiagnosticOpts()));
#else
                                 &c.getDiagnosticOpts()));
#endif

      c.getPreprocessorOpts().addRemappedFile(name,
                                      llvm::MemoryBuffer::getMemBuffer(source));

      // Setting this attribute tells clang to link this file before
      // performing any optimizations.  This is required so that
      // we can replace calls to the OpenCL C barrier() builtin
      // with calls to target intrinsics that have the noduplicate
      // attribute.  This attribute will prevent Clang from creating
      // illegal uses of barrier() (e.g. Moving barrier() inside a conditional
      // that is no executed by all threads) during its optimizaton passes.
      c.getCodeGenOpts().LinkBitcodeFile = libclc_path;

      // Compile the code
      if (!c.ExecuteAction(act))
         throw build_error(log);

      // Get address spaces map to be able to find kernel argument address space
      memcpy(address_spaces, c.getTarget().getAddressSpaceMap(),
                                                        sizeof(address_spaces));

      return act.takeModule();
   }

   void
   find_kernels(llvm::Module *mod, std::vector<llvm::Function *> &kernels) {
      const llvm::NamedMDNode *kernel_node =
                                 mod->getNamedMetadata("opencl.kernels");
      // This means there are no kernels in the program.  The spec does not
      // require that we return an error here, but there will be an error if
      // the user tries to pass this program to a clCreateKernel() call.
      if (!kernel_node) {
         return;
      }

      for (unsigned i = 0; i < kernel_node->getNumOperands(); ++i) {
         kernels.push_back(llvm::dyn_cast<llvm::Function>(
                                    kernel_node->getOperand(i)->getOperand(0)));
      }
   }

   void
   internalize_functions(llvm::Module *mod,
        const std::vector<llvm::Function *> &kernels) {

      llvm::PassManager PM;
      // Add a function internalizer pass.
      //
      // By default, the function internalizer pass will look for a function
      // called "main" and then mark all other functions as internal.  Marking
      // functions as internal enables the optimizer to perform optimizations
      // like function inlining and global dead-code elimination.
      //
      // When there is no "main" function in a module, the internalize pass will
      // treat the module like a library, and it won't internalize any functions.
      // Since there is no "main" function in our kernels, we need to tell
      // the internalizer pass that this module is not a library by passing a
      // list of kernel functions to the internalizer.  The internalizer will
      // treat the functions in the list as "main" functions and internalize
      // all of the other functions.
      std::vector<const char*> export_list;
      for (std::vector<llvm::Function *>::const_iterator I = kernels.begin(),
                                                         E = kernels.end();
                                                         I != E; ++I) {
         llvm::Function *kernel = *I;
         export_list.push_back(kernel->getName().data());
      }
      PM.add(llvm::createInternalizePass(export_list));
      PM.run(*mod);
   }

   module
   build_module_llvm(llvm::Module *mod,
                     const std::vector<llvm::Function *> &kernels,
                     clang::LangAS::Map& address_spaces) {

      module m;
      struct pipe_llvm_program_header header;

      llvm::SmallVector<char, 1024> llvm_bitcode;
      llvm::raw_svector_ostream bitcode_ostream(llvm_bitcode);
      llvm::BitstreamWriter writer(llvm_bitcode);
      llvm::WriteBitcodeToFile(mod, bitcode_ostream);
      bitcode_ostream.flush();

      for (unsigned i = 0; i < kernels.size(); ++i) {
         llvm::Function *kernel_func;
         std::string kernel_name;
         compat::vector<module::argument> args;

         kernel_func = kernels[i];
         kernel_name = kernel_func->getName();

         for (llvm::Function::arg_iterator I = kernel_func->arg_begin(),
                                      E = kernel_func->arg_end(); I != E; ++I) {
            llvm::Argument &arg = *I;
#if HAVE_LLVM < 0x0302
            llvm::TargetData TD(kernel_func->getParent());
#elif HAVE_LLVM < 0x0304
            llvm::DataLayout TD(kernel_func->getParent()->getDataLayout());
#else
            llvm::DataLayout TD(mod);
#endif

            llvm::Type *arg_type = arg.getType();
            unsigned arg_size = TD.getTypeStoreSize(arg_type);

            llvm::Type *target_type = arg_type->isIntegerTy() ?
               TD.getSmallestLegalIntType(mod->getContext(), arg_size * 8) :
               arg_type;
            unsigned target_size = TD.getTypeStoreSize(target_type);
            unsigned target_align = TD.getABITypeAlignment(target_type);

            if (llvm::isa<llvm::PointerType>(arg_type) && arg.hasByValAttr()) {
               arg_type =
                  llvm::dyn_cast<llvm::PointerType>(arg_type)->getElementType();
            }

            if (arg_type->isPointerTy()) {
               unsigned address_space = llvm::cast<llvm::PointerType>(arg_type)->getAddressSpace();
               if (address_space == address_spaces[clang::LangAS::opencl_local
                                                     - clang::LangAS::Offset]) {
                  args.push_back(module::argument(module::argument::local,
                                                  arg_size, target_size,
                                                  target_align,
                                                  module::argument::zero_ext));
               } else {
                  // XXX: Correctly handle constant address space.  There is no
                  // way for r600g to pass a handle for constant buffers back
                  // to clover like it can for global buffers, so
                  // creating constant arguements will break r600g.  For now,
                  // continue treating constant buffers as global buffers
                  // until we can come up with a way to create handles for
                  // constant buffers.
                  args.push_back(module::argument(module::argument::global,
                                                  arg_size, target_size,
                                                  target_align,
                                                  module::argument::zero_ext));
              }

            } else {
               llvm::AttributeSet attrs = kernel_func->getAttributes();
               enum module::argument::ext_type ext_type =
                  (attrs.hasAttribute(arg.getArgNo() + 1,
                                     llvm::Attribute::SExt) ?
                   module::argument::sign_ext :
                   module::argument::zero_ext);

               args.push_back(
                  module::argument(module::argument::scalar, arg_size,
                                   target_size, target_align, ext_type));
            }
         }

         m.syms.push_back(module::symbol(kernel_name, 0, i, args ));
      }

      header.num_bytes = llvm_bitcode.size();
      std::string data;
      data.insert(0, (char*)(&header), sizeof(header));
      data.insert(data.end(), llvm_bitcode.begin(),
                                  llvm_bitcode.end());
      m.secs.push_back(module::section(0, module::section::text,
                                       header.num_bytes, data));

      return m;
   }
} // End anonymous namespace

module
clover::compile_program_llvm(const compat::string &source,
                             enum pipe_shader_ir ir,
                             const compat::string &target,
                             const compat::string &opts) {

   std::vector<llvm::Function *> kernels;
   size_t processor_str_len = std::string(target.begin()).find_first_of("-");
   std::string processor(target.begin(), 0, processor_str_len);
   std::string triple(target.begin(), processor_str_len + 1,
                      target.size() - processor_str_len - 1);
   clang::LangAS::Map address_spaces;

   // The input file name must have the .cl extension in order for the
   // CompilerInvocation class to recognize it as an OpenCL source file.
   llvm::Module *mod = compile(source, "input.cl", triple, processor, opts,
                                                                address_spaces);

   find_kernels(mod, kernels);

   internalize_functions(mod, kernels);

   // Build the clover::module
   switch (ir) {
      case PIPE_SHADER_IR_TGSI:
         //XXX: Handle TGSI
         assert(0);
         return module();
      default:
         return build_module_llvm(mod, kernels, address_spaces);
   }
}
<commit_msg>Revert "Merge branch 'master' of git+ssh://git.freedesktop.org/git/mesa/mesa"<commit_after>//
// Copyright 2012 Francisco Jerez
//
// 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.
//

#include "core/compiler.hpp"

#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/TextDiagnosticBuffer.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <clang/CodeGen/CodeGenAction.h>
#include <clang/Basic/TargetInfo.h>
#include <llvm/Bitcode/BitstreamWriter.h>
#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/Linker.h>
#if HAVE_LLVM < 0x0303
#include <llvm/DerivedTypes.h>
#include <llvm/LLVMContext.h>
#include <llvm/Module.h>
#else
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/IRReader/IRReader.h>
#endif
#include <llvm/PassManager.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/MemoryBuffer.h>
#if HAVE_LLVM < 0x0303
#include <llvm/Support/PathV1.h>
#endif
#include <llvm/Transforms/IPO.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h>

#if HAVE_LLVM < 0x0302
#include <llvm/Target/TargetData.h>
#elif HAVE_LLVM < 0x0303
#include <llvm/DataLayout.h>
#else
#include <llvm/IR/DataLayout.h>
#endif

#include "pipe/p_state.h"
#include "util/u_memory.h"

#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstdio>
#include <sstream>

using namespace clover;

namespace {
#if 0
   void
   build_binary(const std::string &source, const std::string &target,
                const std::string &name) {
      clang::CompilerInstance c;
      clang::EmitObjAction act(&llvm::getGlobalContext());
      std::string log;
      llvm::raw_string_ostream s_log(log);

      LLVMInitializeTGSITarget();
      LLVMInitializeTGSITargetInfo();
      LLVMInitializeTGSITargetMC();
      LLVMInitializeTGSIAsmPrinter();

      c.getFrontendOpts().Inputs.push_back(
         std::make_pair(clang::IK_OpenCL, name));
      c.getHeaderSearchOpts().UseBuiltinIncludes = false;
      c.getHeaderSearchOpts().UseStandardIncludes = false;
      c.getLangOpts().NoBuiltin = true;
      c.getTargetOpts().Triple = target;
      c.getInvocation().setLangDefaults(clang::IK_OpenCL);
      c.createDiagnostics(0, NULL, new clang::TextDiagnosticPrinter(
                             s_log, c.getDiagnosticOpts()));

      c.getPreprocessorOpts().addRemappedFile(
         name, llvm::MemoryBuffer::getMemBuffer(source));

      if (!c.ExecuteAction(act))
         throw build_error(log);
   }

   module
   load_binary(const char *name) {
      std::ifstream fs((name));
      std::vector<unsigned char> str((std::istreambuf_iterator<char>(fs)),
                                     (std::istreambuf_iterator<char>()));
      compat::istream cs(str);
      return module::deserialize(cs);
   }
#endif

   llvm::Module *
   compile(const std::string &source, const std::string &name,
           const std::string &triple, const std::string &processor,
           const std::string &opts, clang::LangAS::Map& address_spaces) {

      clang::CompilerInstance c;
      clang::EmitLLVMOnlyAction act(&llvm::getGlobalContext());
      std::string log;
      llvm::raw_string_ostream s_log(log);
      std::string libclc_path = LIBCLC_LIBEXECDIR + processor + "-"
                                                  + triple + ".bc";

      // Parse the compiler options:
      std::vector<std::string> opts_array;
      std::istringstream ss(opts);

      while (!ss.eof()) {
         std::string opt;
         getline(ss, opt, ' ');
         opts_array.push_back(opt);
      }

      opts_array.push_back(name);

      std::vector<const char *> opts_carray;
      for (unsigned i = 0; i < opts_array.size(); i++) {
         opts_carray.push_back(opts_array.at(i).c_str());
      }

      llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagID;
      llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts;
      clang::TextDiagnosticBuffer *DiagsBuffer;

      DiagID = new clang::DiagnosticIDs();
      DiagOpts = new clang::DiagnosticOptions();
      DiagsBuffer = new clang::TextDiagnosticBuffer();

      clang::DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
      bool Success;

      Success = clang::CompilerInvocation::CreateFromArgs(c.getInvocation(),
                                        opts_carray.data(),
                                        opts_carray.data() + opts_carray.size(),
                                        Diags);
      if (!Success) {
         throw error(CL_INVALID_BUILD_OPTIONS);
      }
      c.getFrontendOpts().ProgramAction = clang::frontend::EmitLLVMOnly;
      c.getHeaderSearchOpts().UseBuiltinIncludes = true;
      c.getHeaderSearchOpts().UseStandardSystemIncludes = true;
      c.getHeaderSearchOpts().ResourceDir = CLANG_RESOURCE_DIR;

      // Add libclc generic search path
      c.getHeaderSearchOpts().AddPath(LIBCLC_INCLUDEDIR,
                                      clang::frontend::Angled,
                                      false, false
#if HAVE_LLVM < 0x0303
                                      , false
#endif
                                      );

      // Add libclc include
      c.getPreprocessorOpts().Includes.push_back("clc/clc.h");

      // clc.h requires that this macro be defined:
      c.getPreprocessorOpts().addMacroDef("cl_clang_storage_class_specifiers");
      c.getPreprocessorOpts().addMacroDef("cl_khr_fp64");

      c.getLangOpts().NoBuiltin = true;
      c.getTargetOpts().Triple = triple;
      c.getTargetOpts().CPU = processor;
#if HAVE_LLVM <= 0x0301
      c.getInvocation().setLangDefaults(clang::IK_OpenCL);
#else
      c.getInvocation().setLangDefaults(c.getLangOpts(), clang::IK_OpenCL,
                                        clang::LangStandard::lang_opencl11);
#endif
      c.createDiagnostics(
#if HAVE_LLVM < 0x0303
                          0, NULL,
#endif
                          new clang::TextDiagnosticPrinter(
                                 s_log,
#if HAVE_LLVM <= 0x0301
                                 c.getDiagnosticOpts()));
#else
                                 &c.getDiagnosticOpts()));
#endif

      c.getPreprocessorOpts().addRemappedFile(name,
                                      llvm::MemoryBuffer::getMemBuffer(source));

      // Setting this attribute tells clang to link this file before
      // performing any optimizations.  This is required so that
      // we can replace calls to the OpenCL C barrier() builtin
      // with calls to target intrinsics that have the noduplicate
      // attribute.  This attribute will prevent Clang from creating
      // illegal uses of barrier() (e.g. Moving barrier() inside a conditional
      // that is no executed by all threads) during its optimizaton passes.
      c.getCodeGenOpts().LinkBitcodeFile = libclc_path;

      // Compile the code
      if (!c.ExecuteAction(act))
         throw build_error(log);

      // Get address spaces map to be able to find kernel argument address space
      memcpy(address_spaces, c.getTarget().getAddressSpaceMap(),
                                                        sizeof(address_spaces));

      return act.takeModule();
   }

   void
   find_kernels(llvm::Module *mod, std::vector<llvm::Function *> &kernels) {
      const llvm::NamedMDNode *kernel_node =
                                 mod->getNamedMetadata("opencl.kernels");
      // This means there are no kernels in the program.  The spec does not
      // require that we return an error here, but there will be an error if
      // the user tries to pass this program to a clCreateKernel() call.
      if (!kernel_node) {
         return;
      }

      for (unsigned i = 0; i < kernel_node->getNumOperands(); ++i) {
         kernels.push_back(llvm::dyn_cast<llvm::Function>(
                                    kernel_node->getOperand(i)->getOperand(0)));
      }
   }

   void
   internalize_functions(llvm::Module *mod,
        const std::vector<llvm::Function *> &kernels) {

      llvm::PassManager PM;
      // Add a function internalizer pass.
      //
      // By default, the function internalizer pass will look for a function
      // called "main" and then mark all other functions as internal.  Marking
      // functions as internal enables the optimizer to perform optimizations
      // like function inlining and global dead-code elimination.
      //
      // When there is no "main" function in a module, the internalize pass will
      // treat the module like a library, and it won't internalize any functions.
      // Since there is no "main" function in our kernels, we need to tell
      // the internalizer pass that this module is not a library by passing a
      // list of kernel functions to the internalizer.  The internalizer will
      // treat the functions in the list as "main" functions and internalize
      // all of the other functions.
      std::vector<const char*> export_list;
      for (std::vector<llvm::Function *>::const_iterator I = kernels.begin(),
                                                         E = kernels.end();
                                                         I != E; ++I) {
         llvm::Function *kernel = *I;
         export_list.push_back(kernel->getName().data());
      }
      PM.add(llvm::createInternalizePass(export_list));
      PM.run(*mod);
   }

   module
   build_module_llvm(llvm::Module *mod,
                     const std::vector<llvm::Function *> &kernels,
                     clang::LangAS::Map& address_spaces) {

      module m;
      struct pipe_llvm_program_header header;

      llvm::SmallVector<char, 1024> llvm_bitcode;
      llvm::raw_svector_ostream bitcode_ostream(llvm_bitcode);
      llvm::BitstreamWriter writer(llvm_bitcode);
      llvm::WriteBitcodeToFile(mod, bitcode_ostream);
      bitcode_ostream.flush();

      for (unsigned i = 0; i < kernels.size(); ++i) {
         llvm::Function *kernel_func;
         std::string kernel_name;
         compat::vector<module::argument> args;

         kernel_func = kernels[i];
         kernel_name = kernel_func->getName();

         for (llvm::Function::arg_iterator I = kernel_func->arg_begin(),
                                      E = kernel_func->arg_end(); I != E; ++I) {
            llvm::Argument &arg = *I;
#if HAVE_LLVM < 0x0302
            llvm::TargetData TD(kernel_func->getParent());
#else
            llvm::DataLayout TD(kernel_func->getParent()->getDataLayout());
#endif

            llvm::Type *arg_type = arg.getType();
            unsigned arg_size = TD.getTypeStoreSize(arg_type);

            llvm::Type *target_type = arg_type->isIntegerTy() ?
               TD.getSmallestLegalIntType(mod->getContext(), arg_size * 8) :
               arg_type;
            unsigned target_size = TD.getTypeStoreSize(target_type);
            unsigned target_align = TD.getABITypeAlignment(target_type);

            if (llvm::isa<llvm::PointerType>(arg_type) && arg.hasByValAttr()) {
               arg_type =
                  llvm::dyn_cast<llvm::PointerType>(arg_type)->getElementType();
            }

            if (arg_type->isPointerTy()) {
               unsigned address_space = llvm::cast<llvm::PointerType>(arg_type)->getAddressSpace();
               if (address_space == address_spaces[clang::LangAS::opencl_local
                                                     - clang::LangAS::Offset]) {
                  args.push_back(module::argument(module::argument::local,
                                                  arg_size, target_size,
                                                  target_align,
                                                  module::argument::zero_ext));
               } else {
                  // XXX: Correctly handle constant address space.  There is no
                  // way for r600g to pass a handle for constant buffers back
                  // to clover like it can for global buffers, so
                  // creating constant arguements will break r600g.  For now,
                  // continue treating constant buffers as global buffers
                  // until we can come up with a way to create handles for
                  // constant buffers.
                  args.push_back(module::argument(module::argument::global,
                                                  arg_size, target_size,
                                                  target_align,
                                                  module::argument::zero_ext));
              }

            } else {
               llvm::AttributeSet attrs = kernel_func->getAttributes();
               enum module::argument::ext_type ext_type =
                  (attrs.hasAttribute(arg.getArgNo() + 1,
                                     llvm::Attribute::SExt) ?
                   module::argument::sign_ext :
                   module::argument::zero_ext);

               args.push_back(
                  module::argument(module::argument::scalar, arg_size,
                                   target_size, target_align, ext_type));
            }
         }

         m.syms.push_back(module::symbol(kernel_name, 0, i, args ));
      }

      header.num_bytes = llvm_bitcode.size();
      std::string data;
      data.insert(0, (char*)(&header), sizeof(header));
      data.insert(data.end(), llvm_bitcode.begin(),
                                  llvm_bitcode.end());
      m.secs.push_back(module::section(0, module::section::text,
                                       header.num_bytes, data));

      return m;
   }
} // End anonymous namespace

module
clover::compile_program_llvm(const compat::string &source,
                             enum pipe_shader_ir ir,
                             const compat::string &target,
                             const compat::string &opts) {

   std::vector<llvm::Function *> kernels;
   size_t processor_str_len = std::string(target.begin()).find_first_of("-");
   std::string processor(target.begin(), 0, processor_str_len);
   std::string triple(target.begin(), processor_str_len + 1,
                      target.size() - processor_str_len - 1);
   clang::LangAS::Map address_spaces;

   // The input file name must have the .cl extension in order for the
   // CompilerInvocation class to recognize it as an OpenCL source file.
   llvm::Module *mod = compile(source, "input.cl", triple, processor, opts,
                                                                address_spaces);

   find_kernels(mod, kernels);

   internalize_functions(mod, kernels);

   // Build the clover::module
   switch (ir) {
      case PIPE_SHADER_IR_TGSI:
         //XXX: Handle TGSI
         assert(0);
         return module();
      default:
         return build_module_llvm(mod, kernels, address_spaces);
   }
}
<|endoftext|>


<commit_before>//
// Copyright 2012 Francisco Jerez
//
// 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.
//

#include "core/compiler.hpp"

#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/TextDiagnosticBuffer.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <clang/CodeGen/CodeGenAction.h>
#include <clang/Basic/TargetInfo.h>
#include <llvm/Bitcode/BitstreamWriter.h>
#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/Linker.h>
#if HAVE_LLVM < 0x0303
#include <llvm/DerivedTypes.h>
#include <llvm/LLVMContext.h>
#include <llvm/Module.h>
#else
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/IRReader/IRReader.h>
#endif
#include <llvm/PassManager.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/MemoryBuffer.h>
#if HAVE_LLVM < 0x0303
#include <llvm/Support/PathV1.h>
#endif
#include <llvm/Transforms/IPO.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h>

#if HAVE_LLVM < 0x0302
#include <llvm/Target/TargetData.h>
#elif HAVE_LLVM < 0x0303
#include <llvm/DataLayout.h>
#else
#include <llvm/IR/DataLayout.h>
#endif

#include "pipe/p_state.h"
#include "util/u_memory.h"

#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstdio>
#include <sstream>

using namespace clover;

namespace {
#if 0
   void
   build_binary(const std::string &source, const std::string &target,
                const std::string &name) {
      clang::CompilerInstance c;
      clang::EmitObjAction act(&llvm::getGlobalContext());
      std::string log;
      llvm::raw_string_ostream s_log(log);

      LLVMInitializeTGSITarget();
      LLVMInitializeTGSITargetInfo();
      LLVMInitializeTGSITargetMC();
      LLVMInitializeTGSIAsmPrinter();

      c.getFrontendOpts().Inputs.push_back(
         std::make_pair(clang::IK_OpenCL, name));
      c.getHeaderSearchOpts().UseBuiltinIncludes = false;
      c.getHeaderSearchOpts().UseStandardIncludes = false;
      c.getLangOpts().NoBuiltin = true;
      c.getTargetOpts().Triple = target;
      c.getInvocation().setLangDefaults(clang::IK_OpenCL);
      c.createDiagnostics(0, NULL, new clang::TextDiagnosticPrinter(
                             s_log, c.getDiagnosticOpts()));

      c.getPreprocessorOpts().addRemappedFile(
         name, llvm::MemoryBuffer::getMemBuffer(source));

      if (!c.ExecuteAction(act))
         throw build_error(log);
   }

   module
   load_binary(const char *name) {
      std::ifstream fs((name));
      std::vector<unsigned char> str((std::istreambuf_iterator<char>(fs)),
                                     (std::istreambuf_iterator<char>()));
      compat::istream cs(str);
      return module::deserialize(cs);
   }
#endif

   llvm::Module *
   compile(const std::string &source, const std::string &name,
           const std::string &triple, const std::string &processor,
           const std::string &opts, clang::LangAS::Map& address_spaces) {

      clang::CompilerInstance c;
      clang::EmitLLVMOnlyAction act(&llvm::getGlobalContext());
      std::string log;
      llvm::raw_string_ostream s_log(log);
      std::string libclc_path = LIBCLC_LIBEXECDIR + processor + "-"
                                                  + triple + ".bc";

      // Parse the compiler options:
      std::vector<std::string> opts_array;
      std::istringstream ss(opts);

      while (!ss.eof()) {
         std::string opt;
         getline(ss, opt, ' ');
         opts_array.push_back(opt);
      }

      opts_array.push_back(name);

      std::vector<const char *> opts_carray;
      for (unsigned i = 0; i < opts_array.size(); i++) {
         opts_carray.push_back(opts_array.at(i).c_str());
      }

      llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagID;
      llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts;
      clang::TextDiagnosticBuffer *DiagsBuffer;

      DiagID = new clang::DiagnosticIDs();
      DiagOpts = new clang::DiagnosticOptions();
      DiagsBuffer = new clang::TextDiagnosticBuffer();

      clang::DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
      bool Success;

      Success = clang::CompilerInvocation::CreateFromArgs(c.getInvocation(),
                                        opts_carray.data(),
                                        opts_carray.data() + opts_carray.size(),
                                        Diags);
      if (!Success) {
         throw error(CL_INVALID_BUILD_OPTIONS);
      }
      c.getFrontendOpts().ProgramAction = clang::frontend::EmitLLVMOnly;
      c.getHeaderSearchOpts().UseBuiltinIncludes = true;
      c.getHeaderSearchOpts().UseStandardSystemIncludes = true;
      c.getHeaderSearchOpts().ResourceDir = CLANG_RESOURCE_DIR;

      // Add libclc generic search path
      c.getHeaderSearchOpts().AddPath(LIBCLC_INCLUDEDIR,
                                      clang::frontend::Angled,
                                      false, false
#if HAVE_LLVM < 0x0303
                                      , false
#endif
                                      );

      // Add libclc include
      c.getPreprocessorOpts().Includes.push_back("clc/clc.h");

      // clc.h requires that this macro be defined:
      c.getPreprocessorOpts().addMacroDef("cl_clang_storage_class_specifiers");
      c.getPreprocessorOpts().addMacroDef("cl_khr_fp64");

      c.getLangOpts().NoBuiltin = true;
      c.getTargetOpts().Triple = triple;
      c.getTargetOpts().CPU = processor;
#if HAVE_LLVM <= 0x0301
      c.getInvocation().setLangDefaults(clang::IK_OpenCL);
#else
      c.getInvocation().setLangDefaults(c.getLangOpts(), clang::IK_OpenCL,
                                        clang::LangStandard::lang_opencl11);
#endif
      c.createDiagnostics(
#if HAVE_LLVM < 0x0303
                          0, NULL,
#endif
                          new clang::TextDiagnosticPrinter(
                                 s_log,
#if HAVE_LLVM <= 0x0301
                                 c.getDiagnosticOpts()));
#else
                                 &c.getDiagnosticOpts()));
#endif

      c.getPreprocessorOpts().addRemappedFile(name,
                                      llvm::MemoryBuffer::getMemBuffer(source));

      // Setting this attribute tells clang to link this file before
      // performing any optimizations.  This is required so that
      // we can replace calls to the OpenCL C barrier() builtin
      // with calls to target intrinsics that have the noduplicate
      // attribute.  This attribute will prevent Clang from creating
      // illegal uses of barrier() (e.g. Moving barrier() inside a conditional
      // that is no executed by all threads) during its optimizaton passes.
      c.getCodeGenOpts().LinkBitcodeFile = libclc_path;

      // Compile the code
      if (!c.ExecuteAction(act))
         throw build_error(log);

      // Get address spaces map to be able to find kernel argument address space
      memcpy(address_spaces, c.getTarget().getAddressSpaceMap(),
                                                        sizeof(address_spaces));

      return act.takeModule();
   }

   void
   find_kernels(llvm::Module *mod, std::vector<llvm::Function *> &kernels) {
      const llvm::NamedMDNode *kernel_node =
                                 mod->getNamedMetadata("opencl.kernels");
      // This means there are no kernels in the program.  The spec does not
      // require that we return an error here, but there will be an error if
      // the user tries to pass this program to a clCreateKernel() call.
      if (!kernel_node) {
         return;
      }

      for (unsigned i = 0; i < kernel_node->getNumOperands(); ++i) {
         kernels.push_back(llvm::dyn_cast<llvm::Function>(
                                    kernel_node->getOperand(i)->getOperand(0)));
      }
   }

   void
   internalize_functions(llvm::Module *mod,
        const std::vector<llvm::Function *> &kernels) {

      llvm::PassManager PM;
      // Add a function internalizer pass.
      //
      // By default, the function internalizer pass will look for a function
      // called "main" and then mark all other functions as internal.  Marking
      // functions as internal enables the optimizer to perform optimizations
      // like function inlining and global dead-code elimination.
      //
      // When there is no "main" function in a module, the internalize pass will
      // treat the module like a library, and it won't internalize any functions.
      // Since there is no "main" function in our kernels, we need to tell
      // the internalizer pass that this module is not a library by passing a
      // list of kernel functions to the internalizer.  The internalizer will
      // treat the functions in the list as "main" functions and internalize
      // all of the other functions.
      std::vector<const char*> export_list;
      for (std::vector<llvm::Function *>::const_iterator I = kernels.begin(),
                                                         E = kernels.end();
                                                         I != E; ++I) {
         llvm::Function *kernel = *I;
         export_list.push_back(kernel->getName().data());
      }
      PM.add(llvm::createInternalizePass(export_list));
      PM.run(*mod);
   }

   module
   build_module_llvm(llvm::Module *mod,
                     const std::vector<llvm::Function *> &kernels,
                     clang::LangAS::Map& address_spaces) {

      module m;
      struct pipe_llvm_program_header header;

      llvm::SmallVector<char, 1024> llvm_bitcode;
      llvm::raw_svector_ostream bitcode_ostream(llvm_bitcode);
      llvm::BitstreamWriter writer(llvm_bitcode);
      llvm::WriteBitcodeToFile(mod, bitcode_ostream);
      bitcode_ostream.flush();

      for (unsigned i = 0; i < kernels.size(); ++i) {
         llvm::Function *kernel_func;
         std::string kernel_name;
         compat::vector<module::argument> args;

         kernel_func = kernels[i];
         kernel_name = kernel_func->getName();

         for (llvm::Function::arg_iterator I = kernel_func->arg_begin(),
                                      E = kernel_func->arg_end(); I != E; ++I) {
            llvm::Argument &arg = *I;
#if HAVE_LLVM < 0x0302
            llvm::TargetData TD(kernel_func->getParent());
#else
            llvm::DataLayout TD(kernel_func->getParent()->getDataLayout());
#endif

            llvm::Type *arg_type = arg.getType();
            unsigned arg_size = TD.getTypeStoreSize(arg_type);

            llvm::Type *target_type = arg_type->isIntegerTy() ?
               TD.getSmallestLegalIntType(mod->getContext(), arg_size * 8) :
               arg_type;
            unsigned target_size = TD.getTypeStoreSize(target_type);
            unsigned target_align = TD.getABITypeAlignment(target_type);

            if (llvm::isa<llvm::PointerType>(arg_type) && arg.hasByValAttr()) {
               arg_type =
                  llvm::dyn_cast<llvm::PointerType>(arg_type)->getElementType();
            }

            if (arg_type->isPointerTy()) {
               unsigned address_space = llvm::cast<llvm::PointerType>(arg_type)->getAddressSpace();
               if (address_space == address_spaces[clang::LangAS::opencl_local
                                                     - clang::LangAS::Offset]) {
                  args.push_back(module::argument(module::argument::local,
                                                  arg_size, target_size,
                                                  target_align,
                                                  module::argument::zero_ext));
               } else {
                  // XXX: Correctly handle constant address space.  There is no
                  // way for r600g to pass a handle for constant buffers back
                  // to clover like it can for global buffers, so
                  // creating constant arguements will break r600g.  For now,
                  // continue treating constant buffers as global buffers
                  // until we can come up with a way to create handles for
                  // constant buffers.
                  args.push_back(module::argument(module::argument::global,
                                                  arg_size, target_size,
                                                  target_align,
                                                  module::argument::zero_ext));
              }

            } else {
               llvm::AttributeSet attrs = kernel_func->getAttributes();
               enum module::argument::ext_type ext_type =
                  (attrs.hasAttribute(arg.getArgNo() + 1,
                                     llvm::Attribute::SExt) ?
                   module::argument::sign_ext :
                   module::argument::zero_ext);

               args.push_back(
                  module::argument(module::argument::scalar, arg_size,
                                   target_size, target_align, ext_type));
            }
         }

         m.syms.push_back(module::symbol(kernel_name, 0, i, args ));
      }

      header.num_bytes = llvm_bitcode.size();
      std::string data;
      data.insert(0, (char*)(&header), sizeof(header));
      data.insert(data.end(), llvm_bitcode.begin(),
                                  llvm_bitcode.end());
      m.secs.push_back(module::section(0, module::section::text,
                                       header.num_bytes, data));

      return m;
   }
} // End anonymous namespace

module
clover::compile_program_llvm(const compat::string &source,
                             enum pipe_shader_ir ir,
                             const compat::string &target,
                             const compat::string &opts) {

   std::vector<llvm::Function *> kernels;
   size_t processor_str_len = std::string(target.begin()).find_first_of("-");
   std::string processor(target.begin(), 0, processor_str_len);
   std::string triple(target.begin(), processor_str_len + 1,
                      target.size() - processor_str_len - 1);
   clang::LangAS::Map address_spaces;

   // The input file name must have the .cl extension in order for the
   // CompilerInvocation class to recognize it as an OpenCL source file.
   llvm::Module *mod = compile(source, "input.cl", triple, processor, opts,
                                                                address_spaces);

   find_kernels(mod, kernels);

   internalize_functions(mod, kernels);

   // Build the clover::module
   switch (ir) {
      case PIPE_SHADER_IR_TGSI:
         //XXX: Handle TGSI
         assert(0);
         return module();
      default:
         return build_module_llvm(mod, kernels, address_spaces);
   }
}
<commit_msg>Re-commit 'clover: Fix build with LLVM 3.5'<commit_after>//
// Copyright 2012 Francisco Jerez
//
// 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.
//

#include "core/compiler.hpp"

#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/TextDiagnosticBuffer.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <clang/CodeGen/CodeGenAction.h>
#include <clang/Basic/TargetInfo.h>
#include <llvm/Bitcode/BitstreamWriter.h>
#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/Linker.h>
#if HAVE_LLVM < 0x0303
#include <llvm/DerivedTypes.h>
#include <llvm/LLVMContext.h>
#include <llvm/Module.h>
#else
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/IRReader/IRReader.h>
#endif
#include <llvm/PassManager.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/MemoryBuffer.h>
#if HAVE_LLVM < 0x0303
#include <llvm/Support/PathV1.h>
#endif
#include <llvm/Transforms/IPO.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h>

#if HAVE_LLVM < 0x0302
#include <llvm/Target/TargetData.h>
#elif HAVE_LLVM < 0x0303
#include <llvm/DataLayout.h>
#else
#include <llvm/IR/DataLayout.h>
#endif

#include "pipe/p_state.h"
#include "util/u_memory.h"

#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstdio>
#include <sstream>

using namespace clover;

namespace {
#if 0
   void
   build_binary(const std::string &source, const std::string &target,
                const std::string &name) {
      clang::CompilerInstance c;
      clang::EmitObjAction act(&llvm::getGlobalContext());
      std::string log;
      llvm::raw_string_ostream s_log(log);

      LLVMInitializeTGSITarget();
      LLVMInitializeTGSITargetInfo();
      LLVMInitializeTGSITargetMC();
      LLVMInitializeTGSIAsmPrinter();

      c.getFrontendOpts().Inputs.push_back(
         std::make_pair(clang::IK_OpenCL, name));
      c.getHeaderSearchOpts().UseBuiltinIncludes = false;
      c.getHeaderSearchOpts().UseStandardIncludes = false;
      c.getLangOpts().NoBuiltin = true;
      c.getTargetOpts().Triple = target;
      c.getInvocation().setLangDefaults(clang::IK_OpenCL);
      c.createDiagnostics(0, NULL, new clang::TextDiagnosticPrinter(
                             s_log, c.getDiagnosticOpts()));

      c.getPreprocessorOpts().addRemappedFile(
         name, llvm::MemoryBuffer::getMemBuffer(source));

      if (!c.ExecuteAction(act))
         throw build_error(log);
   }

   module
   load_binary(const char *name) {
      std::ifstream fs((name));
      std::vector<unsigned char> str((std::istreambuf_iterator<char>(fs)),
                                     (std::istreambuf_iterator<char>()));
      compat::istream cs(str);
      return module::deserialize(cs);
   }
#endif

   llvm::Module *
   compile(const std::string &source, const std::string &name,
           const std::string &triple, const std::string &processor,
           const std::string &opts, clang::LangAS::Map& address_spaces) {

      clang::CompilerInstance c;
      clang::EmitLLVMOnlyAction act(&llvm::getGlobalContext());
      std::string log;
      llvm::raw_string_ostream s_log(log);
      std::string libclc_path = LIBCLC_LIBEXECDIR + processor + "-"
                                                  + triple + ".bc";

      // Parse the compiler options:
      std::vector<std::string> opts_array;
      std::istringstream ss(opts);

      while (!ss.eof()) {
         std::string opt;
         getline(ss, opt, ' ');
         opts_array.push_back(opt);
      }

      opts_array.push_back(name);

      std::vector<const char *> opts_carray;
      for (unsigned i = 0; i < opts_array.size(); i++) {
         opts_carray.push_back(opts_array.at(i).c_str());
      }

      llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagID;
      llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts;
      clang::TextDiagnosticBuffer *DiagsBuffer;

      DiagID = new clang::DiagnosticIDs();
      DiagOpts = new clang::DiagnosticOptions();
      DiagsBuffer = new clang::TextDiagnosticBuffer();

      clang::DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
      bool Success;

      Success = clang::CompilerInvocation::CreateFromArgs(c.getInvocation(),
                                        opts_carray.data(),
                                        opts_carray.data() + opts_carray.size(),
                                        Diags);
      if (!Success) {
         throw error(CL_INVALID_BUILD_OPTIONS);
      }
      c.getFrontendOpts().ProgramAction = clang::frontend::EmitLLVMOnly;
      c.getHeaderSearchOpts().UseBuiltinIncludes = true;
      c.getHeaderSearchOpts().UseStandardSystemIncludes = true;
      c.getHeaderSearchOpts().ResourceDir = CLANG_RESOURCE_DIR;

      // Add libclc generic search path
      c.getHeaderSearchOpts().AddPath(LIBCLC_INCLUDEDIR,
                                      clang::frontend::Angled,
                                      false, false
#if HAVE_LLVM < 0x0303
                                      , false
#endif
                                      );

      // Add libclc include
      c.getPreprocessorOpts().Includes.push_back("clc/clc.h");

      // clc.h requires that this macro be defined:
      c.getPreprocessorOpts().addMacroDef("cl_clang_storage_class_specifiers");
      c.getPreprocessorOpts().addMacroDef("cl_khr_fp64");

      c.getLangOpts().NoBuiltin = true;
      c.getTargetOpts().Triple = triple;
      c.getTargetOpts().CPU = processor;
#if HAVE_LLVM <= 0x0301
      c.getInvocation().setLangDefaults(clang::IK_OpenCL);
#else
      c.getInvocation().setLangDefaults(c.getLangOpts(), clang::IK_OpenCL,
                                        clang::LangStandard::lang_opencl11);
#endif
      c.createDiagnostics(
#if HAVE_LLVM < 0x0303
                          0, NULL,
#endif
                          new clang::TextDiagnosticPrinter(
                                 s_log,
#if HAVE_LLVM <= 0x0301
                                 c.getDiagnosticOpts()));
#else
                                 &c.getDiagnosticOpts()));
#endif

      c.getPreprocessorOpts().addRemappedFile(name,
                                      llvm::MemoryBuffer::getMemBuffer(source));

      // Setting this attribute tells clang to link this file before
      // performing any optimizations.  This is required so that
      // we can replace calls to the OpenCL C barrier() builtin
      // with calls to target intrinsics that have the noduplicate
      // attribute.  This attribute will prevent Clang from creating
      // illegal uses of barrier() (e.g. Moving barrier() inside a conditional
      // that is no executed by all threads) during its optimizaton passes.
      c.getCodeGenOpts().LinkBitcodeFile = libclc_path;

      // Compile the code
      if (!c.ExecuteAction(act))
         throw build_error(log);

      // Get address spaces map to be able to find kernel argument address space
      memcpy(address_spaces, c.getTarget().getAddressSpaceMap(),
                                                        sizeof(address_spaces));

      return act.takeModule();
   }

   void
   find_kernels(llvm::Module *mod, std::vector<llvm::Function *> &kernels) {
      const llvm::NamedMDNode *kernel_node =
                                 mod->getNamedMetadata("opencl.kernels");
      // This means there are no kernels in the program.  The spec does not
      // require that we return an error here, but there will be an error if
      // the user tries to pass this program to a clCreateKernel() call.
      if (!kernel_node) {
         return;
      }

      for (unsigned i = 0; i < kernel_node->getNumOperands(); ++i) {
         kernels.push_back(llvm::dyn_cast<llvm::Function>(
                                    kernel_node->getOperand(i)->getOperand(0)));
      }
   }

   void
   internalize_functions(llvm::Module *mod,
        const std::vector<llvm::Function *> &kernels) {

      llvm::PassManager PM;
      // Add a function internalizer pass.
      //
      // By default, the function internalizer pass will look for a function
      // called "main" and then mark all other functions as internal.  Marking
      // functions as internal enables the optimizer to perform optimizations
      // like function inlining and global dead-code elimination.
      //
      // When there is no "main" function in a module, the internalize pass will
      // treat the module like a library, and it won't internalize any functions.
      // Since there is no "main" function in our kernels, we need to tell
      // the internalizer pass that this module is not a library by passing a
      // list of kernel functions to the internalizer.  The internalizer will
      // treat the functions in the list as "main" functions and internalize
      // all of the other functions.
      std::vector<const char*> export_list;
      for (std::vector<llvm::Function *>::const_iterator I = kernels.begin(),
                                                         E = kernels.end();
                                                         I != E; ++I) {
         llvm::Function *kernel = *I;
         export_list.push_back(kernel->getName().data());
      }
      PM.add(llvm::createInternalizePass(export_list));
      PM.run(*mod);
   }

   module
   build_module_llvm(llvm::Module *mod,
                     const std::vector<llvm::Function *> &kernels,
                     clang::LangAS::Map& address_spaces) {

      module m;
      struct pipe_llvm_program_header header;

      llvm::SmallVector<char, 1024> llvm_bitcode;
      llvm::raw_svector_ostream bitcode_ostream(llvm_bitcode);
      llvm::BitstreamWriter writer(llvm_bitcode);
      llvm::WriteBitcodeToFile(mod, bitcode_ostream);
      bitcode_ostream.flush();

      for (unsigned i = 0; i < kernels.size(); ++i) {
         llvm::Function *kernel_func;
         std::string kernel_name;
         compat::vector<module::argument> args;

         kernel_func = kernels[i];
         kernel_name = kernel_func->getName();

         for (llvm::Function::arg_iterator I = kernel_func->arg_begin(),
                                      E = kernel_func->arg_end(); I != E; ++I) {
            llvm::Argument &arg = *I;
#if HAVE_LLVM < 0x0302
            llvm::TargetData TD(kernel_func->getParent());
#elif HAVE_LLVM < 0x0304
            llvm::DataLayout TD(kernel_func->getParent()->getDataLayout());
#else
            llvm::DataLayout TD(mod);
#endif

            llvm::Type *arg_type = arg.getType();
            unsigned arg_size = TD.getTypeStoreSize(arg_type);

            llvm::Type *target_type = arg_type->isIntegerTy() ?
               TD.getSmallestLegalIntType(mod->getContext(), arg_size * 8) :
               arg_type;
            unsigned target_size = TD.getTypeStoreSize(target_type);
            unsigned target_align = TD.getABITypeAlignment(target_type);

            if (llvm::isa<llvm::PointerType>(arg_type) && arg.hasByValAttr()) {
               arg_type =
                  llvm::dyn_cast<llvm::PointerType>(arg_type)->getElementType();
            }

            if (arg_type->isPointerTy()) {
               unsigned address_space = llvm::cast<llvm::PointerType>(arg_type)->getAddressSpace();
               if (address_space == address_spaces[clang::LangAS::opencl_local
                                                     - clang::LangAS::Offset]) {
                  args.push_back(module::argument(module::argument::local,
                                                  arg_size, target_size,
                                                  target_align,
                                                  module::argument::zero_ext));
               } else {
                  // XXX: Correctly handle constant address space.  There is no
                  // way for r600g to pass a handle for constant buffers back
                  // to clover like it can for global buffers, so
                  // creating constant arguements will break r600g.  For now,
                  // continue treating constant buffers as global buffers
                  // until we can come up with a way to create handles for
                  // constant buffers.
                  args.push_back(module::argument(module::argument::global,
                                                  arg_size, target_size,
                                                  target_align,
                                                  module::argument::zero_ext));
              }

            } else {
               llvm::AttributeSet attrs = kernel_func->getAttributes();
               enum module::argument::ext_type ext_type =
                  (attrs.hasAttribute(arg.getArgNo() + 1,
                                     llvm::Attribute::SExt) ?
                   module::argument::sign_ext :
                   module::argument::zero_ext);

               args.push_back(
                  module::argument(module::argument::scalar, arg_size,
                                   target_size, target_align, ext_type));
            }
         }

         m.syms.push_back(module::symbol(kernel_name, 0, i, args ));
      }

      header.num_bytes = llvm_bitcode.size();
      std::string data;
      data.insert(0, (char*)(&header), sizeof(header));
      data.insert(data.end(), llvm_bitcode.begin(),
                                  llvm_bitcode.end());
      m.secs.push_back(module::section(0, module::section::text,
                                       header.num_bytes, data));

      return m;
   }
} // End anonymous namespace

module
clover::compile_program_llvm(const compat::string &source,
                             enum pipe_shader_ir ir,
                             const compat::string &target,
                             const compat::string &opts) {

   std::vector<llvm::Function *> kernels;
   size_t processor_str_len = std::string(target.begin()).find_first_of("-");
   std::string processor(target.begin(), 0, processor_str_len);
   std::string triple(target.begin(), processor_str_len + 1,
                      target.size() - processor_str_len - 1);
   clang::LangAS::Map address_spaces;

   // The input file name must have the .cl extension in order for the
   // CompilerInvocation class to recognize it as an OpenCL source file.
   llvm::Module *mod = compile(source, "input.cl", triple, processor, opts,
                                                                address_spaces);

   find_kernels(mod, kernels);

   internalize_functions(mod, kernels);

   // Build the clover::module
   switch (ir) {
      case PIPE_SHADER_IR_TGSI:
         //XXX: Handle TGSI
         assert(0);
         return module();
      default:
         return build_module_llvm(mod, kernels, address_spaces);
   }
}
<|endoftext|>