<commit_before>// Copyright (c) Microsoft. All rights reserved.

//
// GpioTestTool
//
//   Utility to manipulate GPIO pins from the command line.
//   Demonstrates how to use the GPIO WinRT APIs from standard
//   C++ with WRL.
//

#include <windows.h>
#include <strsafe.h>
#include <wrl.h>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <cwctype>

#include <windows.foundation.h>
#include <windows.devices.gpio.h>

using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Devices::Gpio;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;

typedef ITypedEventHandler<GpioPin *, GpioPinValueChangedEventArgs *>
    IGpioPinValueChangedHandler;

class wexception
{
public:
    explicit wexception (const std::wstring& Msg) : msg(Msg) { }

    wexception (const wchar_t* Msg, ...) {
        HRESULT hr;
        WCHAR buf[512];

        va_list argList;
        va_start(argList, Msg);
        hr = StringCchVPrintfW(
                buf,
                ARRAYSIZE(buf),
                Msg,
                argList);
        va_end(argList);

        this->msg = SUCCEEDED(hr) ? buf : Msg;
    }

    virtual ~wexception () { /*empty*/ }

    virtual const wchar_t *wwhat () const
    {
        return this->msg.c_str();
    }

private:
    std::wstring msg;
};

ComPtr<IGpioController> MakeDefaultController ()
{
    ComPtr<IGpioController> controller;

    // get the activation factory
    ComPtr<IGpioControllerStatics> controllerStatics;
    HRESULT hr = GetActivationFactory(
        HStringReference(RuntimeClass_Windows_Devices_Gpio_GpioController).Get(),
        &controllerStatics);
    if (FAILED(hr)) {
        throw wexception(
            L"Failed to get activation factory for %s. Please ensure the type "
            L"is present on the system. (hr = 0x%x)",
            RuntimeClass_Windows_Devices_Gpio_GpioController,
            hr);
    }

    hr = controllerStatics->GetDefault(controller.GetAddressOf());
    if (FAILED(hr)) {
        throw wexception(
            L"Failed to get instance of default GPIO controller. (hr = 0x%x)",
            hr);
    }

    if (!controller) {
        throw wexception(L"GPIO is not available on this system");
    }

    return controller;
}

ComPtr<IGpioPin> MakePin (int PinNumber)
{
    auto controller = MakeDefaultController();

    ComPtr<IGpioPin> pin;
    HRESULT hr = controller->OpenPin(PinNumber, pin.GetAddressOf());
    if (FAILED(hr)) {
        throw wexception(L"Failed to open pin. (hr = 0x%x)", hr);
    }

    return pin;
}

void ListPins ()
{
    auto controller = MakeDefaultController();

    INT32 pinCount;
    HRESULT hr = controller->get_PinCount(&pinCount);
    if (FAILED(hr)) {
        throw wexception(L"Failed to get pin count. (hr = 0x%x)", hr);
    }

    wprintf(L"The default GPIO controller has %d pins:\n", pinCount);
    for (INT32 pinNumber = 0; pinNumber < pinCount; ++pinNumber) {
        ComPtr<IGpioPin> pin;
        hr = controller->OpenPin(pinNumber, pin.GetAddressOf());
        switch (hr) {
        case S_OK:
            wprintf(L"  Pin %d is available\n", pinNumber);
            break;
        case __HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION):
            wprintf(L"  Pin %d is currently in use\n", pinNumber);
            break;
        case __HRESULT_FROM_WIN32(ERROR_NOT_FOUND):
            // pin is not available to applications; don't print anything
            break;
        default:
            wprintf(
                L"  Pin %d: unexpected error occurred attempting to open. (hr = 0x%x)\n",
                pinNumber,
                hr);
        }
    }
}

GpioPinValue operator! (GpioPinValue Value)
{
    return (Value == GpioPinValue_Low) ? GpioPinValue_High : GpioPinValue_Low;
}

std::wistream& operator>> (std::wistream& is, GpioPinValue& value)
{
    int raw;
    is >> raw;
    if (is.fail()) {
        return is;
    }
    switch (raw) {
    case GpioPinValue_Low:
    case GpioPinValue_High:
        value = GpioPinValue(raw);
        break;
    default:
        is.clear(is.failbit);
    }
    return is;
}

PCWSTR StringFromGpioPinValue (GpioPinValue value)
{
    switch (value) {
    case GpioPinValue_Low: return L"Low";
    case GpioPinValue_High: return L"High";
    default: return L"[invalid GpioPinValue]";
    }
}

std::wistream& operator>> (std::wistream& is, GpioPinDriveMode& value)
{
    is.clear();
    std::wstring driveMode;
    is >> driveMode;
    if (!_wcsicmp(driveMode.c_str(), L"input")) {
        value = GpioPinDriveMode_Input;
    } else if (!_wcsicmp(driveMode.c_str(), L"output")) {
        value = GpioPinDriveMode_Output;
    } else if (!_wcsicmp(driveMode.c_str(), L"inputPullUp")) {
        value = GpioPinDriveMode_InputPullUp;
    } else if (!_wcsicmp(driveMode.c_str(), L"inputPullDown")) {
        value = GpioPinDriveMode_InputPullDown;
    } else {
        is.clear(is.failbit);
    }
    return is;
}

PCWSTR StringFromGpioPinDriveMode (GpioPinDriveMode value)
{
    switch (value) {
    case GpioPinDriveMode_Input: return L"input";
    case GpioPinDriveMode_Output: return L"output";
    case GpioPinDriveMode_InputPullUp: return L"inputPullUp";
    case GpioPinDriveMode_InputPullDown: return L"inputPullDown";
    default: return L"[invalid GpioPinDriveMode]";
    }
}

PCWSTR StringFromGpioSharingMode (GpioSharingMode value)
{
    switch (value) {
    case GpioSharingMode_Exclusive: return L"Exclusive";
    case GpioSharingMode_SharedReadOnly: return L"SharedReadOnly";
    default: return L"[invalid GpioSharingMode]";
    }
}

PCWSTR StringFromGpioPinEdge (GpioPinEdge value)
{
    switch (value) {
    case GpioPinEdge_FallingEdge: return L"Falling";
    case GpioPinEdge_RisingEdge: return L"Rising";
    default: return L"[Invalid GpioPinEdge value]";
    }
}

PCWSTR Help =
    L"Commands:\n"
    L" > write 0|1                        Write pin low (0) or high (1)\n"
    L" > high                             Alias for 'write 1'\n"
    L" > low                              Alias for 'write 0'\n"
    L" > toggle                           Toggle the pin from its current state\n"
    L" > read                             Read pin\n"
    L" > setdrivemode drive_mode          Set the pins's drive mode\n"
    L"     where drive_mode = input|output|\n"
    L"                        inputPullUp|inputPullDown\n"
    L" > interrupt on|off                 Register or unregister for pin value\n"
    L"                                    change events.\n"
    L" > info                             Dump information about the pin\n"
    L" > help                             Display this help message\n"
    L" > quit                             Quit\n";

void ShowPrompt (_In_ IGpioPin* pin)
{
    auto listener = Callback<IGpioPinValueChangedHandler>([] (
        _In_ IGpioPin* /*Pin*/,
        _In_ IGpioPinValueChangedEventArgs* Args
        ) -> HRESULT
    {
        GpioPinEdge edge;
        Args->get_Edge(&edge);
        wprintf(L"%s edge occurred.\n", StringFromGpioPinEdge(edge));
        return S_OK;
    });

    auto token = EventRegistrationToken();
    bool listenerRegistered = false;

    GpioPinValue outputLatch = GpioPinValue_High;
    while (std::wcin) {
        wprintf(L"> ");

        std::wstring line;
        if (!std::getline(std::wcin, line)) {
            return;
        }
        std::wistringstream linestream(line);

        std::wstring command;
        linestream >> command;
        if ((command == L"q") || (command == L"quit")) {
            return;
        } else if ((command == L"h") || (command == L"help")) {
            wprintf(L"%s\n", Help);
        } else if ((command == L"w") || (command == L"write")) {
            GpioPinValue value;
            linestream >> value;
            if (linestream.fail()) {
                wprintf(L"Syntax error: expecting 0 or 1\nUsage: write 0|1\n");
                continue;
            }

            HRESULT hr = pin->Write(value);
            if (FAILED(hr)) {
                wprintf(L"Failed to write pin. (hr = 0x%x)\n", hr);
                continue;
            }
        } else if (command == L"high") {
            HRESULT hr = pin->Write(GpioPinValue_High);
            if (FAILED(hr)) {
                wprintf(L"Failed to write pin. (hr = 0x%x)\n", hr);
                continue;
            }
        } else if (command == L"low") {
            HRESULT hr = pin->Write(GpioPinValue_Low);
            if (FAILED(hr)) {
                wprintf(L"Failed to write pin. (hr = 0x%x)\n", hr);
                continue;
            }
        } else if ((command == L"t") || (command == L"toggle")) {
            outputLatch = !outputLatch;
            HRESULT hr = pin->Write(outputLatch);
            if (FAILED(hr)) {
                wprintf(L"Failed to write pin. (hr = 0x%x)\n", hr);
                continue;
            }
        } else if ((command == L"r") || (command == L"read")) {
            GpioPinValue value;
            HRESULT hr = pin->Read(&value);
            if (FAILED(hr)) {
                wprintf(L"Failed to read pin. (hr = 0x%x)\n", hr);
                continue;
            }
            wprintf(L"%s\n", StringFromGpioPinValue(value));
        } else if (command == L"setdrivemode") {
            GpioPinDriveMode driveMode;
            linestream >> driveMode;
            if (!linestream) {
                wprintf(L"Syntax error: expecting valid drive mode. Type 'help' for usage.\n");
                continue;
            }

            HRESULT hr = pin->SetDriveMode(driveMode);
            if (FAILED(hr)) {
                wprintf(L"Failed to set drive mode. (hr = 0x%x)\n", hr);
                continue;
            }
        } else if ((command == L"int") || (command == L"interrupt")) {
            std::wstring onOrOff;
            linestream >> onOrOff;
            if (onOrOff == L"on") {
                if (listenerRegistered) {
                    wprintf(L"Interrupt listener already registered.\n");
                    continue;
                }

                HRESULT hr = pin->add_ValueChanged(listener.Get(), &token);
                if (FAILED(hr)) {
                    wprintf(
                        L"Failed to add event listener to ValueChanged event. (hr = 0x%x)\n",
                        hr);
                    continue;
                }
                listenerRegistered = true;
            } else if (onOrOff == L"off") {
                if (!listenerRegistered) {
                    wprintf(L"No interrupt listener is currently registered.\n");
                    continue;
                }

                HRESULT hr = pin->remove_ValueChanged(token);
                if (FAILED(hr)) {
                    wprintf(
                        L"Failed to remove ValueChanged event. (hr = 0x%x)\n",
                        hr);
                    continue;
                }
                listenerRegistered = false;
            } else {
                wprintf(
                    L"Expecting 'on' or 'off': %s. Type 'help' for usage.\n",
                    onOrOff.c_str());
            }
        } else if ((command == L"i") || (command == L"info")) {
            int pinNumber;
            pin->get_PinNumber(&pinNumber);
            GpioSharingMode sharingMode;
            pin->get_SharingMode(&sharingMode);
            TimeSpan debounceTimeout;
            pin->get_DebounceTimeout(&debounceTimeout);
            GpioPinDriveMode driveMode;
            pin->GetDriveMode(&driveMode);
            GpioPinValue value;
            pin->Read(&value);

            wprintf(
                L"        Pin Number: %d\n"
                L"      Sharing Mode: %s\n"
                L"  Debounce Timeout: %d ms\n"
                L"        Drive Mode: %s\n"
                L"             Value: %s\n",
                pinNumber,
                StringFromGpioSharingMode(sharingMode),
                int(debounceTimeout.Duration / 10000LL),
                StringFromGpioPinDriveMode(driveMode),
                StringFromGpioPinValue(value));
        } else if (command.empty()) {
            // ignore
        } else {
            wprintf(
                L"Unrecognized command: %s. Type 'help' for command usage.\n",
                command.c_str());
        }
    }
}

PCWSTR Usage =
L"GpioTestTool: Command line GPIO testing utility\n"
L"Usage: %s [-list] PinNumber\n"
L"\n"
L"  -list         List the available pins on the default GPIO controller.\n"
L"  PinNumber     The pin number with which you wish to interact. This\n"
L"                parameter is required.\n"
L"\n"
L"Example:\n"
L"  %s -list\n"
L"  %s 47\n";

void PrintUsage (PCWSTR name)
{
    wprintf(Usage, name, name, name);
}

int __cdecl wmain (_In_ int argc, _In_reads_(argc) wchar_t *argv[])
{
    enum MainReturnValue { Success, Failure };

    if (argc < 2) {
        fwprintf(
            stderr,
            L"Missing required command line parameter PinNumber\n\n");
        PrintUsage(argv[0]);
        return Success;
    }

    PCWSTR arg = argv[1];
    if (!_wcsicmp(arg, L"-h") || !_wcsicmp(arg, L"/h") ||
        !_wcsicmp(arg, L"-?") || !_wcsicmp(arg, L"/?")) {

        PrintUsage(argv[0]);
        return Success;
    }

    RoInitializeWrapper roInit(RO_INIT_MULTITHREADED);
    try {
        if (!_wcsicmp(arg, L"-list") || !_wcsicmp(arg, L"/list")) {
            ListPins();
            return Success;
        } else {
            std::wistringstream is(arg);
            INT32 pinNumber;
            is >> pinNumber;
            if (!is) {
                fwprintf(
                    stderr,
                    L"Expecting integer: %s\nType %s /? for usage.\n",
                    arg,
                    argv[0]);
                return Failure;
            }

            auto pin = MakePin(pinNumber);
            wprintf(L"Type 'help' for a list of commands\n");
            ShowPrompt(pin.Get());
            return Success;
        }
    } catch (const wexception& ex) {
        fwprintf(stderr, L"Error: %s\n", ex.wwhat());
        return Failure;
    }
}
<commit_msg>Add muxing error messages to GpioTestTool<commit_after>// Copyright (c) Microsoft. All rights reserved.

//
// GpioTestTool
//
//   Utility to manipulate GPIO pins from the command line.
//   Demonstrates how to use the GPIO WinRT APIs from standard
//   C++ with WRL.
//

#include <windows.h>
#include <strsafe.h>
#include <wrl.h>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <cwctype>

#include <windows.foundation.h>
#include <windows.devices.gpio.h>

using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Devices::Gpio;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;

typedef ITypedEventHandler<GpioPin *, GpioPinValueChangedEventArgs *>
    IGpioPinValueChangedHandler;

class wexception
{
public:
    explicit wexception (const std::wstring& Msg) : msg(Msg) { }

    wexception (const wchar_t* Msg, ...) {
        HRESULT hr;
        WCHAR buf[512];

        va_list argList;
        va_start(argList, Msg);
        hr = StringCchVPrintfW(
                buf,
                ARRAYSIZE(buf),
                Msg,
                argList);
        va_end(argList);

        this->msg = SUCCEEDED(hr) ? buf : Msg;
    }

    virtual ~wexception () { /*empty*/ }

    virtual const wchar_t *wwhat () const
    {
        return this->msg.c_str();
    }

private:
    std::wstring msg;
};

ComPtr<IGpioController> MakeDefaultController ()
{
    ComPtr<IGpioController> controller;

    // get the activation factory
    ComPtr<IGpioControllerStatics> controllerStatics;
    HRESULT hr = GetActivationFactory(
        HStringReference(RuntimeClass_Windows_Devices_Gpio_GpioController).Get(),
        &controllerStatics);
    if (FAILED(hr)) {
        throw wexception(
            L"Failed to get activation factory for %s. Please ensure the type "
            L"is present on the system. (hr = 0x%x)",
            RuntimeClass_Windows_Devices_Gpio_GpioController,
            hr);
    }

    hr = controllerStatics->GetDefault(controller.GetAddressOf());
    if (FAILED(hr)) {
        throw wexception(
            L"Failed to get instance of default GPIO controller. (hr = 0x%x)",
            hr);
    }

    if (!controller) {
        throw wexception(L"GPIO is not available on this system");
    }

    return controller;
}

ComPtr<IGpioPin> MakePin (int PinNumber)
{
    auto controller = MakeDefaultController();

    ComPtr<IGpioPin> pin;
    HRESULT hr = controller->OpenPin(PinNumber, pin.GetAddressOf());
    if (FAILED(hr)) {
        switch (hr) {
        case E_INVALIDARG:
            throw wexception(
                L"The pin could not be opened because the pin number is invalid "
                L"or an invalid parameter was specified to OpenPin(). "
                L"Run 'GpioTestTool -list' to see the list of available pins.");
        case __HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION):
            throw wexception(
                L"The pin could not be opened due to a sharing violation. "
                L"Ensure the pin is not already in use.");
        case __HRESULT_FROM_WIN32(ERROR_NOT_FOUND):
            throw wexception(
                L"The pin could not be opened because it is not accessible to "
                L"usermode applications. Run 'GpioTestTool -list' to see the list "
                L"of available pins.");
        case __HRESULT_FROM_WIN32(ERROR_GPIO_INCOMPATIBLE_CONNECT_MODE):
            throw wexception(
                L"The pin could not be opened because it is currently muxed "
                L"to a different function (e.g. I2C/SPI/UART). Ensure this pin "
                L"is not in use by another function.");
        }

        throw wexception(L"Failed to open pin. (hr = 0x%x)", hr);
    }

    return pin;
}

void ListPins ()
{
    auto controller = MakeDefaultController();

    INT32 pinCount;
    HRESULT hr = controller->get_PinCount(&pinCount);
    if (FAILED(hr)) {
        throw wexception(L"Failed to get pin count. (hr = 0x%x)", hr);
    }

    wprintf(L"The default GPIO controller has %d pins:\n", pinCount);
    for (INT32 pinNumber = 0; pinNumber < pinCount; ++pinNumber) {
        ComPtr<IGpioPin> pin;
        hr = controller->OpenPin(pinNumber, pin.GetAddressOf());
        switch (hr) {
        case S_OK:
            wprintf(L"  Pin %d is available\n", pinNumber);
            break;
        case __HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION):
            wprintf(L"  Pin %d is currently in use\n", pinNumber);
            break;
        case __HRESULT_FROM_WIN32(ERROR_NOT_FOUND):
            // pin is not available to applications; don't print anything
            break;
        case __HRESULT_FROM_WIN32(ERROR_GPIO_INCOMPATIBLE_CONNECT_MODE):
            wprintf(
                L"  Pin %d is currently muxed to a different function\n",
                pinNumber);
            break;
        default:
            wprintf(
                L"  Pin %d: unexpected error occurred attempting to open. (hr = 0x%x)\n",
                pinNumber,
                hr);
        }
    }
}

GpioPinValue operator! (GpioPinValue Value)
{
    return (Value == GpioPinValue_Low) ? GpioPinValue_High : GpioPinValue_Low;
}

std::wistream& operator>> (std::wistream& is, GpioPinValue& value)
{
    int raw;
    is >> raw;
    if (is.fail()) {
        return is;
    }
    switch (raw) {
    case GpioPinValue_Low:
    case GpioPinValue_High:
        value = GpioPinValue(raw);
        break;
    default:
        is.clear(is.failbit);
    }
    return is;
}

PCWSTR StringFromGpioPinValue (GpioPinValue value)
{
    switch (value) {
    case GpioPinValue_Low: return L"Low";
    case GpioPinValue_High: return L"High";
    default: return L"[invalid GpioPinValue]";
    }
}

std::wistream& operator>> (std::wistream& is, GpioPinDriveMode& value)
{
    is.clear();
    std::wstring driveMode;
    is >> driveMode;
    if (!_wcsicmp(driveMode.c_str(), L"input")) {
        value = GpioPinDriveMode_Input;
    } else if (!_wcsicmp(driveMode.c_str(), L"output")) {
        value = GpioPinDriveMode_Output;
    } else if (!_wcsicmp(driveMode.c_str(), L"inputPullUp")) {
        value = GpioPinDriveMode_InputPullUp;
    } else if (!_wcsicmp(driveMode.c_str(), L"inputPullDown")) {
        value = GpioPinDriveMode_InputPullDown;
    } else {
        is.clear(is.failbit);
    }
    return is;
}

PCWSTR StringFromGpioPinDriveMode (GpioPinDriveMode value)
{
    switch (value) {
    case GpioPinDriveMode_Input: return L"input";
    case GpioPinDriveMode_Output: return L"output";
    case GpioPinDriveMode_InputPullUp: return L"inputPullUp";
    case GpioPinDriveMode_InputPullDown: return L"inputPullDown";
    default: return L"[invalid GpioPinDriveMode]";
    }
}

PCWSTR StringFromGpioSharingMode (GpioSharingMode value)
{
    switch (value) {
    case GpioSharingMode_Exclusive: return L"Exclusive";
    case GpioSharingMode_SharedReadOnly: return L"SharedReadOnly";
    default: return L"[invalid GpioSharingMode]";
    }
}

PCWSTR StringFromGpioPinEdge (GpioPinEdge value)
{
    switch (value) {
    case GpioPinEdge_FallingEdge: return L"Falling";
    case GpioPinEdge_RisingEdge: return L"Rising";
    default: return L"[Invalid GpioPinEdge value]";
    }
}

PCWSTR Help =
    L"Commands:\n"
    L" > write 0|1                        Write pin low (0) or high (1)\n"
    L" > high                             Alias for 'write 1'\n"
    L" > low                              Alias for 'write 0'\n"
    L" > toggle                           Toggle the pin from its current state\n"
    L" > read                             Read pin\n"
    L" > setdrivemode drive_mode          Set the pins's drive mode\n"
    L"     where drive_mode = input|output|\n"
    L"                        inputPullUp|inputPullDown\n"
    L" > interrupt on|off                 Register or unregister for pin value\n"
    L"                                    change events.\n"
    L" > info                             Dump information about the pin\n"
    L" > help                             Display this help message\n"
    L" > quit                             Quit\n";

void ShowPrompt (_In_ IGpioPin* pin)
{
    auto listener = Callback<IGpioPinValueChangedHandler>([] (
        _In_ IGpioPin* /*Pin*/,
        _In_ IGpioPinValueChangedEventArgs* Args
        ) -> HRESULT
    {
        GpioPinEdge edge;
        Args->get_Edge(&edge);
        wprintf(L"%s edge occurred.\n", StringFromGpioPinEdge(edge));
        return S_OK;
    });

    auto token = EventRegistrationToken();
    bool listenerRegistered = false;

    GpioPinValue outputLatch = GpioPinValue_High;
    while (std::wcin) {
        wprintf(L"> ");

        std::wstring line;
        if (!std::getline(std::wcin, line)) {
            return;
        }
        std::wistringstream linestream(line);

        std::wstring command;
        linestream >> command;
        if ((command == L"q") || (command == L"quit")) {
            return;
        } else if ((command == L"h") || (command == L"help")) {
            wprintf(L"%s\n", Help);
        } else if ((command == L"w") || (command == L"write")) {
            GpioPinValue value;
            linestream >> value;
            if (linestream.fail()) {
                wprintf(L"Syntax error: expecting 0 or 1\nUsage: write 0|1\n");
                continue;
            }

            HRESULT hr = pin->Write(value);
            if (FAILED(hr)) {
                wprintf(L"Failed to write pin. (hr = 0x%x)\n", hr);
                continue;
            }
        } else if (command == L"high") {
            HRESULT hr = pin->Write(GpioPinValue_High);
            if (FAILED(hr)) {
                wprintf(L"Failed to write pin. (hr = 0x%x)\n", hr);
                continue;
            }
        } else if (command == L"low") {
            HRESULT hr = pin->Write(GpioPinValue_Low);
            if (FAILED(hr)) {
                wprintf(L"Failed to write pin. (hr = 0x%x)\n", hr);
                continue;
            }
        } else if ((command == L"t") || (command == L"toggle")) {
            outputLatch = !outputLatch;
            HRESULT hr = pin->Write(outputLatch);
            if (FAILED(hr)) {
                wprintf(L"Failed to write pin. (hr = 0x%x)\n", hr);
                continue;
            }
        } else if ((command == L"r") || (command == L"read")) {
            GpioPinValue value;
            HRESULT hr = pin->Read(&value);
            if (FAILED(hr)) {
                wprintf(L"Failed to read pin. (hr = 0x%x)\n", hr);
                continue;
            }
            wprintf(L"%s\n", StringFromGpioPinValue(value));
        } else if (command == L"setdrivemode") {
            GpioPinDriveMode driveMode;
            linestream >> driveMode;
            if (!linestream) {
                wprintf(L"Syntax error: expecting valid drive mode. Type 'help' for usage.\n");
                continue;
            }

            HRESULT hr = pin->SetDriveMode(driveMode);
            if (FAILED(hr)) {
                wprintf(L"Failed to set drive mode. (hr = 0x%x)\n", hr);
                continue;
            }
        } else if ((command == L"int") || (command == L"interrupt")) {
            std::wstring onOrOff;
            linestream >> onOrOff;
            if (onOrOff == L"on") {
                if (listenerRegistered) {
                    wprintf(L"Interrupt listener already registered.\n");
                    continue;
                }

                HRESULT hr = pin->add_ValueChanged(listener.Get(), &token);
                if (FAILED(hr)) {
                    wprintf(
                        L"Failed to add event listener to ValueChanged event. (hr = 0x%x)\n",
                        hr);
                    continue;
                }
                listenerRegistered = true;
            } else if (onOrOff == L"off") {
                if (!listenerRegistered) {
                    wprintf(L"No interrupt listener is currently registered.\n");
                    continue;
                }

                HRESULT hr = pin->remove_ValueChanged(token);
                if (FAILED(hr)) {
                    wprintf(
                        L"Failed to remove ValueChanged event. (hr = 0x%x)\n",
                        hr);
                    continue;
                }
                listenerRegistered = false;
            } else {
                wprintf(
                    L"Expecting 'on' or 'off': %s. Type 'help' for usage.\n",
                    onOrOff.c_str());
            }
        } else if ((command == L"i") || (command == L"info")) {
            int pinNumber;
            pin->get_PinNumber(&pinNumber);
            GpioSharingMode sharingMode;
            pin->get_SharingMode(&sharingMode);
            TimeSpan debounceTimeout;
            pin->get_DebounceTimeout(&debounceTimeout);
            GpioPinDriveMode driveMode;
            pin->GetDriveMode(&driveMode);
            GpioPinValue value;
            pin->Read(&value);

            wprintf(
                L"        Pin Number: %d\n"
                L"      Sharing Mode: %s\n"
                L"  Debounce Timeout: %d ms\n"
                L"        Drive Mode: %s\n"
                L"             Value: %s\n",
                pinNumber,
                StringFromGpioSharingMode(sharingMode),
                int(debounceTimeout.Duration / 10000LL),
                StringFromGpioPinDriveMode(driveMode),
                StringFromGpioPinValue(value));
        } else if (command.empty()) {
            // ignore
        } else {
            wprintf(
                L"Unrecognized command: %s. Type 'help' for command usage.\n",
                command.c_str());
        }
    }
}

PCWSTR Usage =
L"GpioTestTool: Command line GPIO testing utility\n"
L"Usage: %s [-list] PinNumber\n"
L"\n"
L"  -list         List the available pins on the default GPIO controller.\n"
L"  PinNumber     The pin number with which you wish to interact. This\n"
L"                parameter is required.\n"
L"\n"
L"Example:\n"
L"  %s -list\n"
L"  %s 47\n";

void PrintUsage (PCWSTR name)
{
    wprintf(Usage, name, name, name);
}

int __cdecl wmain (_In_ int argc, _In_reads_(argc) wchar_t *argv[])
{
    enum MainReturnValue { Success, Failure };

    if (argc < 2) {
        fwprintf(
            stderr,
            L"Missing required command line parameter PinNumber\n\n");
        PrintUsage(argv[0]);
        return Success;
    }

    PCWSTR arg = argv[1];
    if (!_wcsicmp(arg, L"-h") || !_wcsicmp(arg, L"/h") ||
        !_wcsicmp(arg, L"-?") || !_wcsicmp(arg, L"/?")) {

        PrintUsage(argv[0]);
        return Success;
    }

    RoInitializeWrapper roInit(RO_INIT_MULTITHREADED);
    try {
        if (!_wcsicmp(arg, L"-list") || !_wcsicmp(arg, L"/list")) {
            ListPins();
            return Success;
        } else {
            std::wistringstream is(arg);
            INT32 pinNumber;
            is >> pinNumber;
            if (!is) {
                fwprintf(
                    stderr,
                    L"Expecting integer: %s\nType %s /? for usage.\n",
                    arg,
                    argv[0]);
                return Failure;
            }

            auto pin = MakePin(pinNumber);
            wprintf(L"Type 'help' for a list of commands\n");
            ShowPrompt(pin.Get());
            return Success;
        }
    } catch (const wexception& ex) {
        fwprintf(stderr, L"Error: %s\n", ex.wwhat());
        return Failure;
    }
}
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/*
 $Log$
*/

#include "AliITSDetType.h"
#include "AliITSClusterFinder.h"
#include "AliITSsimulation.h"

ClassImp(AliITSDetType)

AliITSDetType::AliITSDetType(){
    // constructor

    fSegmentation = 0;
    fResponse     = 0;
    fSimulation   = 0;
    fReconst      = 0;
}
//----------------------------------------------------------------------
AliITSDetType::~AliITSDetType(){
    // destructor

    if(fSegmentation!=0) delete fSegmentation; fSegmentation = 0;
    if(fResponse!=0)     delete fResponse;     fResponse     = 0;
    if(fSimulation!=0)   delete fSimulation;   fSimulation   = 0;
    if(fReconst!=0)      delete fReconst;      fReconst      = 0;
}
//______________________________________________________________________
AliITSDetType::AliITSDetType(const AliITSDetType &source){
  //     Copy Constructor

  if(&source == this) return;
  this->fReconst        = source.fReconst;
  this->fSimulation     = source.fSimulation;
  this->fResponse       = source.fResponse;
  this->fSegmentation   = source.fSegmentation;
  this->fDigClassName   = source.fDigClassName;
  this->fClustClassName = source.fClustClassName;
  return;
}
//______________________________________________________________________
AliITSDetType& AliITSDetType::operator=(const AliITSDetType &source){
  //    Assignment operator

  if(&source == this) return *this;
  this->fReconst        = source.fReconst;
  this->fSimulation     = source.fSimulation;
  this->fResponse       = source.fResponse;
  this->fSegmentation   = source.fSegmentation;
  this->fDigClassName   = source.fDigClassName;
  this->fClustClassName = source.fClustClassName;
  return *this;
}
<commit_msg>Patch problem with destructor<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/*
 $Log$
 Revision 1.4  2001/05/01 14:47:45  nilsen
 Fixed destructor so that it destroyes the pointers fSegmentation, fResponse,
 fSimulation, and fReconst if they have been allocated. The two TStrings
 fDigClassName and fClustClassName shoud be destroyed automaticaly. This should
 fix a small memory leak associated with digitization and reconstruction.

*/

#include "AliITSDetType.h"
#include "AliITSClusterFinder.h"
#include "AliITSsimulation.h"

ClassImp(AliITSDetType)

AliITSDetType::AliITSDetType(){
    // constructor

    fSegmentation = 0;
    fResponse     = 0;
    fSimulation   = 0;
    fReconst      = 0;
}
//----------------------------------------------------------------------
AliITSDetType::~AliITSDetType(){
    // destructor

    if(fSegmentation!=0) delete fSegmentation; fSegmentation = 0;
    //    if(fResponse!=0)     delete fResponse;     fResponse     = 0;
    if(fSimulation!=0)   delete fSimulation;   fSimulation   = 0;
    if(fReconst!=0)      delete fReconst;      fReconst      = 0;
}
//______________________________________________________________________
AliITSDetType::AliITSDetType(const AliITSDetType &source){
  //     Copy Constructor

  if(&source == this) return;
  this->fReconst        = source.fReconst;
  this->fSimulation     = source.fSimulation;
  this->fResponse       = source.fResponse;
  this->fSegmentation   = source.fSegmentation;
  this->fDigClassName   = source.fDigClassName;
  this->fClustClassName = source.fClustClassName;
  return;
}
//______________________________________________________________________
AliITSDetType& AliITSDetType::operator=(const AliITSDetType &source){
  //    Assignment operator

  if(&source == this) return *this;
  this->fReconst        = source.fReconst;
  this->fSimulation     = source.fSimulation;
  this->fResponse       = source.fResponse;
  this->fSegmentation   = source.fSegmentation;
  this->fDigClassName   = source.fDigClassName;
  this->fClustClassName = source.fClustClassName;
  return *this;
}
<|endoftext|>


<commit_before>//===- TypeBasedAliasAnalysis.cpp - Type-Based Alias Analysis -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the TypeBasedAliasAnalysis pass, which implements
// metadata-based TBAA.
//
// In LLVM IR, memory does not have types, so LLVM's own type system is not
// suitable for doing TBAA. Instead, metadata is added to the IR to describe
// a type system of a higher level language.
//
// This pass is language-independent. The type system is encoded in
// metadata. This allows this pass to support typical C and C++ TBAA, but
// it can also support custom aliasing behavior for other languages.
//
// This is a work-in-progress. It doesn't work yet, and the metadata
// format isn't stable.
//
// TODO: getModRefBehavior. The AliasAnalysis infrastructure will need to
//       be extended.
// TODO: struct fields
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Module.h"
#include "llvm/Metadata.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;

// For testing purposes, enable TBAA only via a special option.
static cl::opt<bool> EnableTBAA("enable-tbaa");

namespace {
  /// TBAANode - This is a simple wrapper around an MDNode which provides a
  /// higher-level interface by hiding the details of how alias analysis
  /// information is encoded in its operands.
  class TBAANode {
    const MDNode *Node;

  public:
    TBAANode() : Node(0) {}
    explicit TBAANode(const MDNode *N) : Node(N) {}

    /// getNode - Get the MDNode for this TBAANode.
    const MDNode *getNode() const { return Node; }

    /// getParent - Get this TBAANode's Alias tree parent.
    TBAANode getParent() const {
      if (Node->getNumOperands() < 2)
        return TBAANode();
      MDNode *P = dyn_cast_or_null<MDNode>(Node->getOperand(1));
      if (!P)
        return TBAANode();
      // Ok, this node has a valid parent. Return it.
      return TBAANode(P);
    }

    /// TypeIsImmutable - Test if this TBAANode represents a type for objects
    /// which are not modified (by any means) in the context where this
    /// AliasAnalysis is relevant.
    bool TypeIsImmutable() const {
      if (Node->getNumOperands() < 3)
        return false;
      ConstantInt *CI = dyn_cast<ConstantInt>(Node->getOperand(2));
      if (!CI)
        return false;
      // TODO: Think about the encoding.
      return CI->isOne();
    }
  };
}

namespace {
  /// TypeBasedAliasAnalysis - This is a simple alias analysis
  /// implementation that uses TypeBased to answer queries.
  class TypeBasedAliasAnalysis : public ImmutablePass,
                                 public AliasAnalysis {
  public:
    static char ID; // Class identification, replacement for typeinfo
    TypeBasedAliasAnalysis() : ImmutablePass(ID) {
      initializeTypeBasedAliasAnalysisPass(*PassRegistry::getPassRegistry());
    }

    virtual void initializePass() {
      InitializeAliasAnalysis(this);
    }

    /// getAdjustedAnalysisPointer - This method is used when a pass implements
    /// an analysis interface through multiple inheritance.  If needed, it
    /// should override this to adjust the this pointer as needed for the
    /// specified pass info.
    virtual void *getAdjustedAnalysisPointer(const void *PI) {
      if (PI == &AliasAnalysis::ID)
        return (AliasAnalysis*)this;
      return this;
    }

    bool Aliases(const MDNode *A, const MDNode *B) const;

  private:
    virtual void getAnalysisUsage(AnalysisUsage &AU) const;
    virtual AliasResult alias(const Location &LocA, const Location &LocB);
    virtual bool pointsToConstantMemory(const Location &Loc);
  };
}  // End of anonymous namespace

// Register this pass...
char TypeBasedAliasAnalysis::ID = 0;
INITIALIZE_AG_PASS(TypeBasedAliasAnalysis, AliasAnalysis, "tbaa",
                   "Type-Based Alias Analysis", false, true, false)

ImmutablePass *llvm::createTypeBasedAliasAnalysisPass() {
  return new TypeBasedAliasAnalysis();
}

void
TypeBasedAliasAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.setPreservesAll();
  AliasAnalysis::getAnalysisUsage(AU);
}

/// Aliases - Test whether the type represented by A may alias the
/// type represented by B.
bool
TypeBasedAliasAnalysis::Aliases(const MDNode *A,
                                const MDNode *B) const {
  // Keep track of the root node for A and B.
  TBAANode RootA, RootB;

  // Climb the tree from A to see if we reach B.
  for (TBAANode T(A); ; ) {
    if (T.getNode() == B)
      // B is an ancestor of A.
      return true;

    RootA = T;
    T = T.getParent();
    if (!T.getNode())
      break;
  }

  // Climb the tree from B to see if we reach A.
  for (TBAANode T(B); ; ) {
    if (T.getNode() == A)
      // A is an ancestor of B.
      return true;

    RootB = T;
    T = T.getParent();
    if (!T.getNode())
      break;
  }

  // Neither node is an ancestor of the other.

  // If they have different roots, they're part of different potentially
  // unrelated type systems, so we must be conservative.
  if (RootA.getNode() != RootB.getNode())
    return true;

  // If they have the same root, then we've proved there's no alias.
  return false;
}

AliasAnalysis::AliasResult
TypeBasedAliasAnalysis::alias(const Location &LocA,
                              const Location &LocB) {
  if (!EnableTBAA)
    return AliasAnalysis::alias(LocA, LocB);

  // Get the attached MDNodes. If either value lacks a tbaa MDNode, we must
  // be conservative.
  const MDNode *AM = LocA.TBAATag;
  if (!AM) return AliasAnalysis::alias(LocA, LocB);
  const MDNode *BM = LocB.TBAATag;
  if (!BM) return AliasAnalysis::alias(LocA, LocB);

  // If they may alias, chain to the next AliasAnalysis.
  if (Aliases(AM, BM))
    return AliasAnalysis::alias(LocA, LocB);

  // Otherwise return a definitive result.
  return NoAlias;
}

bool TypeBasedAliasAnalysis::pointsToConstantMemory(const Location &Loc) {
  if (!EnableTBAA)
    return AliasAnalysis::pointsToConstantMemory(Loc);

  const MDNode *M = Loc.TBAATag;
  if (!M) return false;

  // If this is an "immutable" type, we can assume the pointer is pointing
  // to constant memory.
  if (TBAANode(M).TypeIsImmutable())
    return true;

  return AliasAnalysis::pointsToConstantMemory(Loc);
}
<commit_msg>Update comments.<commit_after>//===- TypeBasedAliasAnalysis.cpp - Type-Based Alias Analysis -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the TypeBasedAliasAnalysis pass, which implements
// metadata-based TBAA.
//
// In LLVM IR, memory does not have types, so LLVM's own type system is not
// suitable for doing TBAA. Instead, metadata is added to the IR to describe
// a type system of a higher level language.
//
// This pass is language-independent. The type system is encoded in
// metadata. This allows this pass to support typical C and C++ TBAA, but
// it can also support custom aliasing behavior for other languages.
//
// This is a work-in-progress. It doesn't work yet, and the metadata
// format isn't stable.
//
// The current metadata format is very simple. MDNodes have up to three
// fields, e.g.:
//   !0 = metadata !{ !"name", !1, 0 }
// The first field is an identity field. It can be any MDString which
// uniquely identifies the type. The second field identifies the type's
// parent node in the tree, or is null or omitted for a root node.
// If the third field is present, it's an integer which if equal to 1
// indicates that the type is "constant".
//
// TODO: The current metadata encoding scheme doesn't support struct
// fields. For example:
//   struct X {
//     double d;
//     int i;
//   };
//   void foo(struct X *x, struct X *y, double *p) {
//     *x = *y;
//     *p = 0.0;
//   }
// Struct X has a double member, so the store to *x can alias the store to *p.
// Currently it's not possible to precisely describe all the things struct X
// aliases, so struct assignments must use conservative TBAA nodes. There's
// no scheme for attaching metadata to @llvm.memcpy yet either.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Module.h"
#include "llvm/Metadata.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;

// For testing purposes, enable TBAA only via a special option.
static cl::opt<bool> EnableTBAA("enable-tbaa");

namespace {
  /// TBAANode - This is a simple wrapper around an MDNode which provides a
  /// higher-level interface by hiding the details of how alias analysis
  /// information is encoded in its operands.
  class TBAANode {
    const MDNode *Node;

  public:
    TBAANode() : Node(0) {}
    explicit TBAANode(const MDNode *N) : Node(N) {}

    /// getNode - Get the MDNode for this TBAANode.
    const MDNode *getNode() const { return Node; }

    /// getParent - Get this TBAANode's Alias tree parent.
    TBAANode getParent() const {
      if (Node->getNumOperands() < 2)
        return TBAANode();
      MDNode *P = dyn_cast_or_null<MDNode>(Node->getOperand(1));
      if (!P)
        return TBAANode();
      // Ok, this node has a valid parent. Return it.
      return TBAANode(P);
    }

    /// TypeIsImmutable - Test if this TBAANode represents a type for objects
    /// which are not modified (by any means) in the context where this
    /// AliasAnalysis is relevant.
    bool TypeIsImmutable() const {
      if (Node->getNumOperands() < 3)
        return false;
      ConstantInt *CI = dyn_cast<ConstantInt>(Node->getOperand(2));
      if (!CI)
        return false;
      // TODO: Think about the encoding.
      return CI->isOne();
    }
  };
}

namespace {
  /// TypeBasedAliasAnalysis - This is a simple alias analysis
  /// implementation that uses TypeBased to answer queries.
  class TypeBasedAliasAnalysis : public ImmutablePass,
                                 public AliasAnalysis {
  public:
    static char ID; // Class identification, replacement for typeinfo
    TypeBasedAliasAnalysis() : ImmutablePass(ID) {
      initializeTypeBasedAliasAnalysisPass(*PassRegistry::getPassRegistry());
    }

    virtual void initializePass() {
      InitializeAliasAnalysis(this);
    }

    /// getAdjustedAnalysisPointer - This method is used when a pass implements
    /// an analysis interface through multiple inheritance.  If needed, it
    /// should override this to adjust the this pointer as needed for the
    /// specified pass info.
    virtual void *getAdjustedAnalysisPointer(const void *PI) {
      if (PI == &AliasAnalysis::ID)
        return (AliasAnalysis*)this;
      return this;
    }

    bool Aliases(const MDNode *A, const MDNode *B) const;

  private:
    virtual void getAnalysisUsage(AnalysisUsage &AU) const;
    virtual AliasResult alias(const Location &LocA, const Location &LocB);
    virtual bool pointsToConstantMemory(const Location &Loc);
  };
}  // End of anonymous namespace

// Register this pass...
char TypeBasedAliasAnalysis::ID = 0;
INITIALIZE_AG_PASS(TypeBasedAliasAnalysis, AliasAnalysis, "tbaa",
                   "Type-Based Alias Analysis", false, true, false)

ImmutablePass *llvm::createTypeBasedAliasAnalysisPass() {
  return new TypeBasedAliasAnalysis();
}

void
TypeBasedAliasAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.setPreservesAll();
  AliasAnalysis::getAnalysisUsage(AU);
}

/// Aliases - Test whether the type represented by A may alias the
/// type represented by B.
bool
TypeBasedAliasAnalysis::Aliases(const MDNode *A,
                                const MDNode *B) const {
  // Keep track of the root node for A and B.
  TBAANode RootA, RootB;

  // Climb the tree from A to see if we reach B.
  for (TBAANode T(A); ; ) {
    if (T.getNode() == B)
      // B is an ancestor of A.
      return true;

    RootA = T;
    T = T.getParent();
    if (!T.getNode())
      break;
  }

  // Climb the tree from B to see if we reach A.
  for (TBAANode T(B); ; ) {
    if (T.getNode() == A)
      // A is an ancestor of B.
      return true;

    RootB = T;
    T = T.getParent();
    if (!T.getNode())
      break;
  }

  // Neither node is an ancestor of the other.

  // If they have different roots, they're part of different potentially
  // unrelated type systems, so we must be conservative.
  if (RootA.getNode() != RootB.getNode())
    return true;

  // If they have the same root, then we've proved there's no alias.
  return false;
}

AliasAnalysis::AliasResult
TypeBasedAliasAnalysis::alias(const Location &LocA,
                              const Location &LocB) {
  if (!EnableTBAA)
    return AliasAnalysis::alias(LocA, LocB);

  // Get the attached MDNodes. If either value lacks a tbaa MDNode, we must
  // be conservative.
  const MDNode *AM = LocA.TBAATag;
  if (!AM) return AliasAnalysis::alias(LocA, LocB);
  const MDNode *BM = LocB.TBAATag;
  if (!BM) return AliasAnalysis::alias(LocA, LocB);

  // If they may alias, chain to the next AliasAnalysis.
  if (Aliases(AM, BM))
    return AliasAnalysis::alias(LocA, LocB);

  // Otherwise return a definitive result.
  return NoAlias;
}

bool TypeBasedAliasAnalysis::pointsToConstantMemory(const Location &Loc) {
  if (!EnableTBAA)
    return AliasAnalysis::pointsToConstantMemory(Loc);

  const MDNode *M = Loc.TBAATag;
  if (!M) return false;

  // If this is an "immutable" type, we can assume the pointer is pointing
  // to constant memory.
  if (TBAANode(M).TypeIsImmutable())
    return true;

  return AliasAnalysis::pointsToConstantMemory(Loc);
}
<|endoftext|>


<commit_before>//===-- AMDGPUPromoteAlloca.cpp - Promote Allocas -------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass eliminates allocas by either converting them into vectors or
// by migrating them to local address space.
//
//===----------------------------------------------------------------------===//

#include "AMDGPU.h"
#include "AMDGPUSubtarget.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstVisitor.h"
#include "llvm/Support/Debug.h"

#define DEBUG_TYPE "amdgpu-promote-alloca"

using namespace llvm;

namespace {

class AMDGPUPromoteAlloca : public FunctionPass,
                       public InstVisitor<AMDGPUPromoteAlloca> {

  static char ID;
  Module *Mod;
  const AMDGPUSubtarget &ST;
  int LocalMemAvailable;

public:
  AMDGPUPromoteAlloca(const AMDGPUSubtarget &st) : FunctionPass(ID), ST(st),
                                                   LocalMemAvailable(0) { }
  bool doInitialization(Module &M) override;
  bool runOnFunction(Function &F) override;
  const char *getPassName() const override { return "AMDGPU Promote Alloca"; }
  void visitAlloca(AllocaInst &I);
};

} // End anonymous namespace

char AMDGPUPromoteAlloca::ID = 0;

bool AMDGPUPromoteAlloca::doInitialization(Module &M) {
  Mod = &M;
  return false;
}

bool AMDGPUPromoteAlloca::runOnFunction(Function &F) {

  const FunctionType *FTy = F.getFunctionType();

  LocalMemAvailable = ST.getLocalMemorySize();

  // If the function has any arguments in the local address space, then it's
  // possible these arguments require the entire local memory space, so
  // we cannot use local memory in the pass.
  for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i) {
    const Type *ParamTy = FTy->getParamType(i);
    if (ParamTy->isPointerTy() &&
        ParamTy->getPointerAddressSpace() == AMDGPUAS::LOCAL_ADDRESS) {
      LocalMemAvailable = 0;
      DEBUG(dbgs() << "Function has local memory argument.  Promoting to "
                      "local memory disabled.\n");
      break;
    }
  }

  if (LocalMemAvailable > 0) {
    // Check how much local memory is being used by global objects
    for (Module::global_iterator I = Mod->global_begin(),
                                 E = Mod->global_end(); I != E; ++I) {
      GlobalVariable *GV = I;
      PointerType *GVTy = GV->getType();
      if (GVTy->getAddressSpace() != AMDGPUAS::LOCAL_ADDRESS)
        continue;
      for (Value::use_iterator U = GV->use_begin(),
                               UE = GV->use_end(); U != UE; ++U) {
        Instruction *Use = dyn_cast<Instruction>(*U);
        if (!Use)
          continue;
        if (Use->getParent()->getParent() == &F)
          LocalMemAvailable -=
              Mod->getDataLayout()->getTypeAllocSize(GVTy->getElementType());
      }
    }
  }

  LocalMemAvailable = std::max(0, LocalMemAvailable);
  DEBUG(dbgs() << LocalMemAvailable << "bytes free in local memory.\n");

  visit(F);

  return false;
}

static VectorType *arrayTypeToVecType(const Type *ArrayTy) {
  return VectorType::get(ArrayTy->getArrayElementType(),
                         ArrayTy->getArrayNumElements());
}

static Value* calculateVectorIndex(Value *Ptr,
                                  std::map<GetElementPtrInst*, Value*> GEPIdx) {
  if (isa<AllocaInst>(Ptr))
    return Constant::getNullValue(Type::getInt32Ty(Ptr->getContext()));

  GetElementPtrInst *GEP = cast<GetElementPtrInst>(Ptr);

  return GEPIdx[GEP];
}

static Value* GEPToVectorIndex(GetElementPtrInst *GEP) {
  // FIXME we only support simple cases
  if (GEP->getNumOperands() != 3)
    return NULL;

  ConstantInt *I0 = dyn_cast<ConstantInt>(GEP->getOperand(1));
  if (!I0 || !I0->isZero())
    return NULL;

  return GEP->getOperand(2);
}

// Not an instruction handled below to turn into a vector.
//
// TODO: Check isTriviallyVectorizable for calls and handle other
// instructions.
static bool canVectorizeInst(Instruction *Inst) {
  switch (Inst->getOpcode()) {
  case Instruction::Load:
  case Instruction::Store:
  case Instruction::BitCast:
  case Instruction::AddrSpaceCast:
    return true;
  default:
    return false;
  }
}

static bool tryPromoteAllocaToVector(AllocaInst *Alloca) {
  Type *AllocaTy = Alloca->getAllocatedType();

  DEBUG(dbgs() << "Alloca Candidate for vectorization \n");

  // FIXME: There is no reason why we can't support larger arrays, we
  // are just being conservative for now.
  if (!AllocaTy->isArrayTy() ||
      AllocaTy->getArrayElementType()->isVectorTy() ||
      AllocaTy->getArrayNumElements() > 4) {

    DEBUG(dbgs() << "  Cannot convert type to vector");
    return false;
  }

  std::map<GetElementPtrInst*, Value*> GEPVectorIdx;
  std::vector<Value*> WorkList;
  for (User *AllocaUser : Alloca->users()) {
    GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(AllocaUser);
    if (!GEP) {
      if (!canVectorizeInst(cast<Instruction>(AllocaUser)))
        return false;

      WorkList.push_back(AllocaUser);
      continue;
    }

    Value *Index = GEPToVectorIndex(GEP);

    // If we can't compute a vector index from this GEP, then we can't
    // promote this alloca to vector.
    if (!Index) {
      DEBUG(dbgs() << "  Cannot compute vector index for GEP " << *GEP << '\n');
      return false;
    }

    GEPVectorIdx[GEP] = Index;
    for (User *GEPUser : AllocaUser->users()) {
      if (!canVectorizeInst(cast<Instruction>(GEPUser)))
        return false;

      WorkList.push_back(GEPUser);
    }
  }

  VectorType *VectorTy = arrayTypeToVecType(AllocaTy);

  DEBUG(dbgs() << "  Converting alloca to vector "
        << *AllocaTy << " -> " << *VectorTy << '\n');

  for (std::vector<Value*>::iterator I = WorkList.begin(),
                                     E = WorkList.end(); I != E; ++I) {
    Instruction *Inst = cast<Instruction>(*I);
    IRBuilder<> Builder(Inst);
    switch (Inst->getOpcode()) {
    case Instruction::Load: {
      Value *Ptr = Inst->getOperand(0);
      Value *Index = calculateVectorIndex(Ptr, GEPVectorIdx);
      Value *BitCast = Builder.CreateBitCast(Alloca, VectorTy->getPointerTo(0));
      Value *VecValue = Builder.CreateLoad(BitCast);
      Value *ExtractElement = Builder.CreateExtractElement(VecValue, Index);
      Inst->replaceAllUsesWith(ExtractElement);
      Inst->eraseFromParent();
      break;
    }
    case Instruction::Store: {
      Value *Ptr = Inst->getOperand(1);
      Value *Index = calculateVectorIndex(Ptr, GEPVectorIdx);
      Value *BitCast = Builder.CreateBitCast(Alloca, VectorTy->getPointerTo(0));
      Value *VecValue = Builder.CreateLoad(BitCast);
      Value *NewVecValue = Builder.CreateInsertElement(VecValue,
                                                       Inst->getOperand(0),
                                                       Index);
      Builder.CreateStore(NewVecValue, BitCast);
      Inst->eraseFromParent();
      break;
    }
    case Instruction::BitCast:
    case Instruction::AddrSpaceCast:
      break;

    default:
      Inst->dump();
      llvm_unreachable("Inconsistency in instructions promotable to vector");
    }
  }
  return true;
}

static void collectUsesWithPtrTypes(Value *Val, std::vector<Value*> &WorkList) {
  for (User *User : Val->users()) {
    if(std::find(WorkList.begin(), WorkList.end(), User) != WorkList.end())
      continue;
    if (isa<CallInst>(User)) {
      WorkList.push_back(User);
      continue;
    }
    if (!User->getType()->isPointerTy())
      continue;
    WorkList.push_back(User);
    collectUsesWithPtrTypes(User, WorkList);
  }
}

void AMDGPUPromoteAlloca::visitAlloca(AllocaInst &I) {
  IRBuilder<> Builder(&I);

  // First try to replace the alloca with a vector
  Type *AllocaTy = I.getAllocatedType();

  DEBUG(dbgs() << "Trying to promote " << I << '\n');

  if (tryPromoteAllocaToVector(&I))
    return;

  DEBUG(dbgs() << " alloca is not a candidate for vectorization.\n");

  // FIXME: This is the maximum work group size.  We should try to get
  // value from the reqd_work_group_size function attribute if it is
  // available.
  unsigned WorkGroupSize = 256;
  int AllocaSize = WorkGroupSize *
      Mod->getDataLayout()->getTypeAllocSize(AllocaTy);

  if (AllocaSize > LocalMemAvailable) {
    DEBUG(dbgs() << " Not enough local memory to promote alloca.\n");
    return;
  }

  DEBUG(dbgs() << "Promoting alloca to local memory\n");
  LocalMemAvailable -= AllocaSize;

  GlobalVariable *GV = new GlobalVariable(
      *Mod, ArrayType::get(I.getAllocatedType(), 256), false,
      GlobalValue::ExternalLinkage, 0, I.getName(), 0,
      GlobalVariable::NotThreadLocal, AMDGPUAS::LOCAL_ADDRESS);

  FunctionType *FTy = FunctionType::get(
      Type::getInt32Ty(Mod->getContext()), false);
  AttributeSet AttrSet;
  AttrSet.addAttribute(Mod->getContext(), 0, Attribute::ReadNone);

  Value *ReadLocalSizeY = Mod->getOrInsertFunction(
      "llvm.r600.read.local.size.y", FTy, AttrSet);
  Value *ReadLocalSizeZ = Mod->getOrInsertFunction(
      "llvm.r600.read.local.size.z", FTy, AttrSet);
  Value *ReadTIDIGX = Mod->getOrInsertFunction(
      "llvm.r600.read.tidig.x", FTy, AttrSet);
  Value *ReadTIDIGY = Mod->getOrInsertFunction(
      "llvm.r600.read.tidig.y", FTy, AttrSet);
  Value *ReadTIDIGZ = Mod->getOrInsertFunction(
      "llvm.r600.read.tidig.z", FTy, AttrSet);

  Value *TCntY = Builder.CreateCall(ReadLocalSizeY);
  Value *TCntZ = Builder.CreateCall(ReadLocalSizeZ);
  Value *TIdX  = Builder.CreateCall(ReadTIDIGX);
  Value *TIdY  = Builder.CreateCall(ReadTIDIGY);
  Value *TIdZ  = Builder.CreateCall(ReadTIDIGZ);

  Value *Tmp0 = Builder.CreateMul(TCntY, TCntZ);
  Tmp0 = Builder.CreateMul(Tmp0, TIdX);
  Value *Tmp1 = Builder.CreateMul(TIdY, TCntZ);
  Value *TID = Builder.CreateAdd(Tmp0, Tmp1);
  TID = Builder.CreateAdd(TID, TIdZ);

  std::vector<Value*> Indices;
  Indices.push_back(Constant::getNullValue(Type::getInt32Ty(Mod->getContext())));
  Indices.push_back(TID);

  Value *Offset = Builder.CreateGEP(GV, Indices);
  I.mutateType(Offset->getType());
  I.replaceAllUsesWith(Offset);
  I.eraseFromParent();

  std::vector<Value*> WorkList;

  collectUsesWithPtrTypes(Offset, WorkList);

  for (std::vector<Value*>::iterator i = WorkList.begin(),
                                     e = WorkList.end(); i != e; ++i) {
    Value *V = *i;
    CallInst *Call = dyn_cast<CallInst>(V);
    if (!Call) {
      Type *EltTy = V->getType()->getPointerElementType();
      PointerType *NewTy = PointerType::get(EltTy, AMDGPUAS::LOCAL_ADDRESS);
      V->mutateType(NewTy);
      continue;
    }

    IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(Call);
    if (!Intr) {
      std::vector<Type*> ArgTypes;
      for (unsigned ArgIdx = 0, ArgEnd = Call->getNumArgOperands();
                                ArgIdx != ArgEnd; ++ArgIdx) {
        ArgTypes.push_back(Call->getArgOperand(ArgIdx)->getType());
      }
      Function *F = Call->getCalledFunction();
      FunctionType *NewType = FunctionType::get(Call->getType(), ArgTypes,
                                                F->isVarArg());
      Constant *C = Mod->getOrInsertFunction(StringRef(F->getName().str() + ".local"), NewType,
                                             F->getAttributes());
      Function *NewF = cast<Function>(C);
      Call->setCalledFunction(NewF);
      continue;
    }

    Builder.SetInsertPoint(Intr);
    switch (Intr->getIntrinsicID()) {
    case Intrinsic::lifetime_start:
    case Intrinsic::lifetime_end:
      // These intrinsics are for address space 0 only
      Intr->eraseFromParent();
      continue;
    case Intrinsic::memcpy: {
      MemCpyInst *MemCpy = cast<MemCpyInst>(Intr);
      Builder.CreateMemCpy(MemCpy->getRawDest(), MemCpy->getRawSource(),
                           MemCpy->getLength(), MemCpy->getAlignment(),
                           MemCpy->isVolatile());
      Intr->eraseFromParent();
      continue;
    }
    case Intrinsic::memset: {
      MemSetInst *MemSet = cast<MemSetInst>(Intr);
      Builder.CreateMemSet(MemSet->getRawDest(), MemSet->getValue(),
                           MemSet->getLength(), MemSet->getAlignment(),
                           MemSet->isVolatile());
      Intr->eraseFromParent();
      continue;
    }
    default:
      Intr->dump();
      llvm_unreachable("Don't know how to promote alloca intrinsic use.");
    }
  }
}

FunctionPass *llvm::createAMDGPUPromoteAlloca(const AMDGPUSubtarget &ST) {
  return new AMDGPUPromoteAlloca(ST);
}
<commit_msg>R600/SI: Fix promote alloca pass breaking addrspacecast<commit_after>//===-- AMDGPUPromoteAlloca.cpp - Promote Allocas -------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass eliminates allocas by either converting them into vectors or
// by migrating them to local address space.
//
//===----------------------------------------------------------------------===//

#include "AMDGPU.h"
#include "AMDGPUSubtarget.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstVisitor.h"
#include "llvm/Support/Debug.h"

#define DEBUG_TYPE "amdgpu-promote-alloca"

using namespace llvm;

namespace {

class AMDGPUPromoteAlloca : public FunctionPass,
                       public InstVisitor<AMDGPUPromoteAlloca> {

  static char ID;
  Module *Mod;
  const AMDGPUSubtarget &ST;
  int LocalMemAvailable;

public:
  AMDGPUPromoteAlloca(const AMDGPUSubtarget &st) : FunctionPass(ID), ST(st),
                                                   LocalMemAvailable(0) { }
  bool doInitialization(Module &M) override;
  bool runOnFunction(Function &F) override;
  const char *getPassName() const override { return "AMDGPU Promote Alloca"; }
  void visitAlloca(AllocaInst &I);
};

} // End anonymous namespace

char AMDGPUPromoteAlloca::ID = 0;

bool AMDGPUPromoteAlloca::doInitialization(Module &M) {
  Mod = &M;
  return false;
}

bool AMDGPUPromoteAlloca::runOnFunction(Function &F) {

  const FunctionType *FTy = F.getFunctionType();

  LocalMemAvailable = ST.getLocalMemorySize();

  // If the function has any arguments in the local address space, then it's
  // possible these arguments require the entire local memory space, so
  // we cannot use local memory in the pass.
  for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i) {
    const Type *ParamTy = FTy->getParamType(i);
    if (ParamTy->isPointerTy() &&
        ParamTy->getPointerAddressSpace() == AMDGPUAS::LOCAL_ADDRESS) {
      LocalMemAvailable = 0;
      DEBUG(dbgs() << "Function has local memory argument.  Promoting to "
                      "local memory disabled.\n");
      break;
    }
  }

  if (LocalMemAvailable > 0) {
    // Check how much local memory is being used by global objects
    for (Module::global_iterator I = Mod->global_begin(),
                                 E = Mod->global_end(); I != E; ++I) {
      GlobalVariable *GV = I;
      PointerType *GVTy = GV->getType();
      if (GVTy->getAddressSpace() != AMDGPUAS::LOCAL_ADDRESS)
        continue;
      for (Value::use_iterator U = GV->use_begin(),
                               UE = GV->use_end(); U != UE; ++U) {
        Instruction *Use = dyn_cast<Instruction>(*U);
        if (!Use)
          continue;
        if (Use->getParent()->getParent() == &F)
          LocalMemAvailable -=
              Mod->getDataLayout()->getTypeAllocSize(GVTy->getElementType());
      }
    }
  }

  LocalMemAvailable = std::max(0, LocalMemAvailable);
  DEBUG(dbgs() << LocalMemAvailable << "bytes free in local memory.\n");

  visit(F);

  return false;
}

static VectorType *arrayTypeToVecType(const Type *ArrayTy) {
  return VectorType::get(ArrayTy->getArrayElementType(),
                         ArrayTy->getArrayNumElements());
}

static Value* calculateVectorIndex(Value *Ptr,
                                  std::map<GetElementPtrInst*, Value*> GEPIdx) {
  if (isa<AllocaInst>(Ptr))
    return Constant::getNullValue(Type::getInt32Ty(Ptr->getContext()));

  GetElementPtrInst *GEP = cast<GetElementPtrInst>(Ptr);

  return GEPIdx[GEP];
}

static Value* GEPToVectorIndex(GetElementPtrInst *GEP) {
  // FIXME we only support simple cases
  if (GEP->getNumOperands() != 3)
    return NULL;

  ConstantInt *I0 = dyn_cast<ConstantInt>(GEP->getOperand(1));
  if (!I0 || !I0->isZero())
    return NULL;

  return GEP->getOperand(2);
}

// Not an instruction handled below to turn into a vector.
//
// TODO: Check isTriviallyVectorizable for calls and handle other
// instructions.
static bool canVectorizeInst(Instruction *Inst) {
  switch (Inst->getOpcode()) {
  case Instruction::Load:
  case Instruction::Store:
  case Instruction::BitCast:
  case Instruction::AddrSpaceCast:
    return true;
  default:
    return false;
  }
}

static bool tryPromoteAllocaToVector(AllocaInst *Alloca) {
  Type *AllocaTy = Alloca->getAllocatedType();

  DEBUG(dbgs() << "Alloca Candidate for vectorization \n");

  // FIXME: There is no reason why we can't support larger arrays, we
  // are just being conservative for now.
  if (!AllocaTy->isArrayTy() ||
      AllocaTy->getArrayElementType()->isVectorTy() ||
      AllocaTy->getArrayNumElements() > 4) {

    DEBUG(dbgs() << "  Cannot convert type to vector");
    return false;
  }

  std::map<GetElementPtrInst*, Value*> GEPVectorIdx;
  std::vector<Value*> WorkList;
  for (User *AllocaUser : Alloca->users()) {
    GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(AllocaUser);
    if (!GEP) {
      if (!canVectorizeInst(cast<Instruction>(AllocaUser)))
        return false;

      WorkList.push_back(AllocaUser);
      continue;
    }

    Value *Index = GEPToVectorIndex(GEP);

    // If we can't compute a vector index from this GEP, then we can't
    // promote this alloca to vector.
    if (!Index) {
      DEBUG(dbgs() << "  Cannot compute vector index for GEP " << *GEP << '\n');
      return false;
    }

    GEPVectorIdx[GEP] = Index;
    for (User *GEPUser : AllocaUser->users()) {
      if (!canVectorizeInst(cast<Instruction>(GEPUser)))
        return false;

      WorkList.push_back(GEPUser);
    }
  }

  VectorType *VectorTy = arrayTypeToVecType(AllocaTy);

  DEBUG(dbgs() << "  Converting alloca to vector "
        << *AllocaTy << " -> " << *VectorTy << '\n');

  for (std::vector<Value*>::iterator I = WorkList.begin(),
                                     E = WorkList.end(); I != E; ++I) {
    Instruction *Inst = cast<Instruction>(*I);
    IRBuilder<> Builder(Inst);
    switch (Inst->getOpcode()) {
    case Instruction::Load: {
      Value *Ptr = Inst->getOperand(0);
      Value *Index = calculateVectorIndex(Ptr, GEPVectorIdx);
      Value *BitCast = Builder.CreateBitCast(Alloca, VectorTy->getPointerTo(0));
      Value *VecValue = Builder.CreateLoad(BitCast);
      Value *ExtractElement = Builder.CreateExtractElement(VecValue, Index);
      Inst->replaceAllUsesWith(ExtractElement);
      Inst->eraseFromParent();
      break;
    }
    case Instruction::Store: {
      Value *Ptr = Inst->getOperand(1);
      Value *Index = calculateVectorIndex(Ptr, GEPVectorIdx);
      Value *BitCast = Builder.CreateBitCast(Alloca, VectorTy->getPointerTo(0));
      Value *VecValue = Builder.CreateLoad(BitCast);
      Value *NewVecValue = Builder.CreateInsertElement(VecValue,
                                                       Inst->getOperand(0),
                                                       Index);
      Builder.CreateStore(NewVecValue, BitCast);
      Inst->eraseFromParent();
      break;
    }
    case Instruction::BitCast:
    case Instruction::AddrSpaceCast:
      break;

    default:
      Inst->dump();
      llvm_unreachable("Inconsistency in instructions promotable to vector");
    }
  }
  return true;
}

static void collectUsesWithPtrTypes(Value *Val, std::vector<Value*> &WorkList) {
  for (User *User : Val->users()) {
    if(std::find(WorkList.begin(), WorkList.end(), User) != WorkList.end())
      continue;
    if (isa<CallInst>(User)) {
      WorkList.push_back(User);
      continue;
    }
    if (!User->getType()->isPointerTy())
      continue;
    WorkList.push_back(User);
    collectUsesWithPtrTypes(User, WorkList);
  }
}

void AMDGPUPromoteAlloca::visitAlloca(AllocaInst &I) {
  IRBuilder<> Builder(&I);

  // First try to replace the alloca with a vector
  Type *AllocaTy = I.getAllocatedType();

  DEBUG(dbgs() << "Trying to promote " << I << '\n');

  if (tryPromoteAllocaToVector(&I))
    return;

  DEBUG(dbgs() << " alloca is not a candidate for vectorization.\n");

  // FIXME: This is the maximum work group size.  We should try to get
  // value from the reqd_work_group_size function attribute if it is
  // available.
  unsigned WorkGroupSize = 256;
  int AllocaSize = WorkGroupSize *
      Mod->getDataLayout()->getTypeAllocSize(AllocaTy);

  if (AllocaSize > LocalMemAvailable) {
    DEBUG(dbgs() << " Not enough local memory to promote alloca.\n");
    return;
  }

  DEBUG(dbgs() << "Promoting alloca to local memory\n");
  LocalMemAvailable -= AllocaSize;

  GlobalVariable *GV = new GlobalVariable(
      *Mod, ArrayType::get(I.getAllocatedType(), 256), false,
      GlobalValue::ExternalLinkage, 0, I.getName(), 0,
      GlobalVariable::NotThreadLocal, AMDGPUAS::LOCAL_ADDRESS);

  FunctionType *FTy = FunctionType::get(
      Type::getInt32Ty(Mod->getContext()), false);
  AttributeSet AttrSet;
  AttrSet.addAttribute(Mod->getContext(), 0, Attribute::ReadNone);

  Value *ReadLocalSizeY = Mod->getOrInsertFunction(
      "llvm.r600.read.local.size.y", FTy, AttrSet);
  Value *ReadLocalSizeZ = Mod->getOrInsertFunction(
      "llvm.r600.read.local.size.z", FTy, AttrSet);
  Value *ReadTIDIGX = Mod->getOrInsertFunction(
      "llvm.r600.read.tidig.x", FTy, AttrSet);
  Value *ReadTIDIGY = Mod->getOrInsertFunction(
      "llvm.r600.read.tidig.y", FTy, AttrSet);
  Value *ReadTIDIGZ = Mod->getOrInsertFunction(
      "llvm.r600.read.tidig.z", FTy, AttrSet);

  Value *TCntY = Builder.CreateCall(ReadLocalSizeY);
  Value *TCntZ = Builder.CreateCall(ReadLocalSizeZ);
  Value *TIdX  = Builder.CreateCall(ReadTIDIGX);
  Value *TIdY  = Builder.CreateCall(ReadTIDIGY);
  Value *TIdZ  = Builder.CreateCall(ReadTIDIGZ);

  Value *Tmp0 = Builder.CreateMul(TCntY, TCntZ);
  Tmp0 = Builder.CreateMul(Tmp0, TIdX);
  Value *Tmp1 = Builder.CreateMul(TIdY, TCntZ);
  Value *TID = Builder.CreateAdd(Tmp0, Tmp1);
  TID = Builder.CreateAdd(TID, TIdZ);

  std::vector<Value*> Indices;
  Indices.push_back(Constant::getNullValue(Type::getInt32Ty(Mod->getContext())));
  Indices.push_back(TID);

  Value *Offset = Builder.CreateGEP(GV, Indices);
  I.mutateType(Offset->getType());
  I.replaceAllUsesWith(Offset);
  I.eraseFromParent();

  std::vector<Value*> WorkList;

  collectUsesWithPtrTypes(Offset, WorkList);

  for (std::vector<Value*>::iterator i = WorkList.begin(),
                                     e = WorkList.end(); i != e; ++i) {
    Value *V = *i;
    CallInst *Call = dyn_cast<CallInst>(V);
    if (!Call) {
      Type *EltTy = V->getType()->getPointerElementType();
      PointerType *NewTy = PointerType::get(EltTy, AMDGPUAS::LOCAL_ADDRESS);

      // The operand's value should be corrected on its own.
      if (isa<AddrSpaceCastInst>(V))
        continue;

      // FIXME: It doesn't really make sense to try to do this for all
      // instructions.
      V->mutateType(NewTy);
      continue;
    }

    IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(Call);
    if (!Intr) {
      std::vector<Type*> ArgTypes;
      for (unsigned ArgIdx = 0, ArgEnd = Call->getNumArgOperands();
                                ArgIdx != ArgEnd; ++ArgIdx) {
        ArgTypes.push_back(Call->getArgOperand(ArgIdx)->getType());
      }
      Function *F = Call->getCalledFunction();
      FunctionType *NewType = FunctionType::get(Call->getType(), ArgTypes,
                                                F->isVarArg());
      Constant *C = Mod->getOrInsertFunction(StringRef(F->getName().str() + ".local"), NewType,
                                             F->getAttributes());
      Function *NewF = cast<Function>(C);
      Call->setCalledFunction(NewF);
      continue;
    }

    Builder.SetInsertPoint(Intr);
    switch (Intr->getIntrinsicID()) {
    case Intrinsic::lifetime_start:
    case Intrinsic::lifetime_end:
      // These intrinsics are for address space 0 only
      Intr->eraseFromParent();
      continue;
    case Intrinsic::memcpy: {
      MemCpyInst *MemCpy = cast<MemCpyInst>(Intr);
      Builder.CreateMemCpy(MemCpy->getRawDest(), MemCpy->getRawSource(),
                           MemCpy->getLength(), MemCpy->getAlignment(),
                           MemCpy->isVolatile());
      Intr->eraseFromParent();
      continue;
    }
    case Intrinsic::memset: {
      MemSetInst *MemSet = cast<MemSetInst>(Intr);
      Builder.CreateMemSet(MemSet->getRawDest(), MemSet->getValue(),
                           MemSet->getLength(), MemSet->getAlignment(),
                           MemSet->isVolatile());
      Intr->eraseFromParent();
      continue;
    }
    default:
      Intr->dump();
      llvm_unreachable("Don't know how to promote alloca intrinsic use.");
    }
  }
}

FunctionPass *llvm::createAMDGPUPromoteAlloca(const AMDGPUSubtarget &ST) {
  return new AMDGPUPromoteAlloca(ST);
}
<|endoftext|>


<commit_before>//===-- CondPropagate.cpp - Propagate Conditional Expressions -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass propagates information about conditional expressions through the
// program, allowing it to eliminate conditional branches in some cases.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "condprop"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Pass.h"
#include "llvm/Type.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Streams.h"
using namespace llvm;

STATISTIC(NumBrThread, "Number of CFG edges threaded through branches");
STATISTIC(NumSwThread, "Number of CFG edges threaded through switches");

namespace {
  struct VISIBILITY_HIDDEN CondProp : public FunctionPass {
    static char ID; // Pass identification, replacement for typeid
    CondProp() : FunctionPass(&ID) {}

    virtual bool runOnFunction(Function &F);

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequiredID(BreakCriticalEdgesID);
      //AU.addRequired<DominanceFrontier>();
    }

  private:
    bool MadeChange;
    SmallVector<BasicBlock *, 4> DeadBlocks;
    void SimplifyBlock(BasicBlock *BB);
    void SimplifyPredecessors(BranchInst *BI);
    void SimplifyPredecessors(SwitchInst *SI);
    void RevectorBlockTo(BasicBlock *FromBB, BasicBlock *ToBB);
  };
}

char CondProp::ID = 0;
static RegisterPass<CondProp> X("condprop", "Conditional Propagation");

FunctionPass *llvm::createCondPropagationPass() {
  return new CondProp();
}

bool CondProp::runOnFunction(Function &F) {
  bool EverMadeChange = false;
  DeadBlocks.clear();

  // While we are simplifying blocks, keep iterating.
  do {
    MadeChange = false;
    for (Function::iterator BB = F.begin(), E = F.end(); BB != E;)
      SimplifyBlock(BB++);
    EverMadeChange = EverMadeChange || MadeChange;
  } while (MadeChange);

  if (EverMadeChange) {
    while (!DeadBlocks.empty()) {
      BasicBlock *BB = DeadBlocks.back(); DeadBlocks.pop_back();
      DeleteDeadBlock(BB);
    }
  }
  return EverMadeChange;
}

void CondProp::SimplifyBlock(BasicBlock *BB) {
  if (BranchInst *BI = dyn_cast<BranchInst>(BB->getTerminator())) {
    // If this is a conditional branch based on a phi node that is defined in
    // this block, see if we can simplify predecessors of this block.
    if (BI->isConditional() && isa<PHINode>(BI->getCondition()) &&
        cast<PHINode>(BI->getCondition())->getParent() == BB)
      SimplifyPredecessors(BI);

  } else if (SwitchInst *SI = dyn_cast<SwitchInst>(BB->getTerminator())) {
    if (isa<PHINode>(SI->getCondition()) &&
        cast<PHINode>(SI->getCondition())->getParent() == BB)
      SimplifyPredecessors(SI);
  }

  // If possible, simplify the terminator of this block.
  if (ConstantFoldTerminator(BB))
    MadeChange = true;

  // If this block ends with an unconditional branch and the only successor has
  // only this block as a predecessor, merge the two blocks together.
  if (BranchInst *BI = dyn_cast<BranchInst>(BB->getTerminator()))
    if (BI->isUnconditional() && BI->getSuccessor(0)->getSinglePredecessor() &&
        BB != BI->getSuccessor(0)) {
      BasicBlock *Succ = BI->getSuccessor(0);

      // If Succ has any PHI nodes, they are all single-entry PHI's.  Eliminate
      // them.
      FoldSingleEntryPHINodes(Succ);

      // Remove BI.
      BI->eraseFromParent();

      // Move over all of the instructions.
      BB->getInstList().splice(BB->end(), Succ->getInstList());

      // Any phi nodes that had entries for Succ now have entries from BB.
      Succ->replaceAllUsesWith(BB);

      // Succ is now dead, but we cannot delete it without potentially
      // invalidating iterators elsewhere.  Just insert an unreachable
      // instruction in it and delete this block later on.
      new UnreachableInst(Succ);
      DeadBlocks.push_back(Succ);
      MadeChange = true;
    }
}

// SimplifyPredecessors(branches) - We know that BI is a conditional branch
// based on a PHI node defined in this block.  If the phi node contains constant
// operands, then the blocks corresponding to those operands can be modified to
// jump directly to the destination instead of going through this block.
void CondProp::SimplifyPredecessors(BranchInst *BI) {
  // TODO: We currently only handle the most trival case, where the PHI node has
  // one use (the branch), and is the only instruction besides the branch and dbg
  // intrinsics in the block.
  PHINode *PN = cast<PHINode>(BI->getCondition());

  if (PN->getNumIncomingValues() == 1) {
    // Eliminate single-entry PHI nodes.
    FoldSingleEntryPHINodes(PN->getParent());
    return;
  }

  if (!PN->hasOneUse()) return;

  BasicBlock *BB = BI->getParent();
  if (&*BB->begin() != PN)
    return;
  BasicBlock::iterator BBI = BB->begin();
  BasicBlock::iterator BBE = BB->end();
  while (BBI != BBE && isa<DbgInfoIntrinsic>(++BBI)) ;
  if (&*BBI != BI)
    return;

  // Ok, we have this really simple case, walk the PHI operands, looking for
  // constants.  Walk from the end to remove operands from the end when
  // possible, and to avoid invalidating "i".
  for (unsigned i = PN->getNumIncomingValues(); i != 0; --i)
    if (ConstantInt *CB = dyn_cast<ConstantInt>(PN->getIncomingValue(i-1))) {
      // If we have a constant, forward the edge from its current to its
      // ultimate destination.
      RevectorBlockTo(PN->getIncomingBlock(i-1),
                      BI->getSuccessor(CB->isZero()));
      ++NumBrThread;

      // If there were two predecessors before this simplification, or if the
      // PHI node contained all the same value except for the one we just
      // substituted, the PHI node may be deleted.  Don't iterate through it the
      // last time.
      if (BI->getCondition() != PN) return;
    }
}

// SimplifyPredecessors(switch) - We know that SI is switch based on a PHI node
// defined in this block.  If the phi node contains constant operands, then the
// blocks corresponding to those operands can be modified to jump directly to
// the destination instead of going through this block.
void CondProp::SimplifyPredecessors(SwitchInst *SI) {
  // TODO: We currently only handle the most trival case, where the PHI node has
  // one use (the branch), and is the only instruction besides the branch and
  // dbg intrinsics in the block.
  PHINode *PN = cast<PHINode>(SI->getCondition());
  if (!PN->hasOneUse()) return;

  BasicBlock *BB = SI->getParent();
  if (&*BB->begin() != PN)
    return;
  BasicBlock::iterator BBI = BB->begin();
  BasicBlock::iterator BBE = BB->end();
  while (BBI != BBE && isa<DbgInfoIntrinsic>(++BBI)) ;
  if (&*BBI != SI)
    return;

  bool RemovedPreds = false;

  // Ok, we have this really simple case, walk the PHI operands, looking for
  // constants.  Walk from the end to remove operands from the end when
  // possible, and to avoid invalidating "i".
  for (unsigned i = PN->getNumIncomingValues(); i != 0; --i)
    if (ConstantInt *CI = dyn_cast<ConstantInt>(PN->getIncomingValue(i-1))) {
      // If we have a constant, forward the edge from its current to its
      // ultimate destination.
      unsigned DestCase = SI->findCaseValue(CI);
      RevectorBlockTo(PN->getIncomingBlock(i-1),
                      SI->getSuccessor(DestCase));
      ++NumSwThread;
      RemovedPreds = true;

      // If there were two predecessors before this simplification, or if the
      // PHI node contained all the same value except for the one we just
      // substituted, the PHI node may be deleted.  Don't iterate through it the
      // last time.
      if (SI->getCondition() != PN) return;
    }
}

// RevectorBlockTo - Revector the unconditional branch at the end of FromBB to
// the ToBB block, which is one of the successors of its current successor.
void CondProp::RevectorBlockTo(BasicBlock *FromBB, BasicBlock *ToBB) {
  BranchInst *FromBr = cast<BranchInst>(FromBB->getTerminator());
  assert(FromBr->isUnconditional() && "FromBB should end with uncond br!");

  // Get the old block we are threading through.
  BasicBlock *OldSucc = FromBr->getSuccessor(0);

  // OldSucc had multiple successors. If ToBB has multiple predecessors, then
  // the edge between them would be critical, which we already took care of.
  // If ToBB has single operand PHI node then take care of it here.
  FoldSingleEntryPHINodes(ToBB);

  // Update PHI nodes in OldSucc to know that FromBB no longer branches to it.
  OldSucc->removePredecessor(FromBB);

  // Change FromBr to branch to the new destination.
  FromBr->setSuccessor(0, ToBB);

  MadeChange = true;
}
<commit_msg>Add comment to emphasize that the while body is empty.<commit_after>//===-- CondPropagate.cpp - Propagate Conditional Expressions -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass propagates information about conditional expressions through the
// program, allowing it to eliminate conditional branches in some cases.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "condprop"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Pass.h"
#include "llvm/Type.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Streams.h"
using namespace llvm;

STATISTIC(NumBrThread, "Number of CFG edges threaded through branches");
STATISTIC(NumSwThread, "Number of CFG edges threaded through switches");

namespace {
  struct VISIBILITY_HIDDEN CondProp : public FunctionPass {
    static char ID; // Pass identification, replacement for typeid
    CondProp() : FunctionPass(&ID) {}

    virtual bool runOnFunction(Function &F);

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequiredID(BreakCriticalEdgesID);
      //AU.addRequired<DominanceFrontier>();
    }

  private:
    bool MadeChange;
    SmallVector<BasicBlock *, 4> DeadBlocks;
    void SimplifyBlock(BasicBlock *BB);
    void SimplifyPredecessors(BranchInst *BI);
    void SimplifyPredecessors(SwitchInst *SI);
    void RevectorBlockTo(BasicBlock *FromBB, BasicBlock *ToBB);
  };
}

char CondProp::ID = 0;
static RegisterPass<CondProp> X("condprop", "Conditional Propagation");

FunctionPass *llvm::createCondPropagationPass() {
  return new CondProp();
}

bool CondProp::runOnFunction(Function &F) {
  bool EverMadeChange = false;
  DeadBlocks.clear();

  // While we are simplifying blocks, keep iterating.
  do {
    MadeChange = false;
    for (Function::iterator BB = F.begin(), E = F.end(); BB != E;)
      SimplifyBlock(BB++);
    EverMadeChange = EverMadeChange || MadeChange;
  } while (MadeChange);

  if (EverMadeChange) {
    while (!DeadBlocks.empty()) {
      BasicBlock *BB = DeadBlocks.back(); DeadBlocks.pop_back();
      DeleteDeadBlock(BB);
    }
  }
  return EverMadeChange;
}

void CondProp::SimplifyBlock(BasicBlock *BB) {
  if (BranchInst *BI = dyn_cast<BranchInst>(BB->getTerminator())) {
    // If this is a conditional branch based on a phi node that is defined in
    // this block, see if we can simplify predecessors of this block.
    if (BI->isConditional() && isa<PHINode>(BI->getCondition()) &&
        cast<PHINode>(BI->getCondition())->getParent() == BB)
      SimplifyPredecessors(BI);

  } else if (SwitchInst *SI = dyn_cast<SwitchInst>(BB->getTerminator())) {
    if (isa<PHINode>(SI->getCondition()) &&
        cast<PHINode>(SI->getCondition())->getParent() == BB)
      SimplifyPredecessors(SI);
  }

  // If possible, simplify the terminator of this block.
  if (ConstantFoldTerminator(BB))
    MadeChange = true;

  // If this block ends with an unconditional branch and the only successor has
  // only this block as a predecessor, merge the two blocks together.
  if (BranchInst *BI = dyn_cast<BranchInst>(BB->getTerminator()))
    if (BI->isUnconditional() && BI->getSuccessor(0)->getSinglePredecessor() &&
        BB != BI->getSuccessor(0)) {
      BasicBlock *Succ = BI->getSuccessor(0);

      // If Succ has any PHI nodes, they are all single-entry PHI's.  Eliminate
      // them.
      FoldSingleEntryPHINodes(Succ);

      // Remove BI.
      BI->eraseFromParent();

      // Move over all of the instructions.
      BB->getInstList().splice(BB->end(), Succ->getInstList());

      // Any phi nodes that had entries for Succ now have entries from BB.
      Succ->replaceAllUsesWith(BB);

      // Succ is now dead, but we cannot delete it without potentially
      // invalidating iterators elsewhere.  Just insert an unreachable
      // instruction in it and delete this block later on.
      new UnreachableInst(Succ);
      DeadBlocks.push_back(Succ);
      MadeChange = true;
    }
}

// SimplifyPredecessors(branches) - We know that BI is a conditional branch
// based on a PHI node defined in this block.  If the phi node contains constant
// operands, then the blocks corresponding to those operands can be modified to
// jump directly to the destination instead of going through this block.
void CondProp::SimplifyPredecessors(BranchInst *BI) {
  // TODO: We currently only handle the most trival case, where the PHI node has
  // one use (the branch), and is the only instruction besides the branch and dbg
  // intrinsics in the block.
  PHINode *PN = cast<PHINode>(BI->getCondition());

  if (PN->getNumIncomingValues() == 1) {
    // Eliminate single-entry PHI nodes.
    FoldSingleEntryPHINodes(PN->getParent());
    return;
  }

  if (!PN->hasOneUse()) return;

  BasicBlock *BB = BI->getParent();
  if (&*BB->begin() != PN)
    return;
  BasicBlock::iterator BBI = BB->begin();
  BasicBlock::iterator BBE = BB->end();
  while (BBI != BBE && isa<DbgInfoIntrinsic>(++BBI)) /* empty */;
  if (&*BBI != BI)
    return;

  // Ok, we have this really simple case, walk the PHI operands, looking for
  // constants.  Walk from the end to remove operands from the end when
  // possible, and to avoid invalidating "i".
  for (unsigned i = PN->getNumIncomingValues(); i != 0; --i)
    if (ConstantInt *CB = dyn_cast<ConstantInt>(PN->getIncomingValue(i-1))) {
      // If we have a constant, forward the edge from its current to its
      // ultimate destination.
      RevectorBlockTo(PN->getIncomingBlock(i-1),
                      BI->getSuccessor(CB->isZero()));
      ++NumBrThread;

      // If there were two predecessors before this simplification, or if the
      // PHI node contained all the same value except for the one we just
      // substituted, the PHI node may be deleted.  Don't iterate through it the
      // last time.
      if (BI->getCondition() != PN) return;
    }
}

// SimplifyPredecessors(switch) - We know that SI is switch based on a PHI node
// defined in this block.  If the phi node contains constant operands, then the
// blocks corresponding to those operands can be modified to jump directly to
// the destination instead of going through this block.
void CondProp::SimplifyPredecessors(SwitchInst *SI) {
  // TODO: We currently only handle the most trival case, where the PHI node has
  // one use (the branch), and is the only instruction besides the branch and
  // dbg intrinsics in the block.
  PHINode *PN = cast<PHINode>(SI->getCondition());
  if (!PN->hasOneUse()) return;

  BasicBlock *BB = SI->getParent();
  if (&*BB->begin() != PN)
    return;
  BasicBlock::iterator BBI = BB->begin();
  BasicBlock::iterator BBE = BB->end();
  while (BBI != BBE && isa<DbgInfoIntrinsic>(++BBI)) /* empty */;
  if (&*BBI != SI)
    return;

  bool RemovedPreds = false;

  // Ok, we have this really simple case, walk the PHI operands, looking for
  // constants.  Walk from the end to remove operands from the end when
  // possible, and to avoid invalidating "i".
  for (unsigned i = PN->getNumIncomingValues(); i != 0; --i)
    if (ConstantInt *CI = dyn_cast<ConstantInt>(PN->getIncomingValue(i-1))) {
      // If we have a constant, forward the edge from its current to its
      // ultimate destination.
      unsigned DestCase = SI->findCaseValue(CI);
      RevectorBlockTo(PN->getIncomingBlock(i-1),
                      SI->getSuccessor(DestCase));
      ++NumSwThread;
      RemovedPreds = true;

      // If there were two predecessors before this simplification, or if the
      // PHI node contained all the same value except for the one we just
      // substituted, the PHI node may be deleted.  Don't iterate through it the
      // last time.
      if (SI->getCondition() != PN) return;
    }
}

// RevectorBlockTo - Revector the unconditional branch at the end of FromBB to
// the ToBB block, which is one of the successors of its current successor.
void CondProp::RevectorBlockTo(BasicBlock *FromBB, BasicBlock *ToBB) {
  BranchInst *FromBr = cast<BranchInst>(FromBB->getTerminator());
  assert(FromBr->isUnconditional() && "FromBB should end with uncond br!");

  // Get the old block we are threading through.
  BasicBlock *OldSucc = FromBr->getSuccessor(0);

  // OldSucc had multiple successors. If ToBB has multiple predecessors, then
  // the edge between them would be critical, which we already took care of.
  // If ToBB has single operand PHI node then take care of it here.
  FoldSingleEntryPHINodes(ToBB);

  // Update PHI nodes in OldSucc to know that FromBB no longer branches to it.
  OldSucc->removePredecessor(FromBB);

  // Change FromBr to branch to the new destination.
  FromBr->setSuccessor(0, ToBB);

  MadeChange = true;
}
<|endoftext|>