<commit_before>#include "stdafx.h"
#include "helpers.h"
#include "render_to_window.h"

static PFN_vkCreateDebugReportCallbackEXT pfnCreateDebugReportCallbackEXT = nullptr;
static PFN_vkDestroyDebugReportCallbackEXT pfnDestroyDebugReportCallbackEXT = nullptr;

static VKAPI_ATTR VkBool32 VKAPI_CALL debug_report_callback(
    VkDebugReportFlagsEXT flags,
    VkDebugReportObjectTypeEXT objectType,
    uint64_t object,
    size_t location,
    int32_t messageCode,
    const char* pLayerPrefix,
    const char* pMessage,
    void* pUserData)
{
    std::cerr << pLayerPrefix << ": " << pMessage << std::endl;
    return false;
}

static VkDebugReportCallbackEXT create_debug_report_callback(VkInstance vulkan)
{
    pfnCreateDebugReportCallbackEXT = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(
        vkGetInstanceProcAddr(vulkan, "vkCreateDebugReportCallbackEXT")
        );
    pfnDestroyDebugReportCallbackEXT = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(
        vkGetInstanceProcAddr(vulkan, "vkDestroyDebugReportCallbackEXT")
        );

#if _DEBUG
    VkDebugReportCallbackCreateInfoEXT info = {};
    info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
    info.flags =
        VK_DEBUG_REPORT_ERROR_BIT_EXT |
        VK_DEBUG_REPORT_WARNING_BIT_EXT |
        VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
    info.pfnCallback = &debug_report_callback;

    VkDebugReportCallbackEXT callback;
    auto error = pfnCreateDebugReportCallbackEXT(vulkan, &info, nullptr, &callback);
    assert(!error);
    return callback;
#else
    return nullptr;
#endif
}

vk::Instance create_instance()
{
#if _DEBUG
    const auto layerCount = 1;
    const char* layerNames[layerCount] = { "VK_LAYER_LUNARG_standard_validation" };
#else
    const auto layerCount = 0;
    const char** layerNames = nullptr;
#endif

    const auto extensionCount = 3;
    const char* extensionNames[extensionCount] = {
        VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
        VK_KHR_SURFACE_EXTENSION_NAME,
        VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
    };

    return vk::createInstance(
        vk::InstanceCreateInfo()
        .setEnabledLayerCount(layerCount)
        .setPpEnabledLayerNames(layerNames)
        .setEnabledExtensionCount(extensionCount)
        .setPpEnabledExtensionNames(extensionNames)
    );
}

static vk::PhysicalDevice get_physical_device(vk::Instance vulkan)
{
    auto devices = vulkan.enumeratePhysicalDevices();
    assert(devices.size() == 1);

    auto props = devices[0].getProperties();
    std::cout << "Using physical device " << props.deviceName << std::endl;
    return devices[0];
}

static vk::Device create_device(vk::PhysicalDevice physical_device)
{
    auto props = physical_device.getQueueFamilyProperties();
    assert((props[0].queueFlags & vk::QueueFlagBits::eGraphics) == vk::QueueFlagBits::eGraphics);

    float priorities[] = { 0.f };
    auto queueInfo = vk::DeviceQueueCreateInfo()
        .setQueueCount(1)
        .setPQueuePriorities(priorities);

#if _DEBUG
    const auto layerCount = 1;
    const char* layerNames[layerCount] = { "VK_LAYER_LUNARG_standard_validation" };
#else
    const auto layerCount = 0;
    const char** layerNames = nullptr;
#endif

    const auto extensionCount = 1;
    const char* extensionNames[extensionCount] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };

    auto features = vk::PhysicalDeviceFeatures()
        .setMultiDrawIndirect(true)
        .setDrawIndirectFirstInstance(true)
        .setShaderClipDistance(true)
        .setShaderCullDistance(true);

    return physical_device.createDevice(
        vk::DeviceCreateInfo()
        .setQueueCreateInfoCount(1)
        .setPQueueCreateInfos(&queueInfo)
        .setEnabledLayerCount(layerCount)
        .setPpEnabledLayerNames(layerNames)
        .setEnabledExtensionCount(1)
        .setPpEnabledExtensionNames(extensionNames)
        .setPEnabledFeatures(&features)
    );
}

cxxopts::Options parse_options(int argc, char** argv)
{
    cxxopts::Options options("VulkanRenderer", "Vulkan renderer");
    options.add_options()
        ("model", "PLY model to render. File dialog will be shown if ommitted.", cxxopts::value<std::string>(), "path")
        ("image", "PNG image to save rendering to (overwrites existing). No window will be created if specified.", cxxopts::value<std::string>(), "path")
        ("camera_position", "When using --image, specifies the camera position.", cxxopts::value<std::vector<float>>(), "x y z")
        ("camera_up", "When using --image, specifies the camera up vector.", cxxopts::value<std::vector<float>>(), "x y z")
        ("help", "Show help")
        ;

    try {
        options.parse(argc, argv);
    }
    catch (const cxxopts::OptionException& e) {
        // TODO prints garbage
        std::cerr << e.what() << std::endl;
        exit(EXIT_SUCCESS);
    }
    return options;
}

glm::vec3 std_vector_to_glm_vec3(const std::vector<float>& vector)
{
    return glm::vec3(vector[0], vector[1], vector[2]);
}

int main(int argc, char** argv)
{
    auto options = parse_options(argc, argv);

    if (options["help"].count() > 0) {
        std::cout << options.help();
        return EXIT_SUCCESS;
    }

    std::string model_path;
    auto model_path_option = options["model"];

    if (model_path_option.count() == 1)
    {
        model_path = model_path_option.as<std::string>();
    }
    else
    {
        auto pattern = "*.ply";
        auto model_path_ptr = tinyfd_openFileDialog("Open 3D model", nullptr, 1, &pattern, nullptr, 0);
        if (!model_path_ptr)
        {
            return EXIT_FAILURE;
        }
        model_path = model_path_ptr;
    }

    auto instance = create_instance();
    auto callback = create_debug_report_callback(instance);
    auto physical_device = get_physical_device(instance);
    auto device = create_device(physical_device);

    auto image_path_option = options["image"];
    if (image_path_option.count() == 1)
    {
        auto camera_position_option = options["camera_position"];
        auto camera_position = camera_position_option.count() == 3
            ? std_vector_to_glm_vec3(camera_position_option.as<std::vector<float>>())
            : glm::vec3(0.f, 0.f, 2.f);

        auto camera_up_vector = options["camera_up"];
        auto camera_up = camera_up_vector.count() == 3
            ? std_vector_to_glm_vec3(camera_up_vector.as<std::vector<float>>())
            : glm::vec3(0.f, -1.f, 0.f);

        std::cout << "Rendering to image..." << std::endl;
        render_to_image(physical_device, device, model_path, image_path_option.as<std::string>(), camera_position, camera_up);
    }
    else
    {
        std::cout << "Rendering to window..." << std::endl;
        render_to_window(instance, physical_device, device, model_path);
    }

    device.destroy();
#if _DEBUG
    pfnDestroyDebugReportCallbackEXT(instance, callback, nullptr);
#endif
    instance.destroy();

    return EXIT_SUCCESS;
}
<commit_msg>Allow more than 1 physical device.<commit_after>#include "stdafx.h"
#include "helpers.h"
#include "render_to_window.h"

static PFN_vkCreateDebugReportCallbackEXT pfnCreateDebugReportCallbackEXT = nullptr;
static PFN_vkDestroyDebugReportCallbackEXT pfnDestroyDebugReportCallbackEXT = nullptr;

static VKAPI_ATTR VkBool32 VKAPI_CALL debug_report_callback(
    VkDebugReportFlagsEXT flags,
    VkDebugReportObjectTypeEXT objectType,
    uint64_t object,
    size_t location,
    int32_t messageCode,
    const char* pLayerPrefix,
    const char* pMessage,
    void* pUserData)
{
    std::cerr << pLayerPrefix << ": " << pMessage << std::endl;
    return false;
}

static VkDebugReportCallbackEXT create_debug_report_callback(VkInstance vulkan)
{
    pfnCreateDebugReportCallbackEXT = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(
        vkGetInstanceProcAddr(vulkan, "vkCreateDebugReportCallbackEXT")
        );
    pfnDestroyDebugReportCallbackEXT = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(
        vkGetInstanceProcAddr(vulkan, "vkDestroyDebugReportCallbackEXT")
        );

#if _DEBUG
    VkDebugReportCallbackCreateInfoEXT info = {};
    info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
    info.flags =
        VK_DEBUG_REPORT_ERROR_BIT_EXT |
        VK_DEBUG_REPORT_WARNING_BIT_EXT |
        VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
    info.pfnCallback = &debug_report_callback;

    VkDebugReportCallbackEXT callback;
    auto error = pfnCreateDebugReportCallbackEXT(vulkan, &info, nullptr, &callback);
    assert(!error);
    return callback;
#else
    return nullptr;
#endif
}

vk::Instance create_instance()
{
#if _DEBUG
    const auto layerCount = 1;
    const char* layerNames[layerCount] = { "VK_LAYER_LUNARG_standard_validation" };
#else
    const auto layerCount = 0;
    const char** layerNames = nullptr;
#endif

    const auto extensionCount = 3;
    const char* extensionNames[extensionCount] = {
        VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
        VK_KHR_SURFACE_EXTENSION_NAME,
        VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
    };

    return vk::createInstance(
        vk::InstanceCreateInfo()
        .setEnabledLayerCount(layerCount)
        .setPpEnabledLayerNames(layerNames)
        .setEnabledExtensionCount(extensionCount)
        .setPpEnabledExtensionNames(extensionNames)
    );
}

static vk::PhysicalDevice get_physical_device(vk::Instance vulkan)
{
    auto devices = vulkan.enumeratePhysicalDevices();
    assert(devices.size() > 0);

    auto props = devices[0].getProperties();
    std::cout << "Using physical device " << props.deviceName << std::endl;
    return devices[0];
}

static vk::Device create_device(vk::PhysicalDevice physical_device)
{
    auto props = physical_device.getQueueFamilyProperties();
    assert((props[0].queueFlags & vk::QueueFlagBits::eGraphics) == vk::QueueFlagBits::eGraphics);

    float priorities[] = { 0.f };
    auto queueInfo = vk::DeviceQueueCreateInfo()
        .setQueueCount(1)
        .setPQueuePriorities(priorities);

#if _DEBUG
    const auto layerCount = 1;
    const char* layerNames[layerCount] = { "VK_LAYER_LUNARG_standard_validation" };
#else
    const auto layerCount = 0;
    const char** layerNames = nullptr;
#endif

    const auto extensionCount = 1;
    const char* extensionNames[extensionCount] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };

    auto features = vk::PhysicalDeviceFeatures()
        .setMultiDrawIndirect(true)
        .setDrawIndirectFirstInstance(true)
        .setShaderClipDistance(true)
        .setShaderCullDistance(true);

    return physical_device.createDevice(
        vk::DeviceCreateInfo()
        .setQueueCreateInfoCount(1)
        .setPQueueCreateInfos(&queueInfo)
        .setEnabledLayerCount(layerCount)
        .setPpEnabledLayerNames(layerNames)
        .setEnabledExtensionCount(1)
        .setPpEnabledExtensionNames(extensionNames)
        .setPEnabledFeatures(&features)
    );
}

cxxopts::Options parse_options(int argc, char** argv)
{
    cxxopts::Options options("VulkanRenderer", "Vulkan renderer");
    options.add_options()
        ("model", "PLY model to render. File dialog will be shown if ommitted.", cxxopts::value<std::string>(), "path")
        ("image", "PNG image to save rendering to (overwrites existing). No window will be created if specified.", cxxopts::value<std::string>(), "path")
        ("camera_position", "When using --image, specifies the camera position.", cxxopts::value<std::vector<float>>(), "x y z")
        ("camera_up", "When using --image, specifies the camera up vector.", cxxopts::value<std::vector<float>>(), "x y z")
        ("help", "Show help")
        ;

    try {
        options.parse(argc, argv);
    }
    catch (const cxxopts::OptionException& e) {
        // TODO prints garbage
        std::cerr << e.what() << std::endl;
        exit(EXIT_SUCCESS);
    }
    return options;
}

glm::vec3 std_vector_to_glm_vec3(const std::vector<float>& vector)
{
    return glm::vec3(vector[0], vector[1], vector[2]);
}

int main(int argc, char** argv)
{
    auto options = parse_options(argc, argv);

    if (options["help"].count() > 0) {
        std::cout << options.help();
        return EXIT_SUCCESS;
    }

    std::string model_path;
    auto model_path_option = options["model"];

    if (model_path_option.count() == 1)
    {
        model_path = model_path_option.as<std::string>();
    }
    else
    {
        auto pattern = "*.ply";
        auto model_path_ptr = tinyfd_openFileDialog("Open 3D model", nullptr, 1, &pattern, nullptr, 0);
        if (!model_path_ptr)
        {
            return EXIT_FAILURE;
        }
        model_path = model_path_ptr;
    }

    auto instance = create_instance();
    auto callback = create_debug_report_callback(instance);
    auto physical_device = get_physical_device(instance);
    auto device = create_device(physical_device);

    auto image_path_option = options["image"];
    if (image_path_option.count() == 1)
    {
        auto camera_position_option = options["camera_position"];
        auto camera_position = camera_position_option.count() == 3
            ? std_vector_to_glm_vec3(camera_position_option.as<std::vector<float>>())
            : glm::vec3(0.f, 0.f, 2.f);

        auto camera_up_vector = options["camera_up"];
        auto camera_up = camera_up_vector.count() == 3
            ? std_vector_to_glm_vec3(camera_up_vector.as<std::vector<float>>())
            : glm::vec3(0.f, -1.f, 0.f);

        std::cout << "Rendering to image..." << std::endl;
        render_to_image(physical_device, device, model_path, image_path_option.as<std::string>(), camera_position, camera_up);
    }
    else
    {
        std::cout << "Rendering to window..." << std::endl;
        render_to_window(instance, physical_device, device, model_path);
    }

    device.destroy();
#if _DEBUG
    pfnDestroyDebugReportCallbackEXT(instance, callback, nullptr);
#endif
    instance.destroy();

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "jingle/notifier/communicator/gaia_token_pre_xmpp_auth.h"

#include <algorithm>

#include "talk/base/socketaddress.h"
#include "talk/xmpp/constants.h"
#include "talk/xmpp/saslcookiemechanism.h"

namespace notifier {

namespace {
const char kGaiaAuthMechanism[] = "X-GOOGLE-TOKEN";
}  // namespace

GaiaTokenPreXmppAuth::GaiaTokenPreXmppAuth(
    const std::string& username,
    const std::string& token,
    const std::string& token_service)
    : username_(username),
      token_(token),
      token_service_(token_service) { }

GaiaTokenPreXmppAuth::~GaiaTokenPreXmppAuth() { }

void GaiaTokenPreXmppAuth::StartPreXmppAuth(
    const buzz::Jid& jid,
    const talk_base::SocketAddress& server,
    const talk_base::CryptString& pass,
    const std::string& auth_cookie) {
  SignalAuthDone();
}

bool GaiaTokenPreXmppAuth::IsAuthDone() const {
  return true;
}

bool GaiaTokenPreXmppAuth::IsAuthorized() const {
  return true;
}

bool GaiaTokenPreXmppAuth::HadError() const {
  return false;
}

int GaiaTokenPreXmppAuth::GetError() const {
  return 0;
}

buzz::CaptchaChallenge GaiaTokenPreXmppAuth::GetCaptchaChallenge() const {
  return buzz::CaptchaChallenge();
}

std::string GaiaTokenPreXmppAuth::GetAuthCookie() const {
  return std::string();
}

std::string GaiaTokenPreXmppAuth::ChooseBestSaslMechanism(
    const std::vector<std::string> & mechanisms, bool encrypted) {
  return (std::find(mechanisms.begin(),
                    mechanisms.end(), kGaiaAuthMechanism) !=
          mechanisms.end()) ? kGaiaAuthMechanism : "";
}

buzz::SaslMechanism* GaiaTokenPreXmppAuth::CreateSaslMechanism(
    const std::string& mechanism) {
  if (mechanism != kGaiaAuthMechanism)
    return NULL;
  return new buzz::SaslCookieMechanism(
      kGaiaAuthMechanism, username_, token_, token_service_);
}

}  // namespace notifier
<commit_msg>Fixed bug where sync notifications don't work for non-gmail accounts.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "jingle/notifier/communicator/gaia_token_pre_xmpp_auth.h"

#include <algorithm>

#include "base/basictypes.h"
#include "talk/base/socketaddress.h"
#include "talk/xmpp/constants.h"
#include "talk/xmpp/saslcookiemechanism.h"

namespace notifier {

namespace {

const char kGaiaAuthMechanism[] = "X-GOOGLE-TOKEN";

class GaiaCookieMechanism : public buzz::SaslCookieMechanism {
 public:
  GaiaCookieMechanism(const std::string & mechanism,
                      const std::string & username,
                      const std::string & cookie,
                      const std::string & token_service)
      : buzz::SaslCookieMechanism(
          mechanism, username, cookie, token_service) {}

  virtual ~GaiaCookieMechanism() {}

  virtual buzz::XmlElement* StartSaslAuth() {
    buzz::XmlElement* auth = buzz::SaslCookieMechanism::StartSaslAuth();
    // These attributes are necessary for working with non-gmail gaia
    // accounts.
    const std::string NS_GOOGLE_AUTH_PROTOCOL(
        "http://www.google.com/talk/protocol/auth");
    const buzz::QName QN_GOOGLE_ALLOW_GENERATED_JID_XMPP_LOGIN(
        true, NS_GOOGLE_AUTH_PROTOCOL, "allow-generated-jid");
    const buzz::QName QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT(
        true, NS_GOOGLE_AUTH_PROTOCOL, "client-uses-full-bind-result");
    auth->SetAttr(QN_GOOGLE_ALLOW_GENERATED_JID_XMPP_LOGIN, "true");
    auth->SetAttr(QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT, "true");
    return auth;
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(GaiaCookieMechanism);
};

}  // namespace

GaiaTokenPreXmppAuth::GaiaTokenPreXmppAuth(
    const std::string& username,
    const std::string& token,
    const std::string& token_service)
    : username_(username),
      token_(token),
      token_service_(token_service) { }

GaiaTokenPreXmppAuth::~GaiaTokenPreXmppAuth() { }

void GaiaTokenPreXmppAuth::StartPreXmppAuth(
    const buzz::Jid& jid,
    const talk_base::SocketAddress& server,
    const talk_base::CryptString& pass,
    const std::string& auth_cookie) {
  SignalAuthDone();
}

bool GaiaTokenPreXmppAuth::IsAuthDone() const {
  return true;
}

bool GaiaTokenPreXmppAuth::IsAuthorized() const {
  return true;
}

bool GaiaTokenPreXmppAuth::HadError() const {
  return false;
}

int GaiaTokenPreXmppAuth::GetError() const {
  return 0;
}

buzz::CaptchaChallenge GaiaTokenPreXmppAuth::GetCaptchaChallenge() const {
  return buzz::CaptchaChallenge();
}

std::string GaiaTokenPreXmppAuth::GetAuthCookie() const {
  return std::string();
}

std::string GaiaTokenPreXmppAuth::ChooseBestSaslMechanism(
    const std::vector<std::string> & mechanisms, bool encrypted) {
  return (std::find(mechanisms.begin(),
                    mechanisms.end(), kGaiaAuthMechanism) !=
          mechanisms.end()) ? kGaiaAuthMechanism : "";
}

buzz::SaslMechanism* GaiaTokenPreXmppAuth::CreateSaslMechanism(
    const std::string& mechanism) {
  if (mechanism != kGaiaAuthMechanism)
    return NULL;
  return new GaiaCookieMechanism(
      kGaiaAuthMechanism, username_, token_, token_service_);
}

}  // namespace notifier
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Sacha Refshauge
 *
 */
// Blackberry implementation of the framework.

#include <pwd.h>
#include <unistd.h>
#include <string>

#include <bps/region.h> // Get region and language
#include "BlackberryMain.h"
#include "base/NKCodeFromBlackberry.h"

// Simple implementations of System functions

std::string System_GetProperty(SystemProperty prop) {
	switch (prop) {
	case SYSPROP_NAME: {
		std::string name = "Blackberry10:";
		return name + ((pixel_xres != pixel_yres) ? "Touch" : "QWERTY");
	}
	case SYSPROP_LANGREGION: {
		char *lang = 0;
		char *region = 0;
		region_get(&lang, &region);
		return std::string(lang) + "_" + std::string(region);
	}
	default:
		return "";
	}
}

void SystemToast(const char *text) {
	dialog_instance_t dialog = 0;
	dialog_create_toast(&dialog);
	dialog_set_toast_message_text(dialog, text);
	dialog_set_toast_position(dialog, DIALOG_POSITION_TOP_CENTER);
	dialog_show(dialog);
}

void ShowAd(int x, int y, bool center_x) {
}

void ShowKeyboard() {
	virtualkeyboard_show();
}

void Vibrate(int length_ms) {
	// Vibration: intensity strength(1-100), duration ms(0-5000)
	// Intensity: LOW = 1, MEDIUM = 10, HIGH = 100
	switch (length_ms) {
	case -1: // Keyboard Tap
		vibration_request(VIBRATION_INTENSITY_LOW, 50);
		break;
	case -2: // Virtual Key
		vibration_request(VIBRATION_INTENSITY_LOW, 25);
		break;
	case -3: // Long Press
		vibration_request(VIBRATION_INTENSITY_LOW, 50);
		break;
	default:
		vibration_request(VIBRATION_INTENSITY_LOW, length_ms);
		break;
	}
}

void LaunchBrowser(const char *url)
{
	char* error;
	navigator_invoke(url, &error);
}

void LaunchMarket(const char *url)
{
	char* error;
	navigator_invoke(url, &error);
}

void LaunchEmail(const char *email_address)
{
	char* error;
	navigator_invoke((std::string("mailto:") + email_address).c_str(), &error);
}

InputState input_state;

void BlackberryMain::handleInput(screen_event_t screen_event)
{
	TouchInput input;
	KeyInput key;
	int val, buttons, pointerId;
	int pair[2];
	screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &val);
	screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_SOURCE_POSITION, pair);
	screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TOUCH_ID, &pointerId);

	input_state.mouse_valid = true;
	switch(val)
	{
	// Touchscreen
	case SCREEN_EVENT_MTOUCH_TOUCH:
	case SCREEN_EVENT_MTOUCH_RELEASE: 	// Up, down
		input_state.pointer_down[pointerId] = (val == SCREEN_EVENT_MTOUCH_TOUCH);
		input_state.pointer_x[pointerId] = pair[0] * g_dpi_scale;
		input_state.pointer_y[pointerId] = pair[1] * g_dpi_scale;

		input.x = pair[0] * g_dpi_scale;
		input.y = pair[1] * g_dpi_scale;
		input.flags = (val == SCREEN_EVENT_MTOUCH_TOUCH) ? TOUCH_DOWN : TOUCH_UP;
		input.id = pointerId;
		NativeTouch(input);
		break;
	case SCREEN_EVENT_MTOUCH_MOVE:
		input_state.pointer_x[pointerId] = pair[0] * g_dpi_scale;
		input_state.pointer_y[pointerId] = pair[1] * g_dpi_scale;

		input.x = pair[0] * g_dpi_scale;
		input.y = pair[1] * g_dpi_scale;
		input.flags = TOUCH_MOVE;
		input.id = pointerId;
		NativeTouch(input);
		break;
	// Mouse, Simulator
    case SCREEN_EVENT_POINTER:
		screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_BUTTONS,
			&buttons);
		if (buttons == SCREEN_LEFT_MOUSE_BUTTON) { 			// Down
			input_state.pointer_x[pointerId] = pair[0] * g_dpi_scale;
			input_state.pointer_y[pointerId] = pair[1] * g_dpi_scale;
			input_state.pointer_down[pointerId] = true;

			input.x = pair[0] * g_dpi_scale;
			input.y = pair[1] * g_dpi_scale;
			input.flags = TOUCH_DOWN;
			input.id = pointerId;
			NativeTouch(input);
		} else if (input_state.pointer_down[pointerId]) {	// Up
			input_state.pointer_x[pointerId] = pair[0] * g_dpi_scale;
			input_state.pointer_y[pointerId] = pair[1] * g_dpi_scale;
			input_state.pointer_down[pointerId] = false;

			input.x = pair[0] * g_dpi_scale;
			input.y = pair[1] * g_dpi_scale;
			input.flags = TOUCH_UP;
			input.id = pointerId;
			NativeTouch(input);
		}
		break;
	// Keyboard
	case SCREEN_EVENT_KEYBOARD:
		int flags, value;
		screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_FLAGS, &flags);
		screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_SYM, &value);
		NativeKey(KeyInput(DEVICE_ID_KEYBOARD, KeyMapRawBlackberrytoNative.find(value)->second, (flags & KEY_DOWN) ? KEY_DOWN : KEY_UP));
		break;
	// Gamepad
	case SCREEN_EVENT_GAMEPAD:
	case SCREEN_EVENT_JOYSTICK:
		char device_id[16];
		screen_device_t device;
		screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_DEVICE, (void**)&device);
		screen_get_device_property_cv(device, SCREEN_PROPERTY_ID_STRING, sizeof(device_id), device_id);
		screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_BUTTONS, &buttons);
		for (int i = 0; i < 32; i++) {
			int mask = 1 << i;
			if ((old_buttons & mask) != (buttons & mask))
				NativeKey(KeyInput(DEVICE_ID_PAD_0, KeyMapPadBlackberrytoNative.find(mask)->second, (buttons & mask) ? KEY_DOWN : KEY_UP));
		}
		old_buttons = buttons;
		break;
	case SCREEN_EVENT_DISPLAY:
		screen_display_t new_dpy = NULL;
		screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_DISPLAY, (void **)&new_dpy);
		for (int i = 0; i < ndisplays; i++) {
			if (new_dpy != screen_dpy[i])
				continue;
			int active = 0;
			screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_ATTACHED, &active);
			if (active) {
				int size[2];
				screen_get_display_property_iv(screen_dpy[i], SCREEN_PROPERTY_SIZE, size);
				if (size[0] == 0 || size[1] == 0)
					active = 0;
			}
			if (active && !displays[i].attached)
				realiseDisplay(i);
			else if (!active && displays[i].attached && displays[i].realised)
				unrealiseDisplay(i);
			displays[i].attached = active;
		}
		break;
	}
}

void BlackberryMain::startMain(int argc, char *argv[]) {
	// Receive events from window manager
	screen_create_context(&screen_cxt, 0);
	// Initialise Blackberry Platform Services
	bps_initialize();
	// TODO: Enable/disable based on setting
	sensor_set_rate(SENSOR_TYPE_ACCELEROMETER, 25000);
	sensor_request_events(SENSOR_TYPE_ACCELEROMETER);

	net::Init();
	startDisplays();
	NativeInit(argc, (const char **)argv, "/accounts/1000/shared/misc/", "app/native/assets/", "BADCOFFEE");
	NativeInitGraphics();
	screen_request_events(screen_cxt);
	navigator_request_events(0);
	dialog_request_events(0);
	vibration_request_events(0);
	audio = new BlackberryAudio();
	runMain();
}

void BlackberryMain::runMain() {
	bool running = true;
	while (running) {
		input_state.mouse_valid = false;
		input_state.accelerometer_valid = false;
		while (true) {
			// Handle Blackberry events
			bps_event_t *event = NULL;
			bps_get_event(&event, 0);
			if (event == NULL)
				break; // Ran out of events
			int domain = bps_event_get_domain(event);
			if (domain == screen_get_domain()) {
				handleInput(screen_event_get_event(event));
			} else if (domain == navigator_get_domain()) {
				switch(bps_event_get_code(event))
				{
				case NAVIGATOR_BACK:
				case NAVIGATOR_SWIPE_DOWN:
					NativeKey(KeyInput(DEVICE_ID_KEYBOARD, NKCODE_ESCAPE, KEY_DOWN));
					break;
				case NAVIGATOR_EXIT:
					return;
				}
			} else if (domain == sensor_get_domain()) {
				if (SENSOR_ACCELEROMETER_READING == bps_event_get_code(event)) {
					float x, y, z;
					sensor_event_get_xyz(event, &x, &y, &z);
					if (pixel_xres == 1024 || pixel_xres == 720) // Q10 has this negative and reversed
					{
						input_state.acc.x = -y;
						input_state.acc.y = -x;
					} else {
						input_state.acc.x = x;
						input_state.acc.y = y;
					}
					input_state.acc.z = z;
				}
			}
		}
		UpdateInputState(&input_state);
		NativeUpdate(input_state);
		// Work in Progress
		// Currently: Render to HDMI port (eg. 1080p) when in game. Render to device when in menu.
		// Idea: Render to all displays. Controls go to internal, game goes to external(s).
		if (globalUIState == UISTATE_INGAME && !emulating)
		{
			emulating = true;
			switchDisplay(screen_emu);
		} else if (globalUIState != UISTATE_INGAME && emulating) {
			emulating = false;
			switchDisplay(screen_ui);
		}
		NativeRender();
		EndInputState(&input_state);
		time_update();
		// This handles VSync
		if (emulating)
			eglSwapBuffers(egl_disp[screen_emu], egl_surf[screen_emu]);
		else
			eglSwapBuffers(egl_disp[screen_ui], egl_surf[screen_ui]);
	}
}

void BlackberryMain::endMain() {
	screen_stop_events(screen_cxt);
	bps_shutdown();
	NativeShutdownGraphics();
	delete audio;
	NativeShutdown();
	killDisplays();
	net::Shutdown();
	screen_destroy_context(screen_cxt);
}

// Entry Point
int main(int argc, char *argv[]) {
	delete new BlackberryMain(argc, argv);
	return 0;
}
<commit_msg>Support left analog stick for game controllers on Blackberry.<commit_after>/*
 * Copyright (c) 2013 Sacha Refshauge
 *
 */
// Blackberry implementation of the framework.

#include <pwd.h>
#include <unistd.h>
#include <string>

#include <bps/region.h> // Get region and language
#include "BlackberryMain.h"
#include "base/NKCodeFromBlackberry.h"

// Simple implementations of System functions

std::string System_GetProperty(SystemProperty prop) {
	switch (prop) {
	case SYSPROP_NAME: {
		std::string name = "Blackberry10:";
		return name + ((pixel_xres != pixel_yres) ? "Touch" : "QWERTY");
	}
	case SYSPROP_LANGREGION: {
		char *lang = 0;
		char *region = 0;
		region_get(&lang, &region);
		return std::string(lang) + "_" + std::string(region);
	}
	default:
		return "";
	}
}

void SystemToast(const char *text) {
	dialog_instance_t dialog = 0;
	dialog_create_toast(&dialog);
	dialog_set_toast_message_text(dialog, text);
	dialog_set_toast_position(dialog, DIALOG_POSITION_TOP_CENTER);
	dialog_show(dialog);
}

void ShowAd(int x, int y, bool center_x) {
}

void ShowKeyboard() {
	virtualkeyboard_show();
}

void Vibrate(int length_ms) {
	// Vibration: intensity strength(1-100), duration ms(0-5000)
	// Intensity: LOW = 1, MEDIUM = 10, HIGH = 100
	switch (length_ms) {
	case -1: // Keyboard Tap
		vibration_request(VIBRATION_INTENSITY_LOW, 50);
		break;
	case -2: // Virtual Key
		vibration_request(VIBRATION_INTENSITY_LOW, 25);
		break;
	case -3: // Long Press
		vibration_request(VIBRATION_INTENSITY_LOW, 50);
		break;
	default:
		vibration_request(VIBRATION_INTENSITY_LOW, length_ms);
		break;
	}
}

void LaunchBrowser(const char *url)
{
	char* error;
	navigator_invoke(url, &error);
}

void LaunchMarket(const char *url)
{
	char* error;
	navigator_invoke(url, &error);
}

void LaunchEmail(const char *email_address)
{
	char* error;
	navigator_invoke((std::string("mailto:") + email_address).c_str(), &error);
}

InputState input_state;

void BlackberryMain::handleInput(screen_event_t screen_event)
{
	TouchInput input;
	KeyInput key;
	int val, buttons, pointerId;
	int pair[2];
	screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &val);
	screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_SOURCE_POSITION, pair);
	screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TOUCH_ID, &pointerId);

	input_state.mouse_valid = true;
	switch(val)
	{
	// Touchscreen
	case SCREEN_EVENT_MTOUCH_TOUCH:
	case SCREEN_EVENT_MTOUCH_RELEASE: 	// Up, down
		input_state.pointer_down[pointerId] = (val == SCREEN_EVENT_MTOUCH_TOUCH);
		input_state.pointer_x[pointerId] = pair[0] * g_dpi_scale;
		input_state.pointer_y[pointerId] = pair[1] * g_dpi_scale;

		input.x = pair[0] * g_dpi_scale;
		input.y = pair[1] * g_dpi_scale;
		input.flags = (val == SCREEN_EVENT_MTOUCH_TOUCH) ? TOUCH_DOWN : TOUCH_UP;
		input.id = pointerId;
		NativeTouch(input);
		break;
	case SCREEN_EVENT_MTOUCH_MOVE:
		input_state.pointer_x[pointerId] = pair[0] * g_dpi_scale;
		input_state.pointer_y[pointerId] = pair[1] * g_dpi_scale;

		input.x = pair[0] * g_dpi_scale;
		input.y = pair[1] * g_dpi_scale;
		input.flags = TOUCH_MOVE;
		input.id = pointerId;
		NativeTouch(input);
		break;
	// Mouse, Simulator
    case SCREEN_EVENT_POINTER:
		screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_BUTTONS,
			&buttons);
		if (buttons == SCREEN_LEFT_MOUSE_BUTTON) { 			// Down
			input_state.pointer_x[pointerId] = pair[0] * g_dpi_scale;
			input_state.pointer_y[pointerId] = pair[1] * g_dpi_scale;
			input_state.pointer_down[pointerId] = true;

			input.x = pair[0] * g_dpi_scale;
			input.y = pair[1] * g_dpi_scale;
			input.flags = TOUCH_DOWN;
			input.id = pointerId;
			NativeTouch(input);
		} else if (input_state.pointer_down[pointerId]) {	// Up
			input_state.pointer_x[pointerId] = pair[0] * g_dpi_scale;
			input_state.pointer_y[pointerId] = pair[1] * g_dpi_scale;
			input_state.pointer_down[pointerId] = false;

			input.x = pair[0] * g_dpi_scale;
			input.y = pair[1] * g_dpi_scale;
			input.flags = TOUCH_UP;
			input.id = pointerId;
			NativeTouch(input);
		}
		break;
	// Keyboard
	case SCREEN_EVENT_KEYBOARD:
		int flags, value;
		screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_FLAGS, &flags);
		screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_SYM, &value);
		NativeKey(KeyInput(DEVICE_ID_KEYBOARD, KeyMapRawBlackberrytoNative.find(value)->second, (flags & KEY_DOWN) ? KEY_DOWN : KEY_UP));
		break;
	// Gamepad
	case SCREEN_EVENT_GAMEPAD:
	case SCREEN_EVENT_JOYSTICK:
		char device_id[16];
		int analog0[3];
		screen_device_t device;
		screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_DEVICE, (void**)&device);
		screen_get_device_property_cv(device, SCREEN_PROPERTY_ID_STRING, sizeof(device_id), device_id);
		screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_BUTTONS, &buttons);
		for (int i = 0; i < 32; i++) {
			int mask = 1 << i;
			if ((old_buttons & mask) != (buttons & mask))
				NativeKey(KeyInput(DEVICE_ID_PAD_0, KeyMapPadBlackberrytoNative.find(mask)->second, (buttons & mask) ? KEY_DOWN : KEY_UP));
		}
		if (!screen_get_device_property_iv(device, SCREEN_PROPERTY_ANALOG0, analog0)) {
			for (int i = 0; i < 3; i++) {
				AxisInput axis;
				axis.axisId = (i == 0) ? JOYSTICK_AXIS_X : (
				              (i == 1) ? JOYSTICK_AXIS_Y : JOYSTICK_AXIS_Z);
				// 1.2 to try to approximate the PSP's clamped rectangular range.
				axis.value = 1.2 * analog0[i] / 128.0f;
				if (axis.value > 1.0f) axis.value = 1.0f;
				if (axis.value < -1.0f) axis.value = -1.0f;
				axis.deviceId = DEVICE_ID_PAD_0;
				axis.flags = 0;
				NativeAxis(axis);
			}
		}
		old_buttons = buttons;
		break;
	case SCREEN_EVENT_DISPLAY:
		screen_display_t new_dpy = NULL;
		screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_DISPLAY, (void **)&new_dpy);
		for (int i = 0; i < ndisplays; i++) {
			if (new_dpy != screen_dpy[i])
				continue;
			int active = 0;
			screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_ATTACHED, &active);
			if (active) {
				int size[2];
				screen_get_display_property_iv(screen_dpy[i], SCREEN_PROPERTY_SIZE, size);
				if (size[0] == 0 || size[1] == 0)
					active = 0;
			}
			if (active && !displays[i].attached)
				realiseDisplay(i);
			else if (!active && displays[i].attached && displays[i].realised)
				unrealiseDisplay(i);
			displays[i].attached = active;
		}
		break;
	}
}

void BlackberryMain::startMain(int argc, char *argv[]) {
	// Receive events from window manager
	screen_create_context(&screen_cxt, 0);
	// Initialise Blackberry Platform Services
	bps_initialize();
	// TODO: Enable/disable based on setting
	sensor_set_rate(SENSOR_TYPE_ACCELEROMETER, 25000);
	sensor_request_events(SENSOR_TYPE_ACCELEROMETER);

	net::Init();
	startDisplays();
	NativeInit(argc, (const char **)argv, "/accounts/1000/shared/misc/", "app/native/assets/", "BADCOFFEE");
	NativeInitGraphics();
	screen_request_events(screen_cxt);
	navigator_request_events(0);
	dialog_request_events(0);
	vibration_request_events(0);
	audio = new BlackberryAudio();
	runMain();
}

void BlackberryMain::runMain() {
	bool running = true;
	while (running) {
		input_state.mouse_valid = false;
		input_state.accelerometer_valid = false;
		while (true) {
			// Handle Blackberry events
			bps_event_t *event = NULL;
			bps_get_event(&event, 0);
			if (event == NULL)
				break; // Ran out of events
			int domain = bps_event_get_domain(event);
			if (domain == screen_get_domain()) {
				handleInput(screen_event_get_event(event));
			} else if (domain == navigator_get_domain()) {
				switch(bps_event_get_code(event))
				{
				case NAVIGATOR_BACK:
				case NAVIGATOR_SWIPE_DOWN:
					NativeKey(KeyInput(DEVICE_ID_KEYBOARD, NKCODE_ESCAPE, KEY_DOWN));
					break;
				case NAVIGATOR_EXIT:
					return;
				}
			} else if (domain == sensor_get_domain()) {
				if (SENSOR_ACCELEROMETER_READING == bps_event_get_code(event)) {
					float x, y, z;
					sensor_event_get_xyz(event, &x, &y, &z);
					if (pixel_xres == 1024 || pixel_xres == 720) // Q10 has this negative and reversed
					{
						input_state.acc.x = -y;
						input_state.acc.y = -x;
					} else {
						input_state.acc.x = x;
						input_state.acc.y = y;
					}
					input_state.acc.z = z;
				}
			}
		}
		UpdateInputState(&input_state);
		NativeUpdate(input_state);
		// Work in Progress
		// Currently: Render to HDMI port (eg. 1080p) when in game. Render to device when in menu.
		// Idea: Render to all displays. Controls go to internal, game goes to external(s).
		if (globalUIState == UISTATE_INGAME && !emulating)
		{
			emulating = true;
			switchDisplay(screen_emu);
		} else if (globalUIState != UISTATE_INGAME && emulating) {
			emulating = false;
			switchDisplay(screen_ui);
		}
		NativeRender();
		EndInputState(&input_state);
		time_update();
		// This handles VSync
		if (emulating)
			eglSwapBuffers(egl_disp[screen_emu], egl_surf[screen_emu]);
		else
			eglSwapBuffers(egl_disp[screen_ui], egl_surf[screen_ui]);
	}
}

void BlackberryMain::endMain() {
	screen_stop_events(screen_cxt);
	bps_shutdown();
	NativeShutdownGraphics();
	delete audio;
	NativeShutdown();
	killDisplays();
	net::Shutdown();
	screen_destroy_context(screen_cxt);
}

// Entry Point
int main(int argc, char *argv[]) {
	delete new BlackberryMain(argc, argv);
	return 0;
}
<|endoftext|>


<commit_before>//===-- CommandLineStatusOutput.cpp ---------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "CommandLineStatusOutput.h"

#include <cassert>
#include <cstdio>

#include <llvm/Support/Process.h>

namespace {

struct CommandLineStatusOutputImpl {
  /// The output stream.
  FILE* fp{nullptr};

  /// Whether the output stream honors '\r'.
  bool termHonorsCarriageReturn{false};

  /// Whether the stream has current output.
  bool hasOutput{false};

  /// Whether the stream has been closed.
  bool isClosed{false};

  /// The number of characters written to the current line.
  int numCurrentCharacters{0};

  CommandLineStatusOutputImpl() {}

  ~CommandLineStatusOutputImpl() {
    if (isOpen()) {
      std::string error;
      close(&error);
    }
  }

  bool isOpen() const {
    return fp != nullptr;
  }

  bool open(std::string* error_out) {
    assert(!isOpen() && !isClosed);
    fp = stdout;

    // Detect the features of the output.
    int fd = fileno(fp);
    if (::isatty(fd)) {
      // If the terminal is a tty, check the TERM variable.
      const char* term = ::getenv("TERM");

      // We assume the terminal honors '\r' if it is either not-"dumb", or it is
      // "dumb" and we are inside Emacs (comint-mode reports as "dumb").
      if (term) {
        termHonorsCarriageReturn = (term != std::string("dumb") ||
                                    ::getenv("INSIDE_EMACS") != nullptr);
      }
    }

    return true;
  }

  bool close(std::string* error_out) {
    if (hasOutput) {
      fprintf(fp, "\n");
      fflush(fp);
    }

    fp = nullptr;
    isClosed = true; // Don't allow re-opening.
    return true;
  }

  bool canUpdateCurrentLine() const {
    assert(isOpen());
    return termHonorsCarriageReturn;
  }

  void clearOutput() {
    assert(isOpen());
    assert(canUpdateCurrentLine());

    if (hasOutput) {
      // Clear the line before writing, this tends to produce better results
      // than clearing the unwritten tail of the line written below.
      fprintf(fp, "\r%*s\r", numCurrentCharacters, "");
      fflush(fp);
      hasOutput = false;
    }
  }

  int getNumColumns() {
    auto result = llvm::sys::Process::StandardOutColumns();

    // If we were unable to query the terminal, just use a default.
    if (!result) {
      return 80;
    }

    return result;
  }

  void setCurrentLine(const std::string& text) {
    assert(isOpen());
    assert(text.find('\r') == std::string::npos);
    assert(text.find('\n') == std::string::npos);

    // Clear the line before writing, this tends to produce better results than
    // clearing the unwritten tail of the line written below.
    clearOutput();

    // Write the line, trimming it to fit in the current terminal.
    int columns = getNumColumns();
    if (columns > 0 && (int)text.size() > columns) {
      // Elide the middle of the text.
      int midpoint = columns / 2;
      std::string elided = text.substr(0, std::max(0, midpoint - 2)) + "..." +
        text.substr(text.size() - (columns - (midpoint + 1)));
      assert(columns < 3 || (int)elided.size() == columns);
      fprintf(fp, "%s", elided.c_str());
      numCurrentCharacters = elided.size();
    } else {
      fprintf(fp, "%s", text.c_str());
      numCurrentCharacters = text.size();
    }
    fflush(fp);

    hasOutput = numCurrentCharacters != 0;
  }

  void setOrWriteLine(const std::string& text) {
    if (canUpdateCurrentLine())
      return setCurrentLine(text);
    writeText(text + "\n");
  }

  void finishLine() {
    assert(isOpen());

    // Finish the current line, if necessary.
    if (canUpdateCurrentLine() && hasOutput) {
      fputc('\n', fp);
      fflush(fp);
      hasOutput = false;
    }
  }

  void writeText(const std::string& text) {
    assert(isOpen());
    assert(text.size() && text.back() == '\n');

    // Clear the current output, if present.
    if (hasOutput)
      clearOutput();

    fwrite(text.c_str(), text.size(), 1, fp);
    fflush(fp);
  }
};

}

namespace llbuild {
namespace commands {

CommandLineStatusOutput::CommandLineStatusOutput()
    : impl(new CommandLineStatusOutputImpl())
{
}

CommandLineStatusOutput::~CommandLineStatusOutput() {
  delete static_cast<CommandLineStatusOutputImpl*>(impl);
}

bool CommandLineStatusOutput::open(std::string* error_out) {
  return static_cast<CommandLineStatusOutputImpl*>(impl)->open(error_out);
}

bool CommandLineStatusOutput::close(std::string* error_out) {
  return static_cast<CommandLineStatusOutputImpl*>(impl)->close(error_out);
}

bool CommandLineStatusOutput::canUpdateCurrentLine() const {
  return
    static_cast<CommandLineStatusOutputImpl*>(impl)->canUpdateCurrentLine();
}

void CommandLineStatusOutput::clearOutput() {
  return static_cast<CommandLineStatusOutputImpl*>(impl)->clearOutput();
}

void CommandLineStatusOutput::setCurrentLine(const std::string& text) {
  return
    static_cast<CommandLineStatusOutputImpl*>(impl)->setCurrentLine(text);
}

void CommandLineStatusOutput::setOrWriteLine(const std::string& text) {
  return
    static_cast<CommandLineStatusOutputImpl*>(impl)->setOrWriteLine(text);
}

void CommandLineStatusOutput::finishLine() {
  return static_cast<CommandLineStatusOutputImpl*>(impl)->finishLine();
}

void CommandLineStatusOutput::writeText(const std::string& text) {
  return
    static_cast<CommandLineStatusOutputImpl*>(impl)->writeText(text);
}

}
}
<commit_msg>[portability] Avoid direct use of isatty().<commit_after>//===-- CommandLineStatusOutput.cpp ---------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "CommandLineStatusOutput.h"

#include <cassert>
#include <cstdio>

#include <llvm/Support/Process.h>

namespace {

struct CommandLineStatusOutputImpl {
  /// The output stream.
  FILE* fp{nullptr};

  /// Whether the output stream honors '\r'.
  bool termHonorsCarriageReturn{false};

  /// Whether the stream has current output.
  bool hasOutput{false};

  /// Whether the stream has been closed.
  bool isClosed{false};

  /// The number of characters written to the current line.
  int numCurrentCharacters{0};

  CommandLineStatusOutputImpl() {}

  ~CommandLineStatusOutputImpl() {
    if (isOpen()) {
      std::string error;
      close(&error);
    }
  }

  bool isOpen() const {
    return fp != nullptr;
  }

  bool open(std::string* error_out) {
    assert(!isOpen() && !isClosed);
    fp = stdout;

    // Detect the features of the output.
    int fd = fileno(fp);
    if (llvm::sys::Process::FileDescriptorIsDisplayed(fd)) {
      // If the terminal is a tty, check the TERM variable.
      const char* term = ::getenv("TERM");

      // We assume the terminal honors '\r' if it is either not-"dumb", or it is
      // "dumb" and we are inside Emacs (comint-mode reports as "dumb").
      if (term) {
        termHonorsCarriageReturn = (term != std::string("dumb") ||
                                    ::getenv("INSIDE_EMACS") != nullptr);
      }
    }

    return true;
  }

  bool close(std::string* error_out) {
    if (hasOutput) {
      fprintf(fp, "\n");
      fflush(fp);
    }

    fp = nullptr;
    isClosed = true; // Don't allow re-opening.
    return true;
  }

  bool canUpdateCurrentLine() const {
    assert(isOpen());
    return termHonorsCarriageReturn;
  }

  void clearOutput() {
    assert(isOpen());
    assert(canUpdateCurrentLine());

    if (hasOutput) {
      // Clear the line before writing, this tends to produce better results
      // than clearing the unwritten tail of the line written below.
      fprintf(fp, "\r%*s\r", numCurrentCharacters, "");
      fflush(fp);
      hasOutput = false;
    }
  }

  int getNumColumns() {
    auto result = llvm::sys::Process::StandardOutColumns();

    // If we were unable to query the terminal, just use a default.
    if (!result) {
      return 80;
    }

    return result;
  }

  void setCurrentLine(const std::string& text) {
    assert(isOpen());
    assert(text.find('\r') == std::string::npos);
    assert(text.find('\n') == std::string::npos);

    // Clear the line before writing, this tends to produce better results than
    // clearing the unwritten tail of the line written below.
    clearOutput();

    // Write the line, trimming it to fit in the current terminal.
    int columns = getNumColumns();
    if (columns > 0 && (int)text.size() > columns) {
      // Elide the middle of the text.
      int midpoint = columns / 2;
      std::string elided = text.substr(0, std::max(0, midpoint - 2)) + "..." +
        text.substr(text.size() - (columns - (midpoint + 1)));
      assert(columns < 3 || (int)elided.size() == columns);
      fprintf(fp, "%s", elided.c_str());
      numCurrentCharacters = elided.size();
    } else {
      fprintf(fp, "%s", text.c_str());
      numCurrentCharacters = text.size();
    }
    fflush(fp);

    hasOutput = numCurrentCharacters != 0;
  }

  void setOrWriteLine(const std::string& text) {
    if (canUpdateCurrentLine())
      return setCurrentLine(text);
    writeText(text + "\n");
  }

  void finishLine() {
    assert(isOpen());

    // Finish the current line, if necessary.
    if (canUpdateCurrentLine() && hasOutput) {
      fputc('\n', fp);
      fflush(fp);
      hasOutput = false;
    }
  }

  void writeText(const std::string& text) {
    assert(isOpen());
    assert(text.size() && text.back() == '\n');

    // Clear the current output, if present.
    if (hasOutput)
      clearOutput();

    fwrite(text.c_str(), text.size(), 1, fp);
    fflush(fp);
  }
};

}

namespace llbuild {
namespace commands {

CommandLineStatusOutput::CommandLineStatusOutput()
    : impl(new CommandLineStatusOutputImpl())
{
}

CommandLineStatusOutput::~CommandLineStatusOutput() {
  delete static_cast<CommandLineStatusOutputImpl*>(impl);
}

bool CommandLineStatusOutput::open(std::string* error_out) {
  return static_cast<CommandLineStatusOutputImpl*>(impl)->open(error_out);
}

bool CommandLineStatusOutput::close(std::string* error_out) {
  return static_cast<CommandLineStatusOutputImpl*>(impl)->close(error_out);
}

bool CommandLineStatusOutput::canUpdateCurrentLine() const {
  return
    static_cast<CommandLineStatusOutputImpl*>(impl)->canUpdateCurrentLine();
}

void CommandLineStatusOutput::clearOutput() {
  return static_cast<CommandLineStatusOutputImpl*>(impl)->clearOutput();
}

void CommandLineStatusOutput::setCurrentLine(const std::string& text) {
  return
    static_cast<CommandLineStatusOutputImpl*>(impl)->setCurrentLine(text);
}

void CommandLineStatusOutput::setOrWriteLine(const std::string& text) {
  return
    static_cast<CommandLineStatusOutputImpl*>(impl)->setOrWriteLine(text);
}

void CommandLineStatusOutput::finishLine() {
  return static_cast<CommandLineStatusOutputImpl*>(impl)->finishLine();
}

void CommandLineStatusOutput::writeText(const std::string& text) {
  return
    static_cast<CommandLineStatusOutputImpl*>(impl)->writeText(text);
}

}
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: expbase.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 19:17:49 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SC_EXPBASE_HXX
#define SC_EXPBASE_HXX

#ifndef _SOLAR_H
#include <tools/solar.h>
#endif

#ifndef SC_SCGLOB_HXX
#include "global.hxx"
#endif

#ifndef SC_ADDRESS_HXX
#include "address.hxx"
#endif

class SvStream;
class ScFieldEditEngine;

class ScExportBase
{
public:
#if defined UNX || defined MAC
    static const sal_Char __FAR_DATA sNewLine;
#else
    static const sal_Char __FAR_DATA sNewLine[];
#endif

protected:

    SvStream&           rStrm;
    ScRange             aRange;
    ScDocument*         pDoc;
    SvNumberFormatter*  pFormatter;
    ScFieldEditEngine*  pEditEngine;

public:

                        ScExportBase( SvStream&, ScDocument*, const ScRange& );
    virtual             ~ScExportBase();

                        // Hidden Cols/Rows an den Raendern trimmen,
                        // return: TRUE wenn Bereich vorhanden
                        // Start/End/Col/Row muessen gueltige Ausgangswerte sein
    BOOL                TrimDataArea( SCTAB nTab, SCCOL& nStartCol,
                            SCROW& nStartRow, SCCOL& nEndCol, SCROW& nEndRow ) const;

                        // Ausgabebereich einer Tabelle ermitteln,
                        // Hidden Cols/Rows an den Raendern beruecksichtigt,
                        // return: TRUE wenn Bereich vorhanden
    BOOL                GetDataArea( SCTAB nTab, SCCOL& nStartCol,
                            SCROW& nStartRow, SCCOL& nEndCol, SCROW& nEndRow ) const;

                        // Tabelle nicht vorhanden oder leer
    BOOL                IsEmptyTable( SCTAB nTab ) const;

    ScFieldEditEngine&  GetEditEngine() const;

};

#endif  // SC_EXPBASE_HXX

<commit_msg>INTEGRATION: CWS dr55 (1.3.456); FILE MERGED 2007/06/20 19:30:40 er 1.3.456.1: #i78630# remove MacOS9 specifics<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: expbase.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2007-07-06 12:38:15 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SC_EXPBASE_HXX
#define SC_EXPBASE_HXX

#ifndef _SOLAR_H
#include <tools/solar.h>
#endif

#ifndef SC_SCGLOB_HXX
#include "global.hxx"
#endif

#ifndef SC_ADDRESS_HXX
#include "address.hxx"
#endif

class SvStream;
class ScFieldEditEngine;

class ScExportBase
{
public:
#if defined UNX
    static const sal_Char __FAR_DATA sNewLine;
#else
    static const sal_Char __FAR_DATA sNewLine[];
#endif

protected:

    SvStream&           rStrm;
    ScRange             aRange;
    ScDocument*         pDoc;
    SvNumberFormatter*  pFormatter;
    ScFieldEditEngine*  pEditEngine;

public:

                        ScExportBase( SvStream&, ScDocument*, const ScRange& );
    virtual             ~ScExportBase();

                        // Hidden Cols/Rows an den Raendern trimmen,
                        // return: TRUE wenn Bereich vorhanden
                        // Start/End/Col/Row muessen gueltige Ausgangswerte sein
    BOOL                TrimDataArea( SCTAB nTab, SCCOL& nStartCol,
                            SCROW& nStartRow, SCCOL& nEndCol, SCROW& nEndRow ) const;

                        // Ausgabebereich einer Tabelle ermitteln,
                        // Hidden Cols/Rows an den Raendern beruecksichtigt,
                        // return: TRUE wenn Bereich vorhanden
    BOOL                GetDataArea( SCTAB nTab, SCCOL& nStartCol,
                            SCROW& nStartRow, SCCOL& nEndCol, SCROW& nEndRow ) const;

                        // Tabelle nicht vorhanden oder leer
    BOOL                IsEmptyTable( SCTAB nTab ) const;

    ScFieldEditEngine&  GetEditEngine() const;

};

#endif  // SC_EXPBASE_HXX

<|endoftext|>


<commit_before>//===-- MBlazeISelDAGToDAG.cpp - A dag to dag inst selector for MBlaze ----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines an instruction selector for the MBlaze target.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "mblaze-isel"
#include "MBlaze.h"
#include "MBlazeMachineFunction.h"
#include "MBlazeRegisterInfo.h"
#include "MBlazeSubtarget.h"
#include "MBlazeTargetMachine.h"
#include "llvm/GlobalValue.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/Support/CFG.h"
#include "llvm/Type.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

//===----------------------------------------------------------------------===//
// Instruction Selector Implementation
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
// MBlazeDAGToDAGISel - MBlaze specific code to select MBlaze machine
// instructions for SelectionDAG operations.
//===----------------------------------------------------------------------===//
namespace {

class MBlazeDAGToDAGISel : public SelectionDAGISel {

  /// TM - Keep a reference to MBlazeTargetMachine.
  MBlazeTargetMachine &TM;

  /// Subtarget - Keep a pointer to the MBlazeSubtarget around so that we can
  /// make the right decision when generating code for different targets.
  const MBlazeSubtarget &Subtarget;

public:
  explicit MBlazeDAGToDAGISel(MBlazeTargetMachine &tm) :
  SelectionDAGISel(tm),
  TM(tm), Subtarget(tm.getSubtarget<MBlazeSubtarget>()) {}

  // Pass Name
  virtual const char *getPassName() const {
    return "MBlaze DAG->DAG Pattern Instruction Selection";
  }
private:
  // Include the pieces autogenerated from the target description.
  #include "MBlazeGenDAGISel.inc"

  /// getTargetMachine - Return a reference to the TargetMachine, casted
  /// to the target-specific type.
  const MBlazeTargetMachine &getTargetMachine() {
    return static_cast<const MBlazeTargetMachine &>(TM);
  }

  /// getInstrInfo - Return a reference to the TargetInstrInfo, casted
  /// to the target-specific type.
  const MBlazeInstrInfo *getInstrInfo() {
    return getTargetMachine().getInstrInfo();
  }

  SDNode *getGlobalBaseReg();
  SDNode *Select(SDNode *N);

  // Complex Pattern.
  bool SelectAddr(SDNode *Op, SDValue N,
                  SDValue &Base, SDValue &Offset);

  // Address Selection
  bool SelectAddrRegReg(SDNode *Op, SDValue N, SDValue &Base, SDValue &Index);
  bool SelectAddrRegImm(SDNode *Op, SDValue N, SDValue &Disp, SDValue &Base);

  // getI32Imm - Return a target constant with the specified value, of type i32.
  inline SDValue getI32Imm(unsigned Imm) {
    return CurDAG->getTargetConstant(Imm, MVT::i32);
  }
};

}

/// isIntS32Immediate - This method tests to see if the node is either a 32-bit
/// or 64-bit immediate, and if the value can be accurately represented as a
/// sign extension from a 32-bit value.  If so, this returns true and the
/// immediate.
static bool isIntS32Immediate(SDNode *N, int32_t &Imm) {
  unsigned Opc = N->getOpcode();
  if (Opc != ISD::Constant)
    return false;

  Imm = (int32_t)cast<ConstantSDNode>(N)->getZExtValue();
  if (N->getValueType(0) == MVT::i32)
    return Imm == (int32_t)cast<ConstantSDNode>(N)->getZExtValue();
  else
    return Imm == (int64_t)cast<ConstantSDNode>(N)->getZExtValue();
}

static bool isIntS32Immediate(SDValue Op, int32_t &Imm) {
  return isIntS32Immediate(Op.getNode(), Imm);
}

/// SelectAddressRegReg - Given the specified addressed, check to see if it
/// can be represented as an indexed [r+r] operation.  Returns false if it
/// can be more efficiently represented with [r+imm].
bool MBlazeDAGToDAGISel::
SelectAddrRegReg(SDNode *Op, SDValue N, SDValue &Base, SDValue &Index) {
  if (N.getOpcode() == ISD::FrameIndex) return false;
  if (N.getOpcode() == ISD::TargetExternalSymbol ||
      N.getOpcode() == ISD::TargetGlobalAddress)
    return false;  // direct calls.

  int32_t imm = 0;
  if (N.getOpcode() == ISD::ADD || N.getOpcode() == ISD::OR) {
    if (isIntS32Immediate(N.getOperand(1), imm))
      return false;    // r+i

    if (N.getOperand(0).getOpcode() == ISD::TargetJumpTable ||
        N.getOperand(1).getOpcode() == ISD::TargetJumpTable)
      return false; // jump tables.

    Base = N.getOperand(1);
    Index = N.getOperand(0);
    return true;
  }

  return false;
}

/// Returns true if the address N can be represented by a base register plus
/// a signed 32-bit displacement [r+imm], and if it is not better
/// represented as reg+reg.
bool MBlazeDAGToDAGISel::
SelectAddrRegImm(SDNode *Op, SDValue N, SDValue &Disp, SDValue &Base) {
  // If this can be more profitably realized as r+r, fail.
  if (SelectAddrRegReg(Op, N, Disp, Base))
    return false;

  if (N.getOpcode() == ISD::ADD || N.getOpcode() == ISD::OR) {
    int32_t imm = 0;
    if (isIntS32Immediate(N.getOperand(1), imm)) {
      Disp = CurDAG->getTargetConstant(imm, MVT::i32);
      if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N.getOperand(0))) {
        Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType());
      } else {
        Base = N.getOperand(0);
      }
      DEBUG( errs() << "WESLEY: Using Operand Immediate\n" );
      return true; // [r+i]
    }
  } else if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N)) {
    // Loading from a constant address.
    uint32_t Imm = CN->getZExtValue();
    Disp = CurDAG->getTargetConstant(Imm, CN->getValueType(0));
    Base = CurDAG->getRegister(MBlaze::R0, CN->getValueType(0));
    DEBUG( errs() << "WESLEY: Using Constant Node\n" );
    return true;
  }

  Disp = CurDAG->getTargetConstant(0, TM.getTargetLowering()->getPointerTy());
  if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N))
    Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType());
  else
    Base = N;
  return true;      // [r+0]
}

/// getGlobalBaseReg - Output the instructions required to put the
/// GOT address into a register.
SDNode *MBlazeDAGToDAGISel::getGlobalBaseReg() {
  unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF);
  return CurDAG->getRegister(GlobalBaseReg, TLI.getPointerTy()).getNode();
}

/// ComplexPattern used on MBlazeInstrInfo
/// Used on MBlaze Load/Store instructions
bool MBlazeDAGToDAGISel::
SelectAddr(SDNode *Op, SDValue Addr, SDValue &Offset, SDValue &Base) {
  // if Address is FI, get the TargetFrameIndex.
  if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
    Base   = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
    Offset = CurDAG->getTargetConstant(0, MVT::i32);
    return true;
  }

  // on PIC code Load GA
  if (TM.getRelocationModel() == Reloc::PIC_) {
    if ((Addr.getOpcode() == ISD::TargetGlobalAddress) ||
        (Addr.getOpcode() == ISD::TargetConstantPool) ||
        (Addr.getOpcode() == ISD::TargetJumpTable)){
      Base   = CurDAG->getRegister(MBlaze::R15, MVT::i32);
      Offset = Addr;
      return true;
    }
  } else {
    if ((Addr.getOpcode() == ISD::TargetExternalSymbol ||
        Addr.getOpcode() == ISD::TargetGlobalAddress))
      return false;
  }

  // Operand is a result from an ADD.
  if (Addr.getOpcode() == ISD::ADD) {
    if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
      if (isUInt<16>(CN->getZExtValue())) {

        // If the first operand is a FI, get the TargetFI Node
        if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>
                                    (Addr.getOperand(0))) {
          Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
        } else {
          Base = Addr.getOperand(0);
        }

        Offset = CurDAG->getTargetConstant(CN->getZExtValue(), MVT::i32);
        return true;
      }
    }
  }

  Base   = Addr;
  Offset = CurDAG->getTargetConstant(0, MVT::i32);
  return true;
}

/// Select instructions not customized! Used for
/// expanded, promoted and normal instructions
SDNode* MBlazeDAGToDAGISel::Select(SDNode *Node) {
  unsigned Opcode = Node->getOpcode();
  DebugLoc dl = Node->getDebugLoc();

  // Dump information about the Node being selected
  DEBUG(errs() << "Selecting: "; Node->dump(CurDAG); errs() << "\n");

  // If we have a custom node, we already have selected!
  if (Node->isMachineOpcode()) {
    DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n");
    return NULL;
  }

  ///
  // Instruction Selection not handled by the auto-generated
  // tablegen selection should be handled here.
  ///
  switch(Opcode) {
    default: break;

    // Get target GOT address.
    case ISD::GLOBAL_OFFSET_TABLE:
      return getGlobalBaseReg();

    case ISD::FrameIndex: {
        SDValue imm = CurDAG->getTargetConstant(0, MVT::i32);
        int FI = dyn_cast<FrameIndexSDNode>(Node)->getIndex();
        EVT VT = Node->getValueType(0);
        SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
        unsigned Opc = MBlaze::ADDI;
        if (Node->hasOneUse())
          return CurDAG->SelectNodeTo(Node, Opc, VT, TFI, imm);
        return CurDAG->getMachineNode(Opc, dl, VT, TFI, imm);
    }

    /// Handle direct and indirect calls when using PIC. On PIC, when
    /// GOT is smaller than about 64k (small code) the GA target is
    /// loaded with only one instruction. Otherwise GA's target must
    /// be loaded with 3 instructions.
    case MBlazeISD::JmpLink: {
      if (TM.getRelocationModel() == Reloc::PIC_) {
        SDValue Chain  = Node->getOperand(0);
        SDValue Callee = Node->getOperand(1);
        SDValue R20Reg = CurDAG->getRegister(MBlaze::R20, MVT::i32);
        SDValue InFlag(0, 0);

        if ( (isa<GlobalAddressSDNode>(Callee)) ||
             (isa<ExternalSymbolSDNode>(Callee)) )
        {
          /// Direct call for global addresses and external symbols
          SDValue GPReg = CurDAG->getRegister(MBlaze::R15, MVT::i32);

          // Use load to get GOT target
          SDValue Ops[] = { Callee, GPReg, Chain };
          SDValue Load = SDValue(CurDAG->getMachineNode(MBlaze::LW, dl,
                                 MVT::i32, MVT::Other, Ops, 3), 0);
          Chain = Load.getValue(1);

          // Call target must be on T9
          Chain = CurDAG->getCopyToReg(Chain, dl, R20Reg, Load, InFlag);
        } else
          /// Indirect call
          Chain = CurDAG->getCopyToReg(Chain, dl, R20Reg, Callee, InFlag);

        // Emit Jump and Link Register
        SDNode *ResNode = CurDAG->getMachineNode(MBlaze::BRLID, dl, MVT::Other,
                                                 MVT::Flag, R20Reg, Chain);
        Chain  = SDValue(ResNode, 0);
        InFlag = SDValue(ResNode, 1);
        ReplaceUses(SDValue(Node, 0), Chain);
        ReplaceUses(SDValue(Node, 1), InFlag);
        return ResNode;
      }
    }
  }

  // Select the default instruction
  SDNode *ResNode = SelectCode(Node);

  DEBUG(errs() << "=> ");
  if (ResNode == NULL || ResNode == Node)
    DEBUG(Node->dump(CurDAG));
  else
    DEBUG(ResNode->dump(CurDAG));
  DEBUG(errs() << "\n");
  return ResNode;
}

/// createMBlazeISelDag - This pass converts a legalized DAG into a
/// MBlaze-specific DAG, ready for instruction scheduling.
FunctionPass *llvm::createMBlazeISelDag(MBlazeTargetMachine &TM) {
  return new MBlazeDAGToDAGISel(TM);
}
<commit_msg>remove dead code, mblaze uses SelectAddrRegImm/SelectAddrRegReg, not SelectAddr<commit_after>//===-- MBlazeISelDAGToDAG.cpp - A dag to dag inst selector for MBlaze ----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines an instruction selector for the MBlaze target.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "mblaze-isel"
#include "MBlaze.h"
#include "MBlazeMachineFunction.h"
#include "MBlazeRegisterInfo.h"
#include "MBlazeSubtarget.h"
#include "MBlazeTargetMachine.h"
#include "llvm/GlobalValue.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/Support/CFG.h"
#include "llvm/Type.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

//===----------------------------------------------------------------------===//
// Instruction Selector Implementation
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
// MBlazeDAGToDAGISel - MBlaze specific code to select MBlaze machine
// instructions for SelectionDAG operations.
//===----------------------------------------------------------------------===//
namespace {

class MBlazeDAGToDAGISel : public SelectionDAGISel {

  /// TM - Keep a reference to MBlazeTargetMachine.
  MBlazeTargetMachine &TM;

  /// Subtarget - Keep a pointer to the MBlazeSubtarget around so that we can
  /// make the right decision when generating code for different targets.
  const MBlazeSubtarget &Subtarget;

public:
  explicit MBlazeDAGToDAGISel(MBlazeTargetMachine &tm) :
  SelectionDAGISel(tm),
  TM(tm), Subtarget(tm.getSubtarget<MBlazeSubtarget>()) {}

  // Pass Name
  virtual const char *getPassName() const {
    return "MBlaze DAG->DAG Pattern Instruction Selection";
  }
private:
  // Include the pieces autogenerated from the target description.
  #include "MBlazeGenDAGISel.inc"

  /// getTargetMachine - Return a reference to the TargetMachine, casted
  /// to the target-specific type.
  const MBlazeTargetMachine &getTargetMachine() {
    return static_cast<const MBlazeTargetMachine &>(TM);
  }

  /// getInstrInfo - Return a reference to the TargetInstrInfo, casted
  /// to the target-specific type.
  const MBlazeInstrInfo *getInstrInfo() {
    return getTargetMachine().getInstrInfo();
  }

  SDNode *getGlobalBaseReg();
  SDNode *Select(SDNode *N);

  // Address Selection
  bool SelectAddrRegReg(SDNode *Op, SDValue N, SDValue &Base, SDValue &Index);
  bool SelectAddrRegImm(SDNode *Op, SDValue N, SDValue &Disp, SDValue &Base);

  // getI32Imm - Return a target constant with the specified value, of type i32.
  inline SDValue getI32Imm(unsigned Imm) {
    return CurDAG->getTargetConstant(Imm, MVT::i32);
  }
};

}

/// isIntS32Immediate - This method tests to see if the node is either a 32-bit
/// or 64-bit immediate, and if the value can be accurately represented as a
/// sign extension from a 32-bit value.  If so, this returns true and the
/// immediate.
static bool isIntS32Immediate(SDNode *N, int32_t &Imm) {
  unsigned Opc = N->getOpcode();
  if (Opc != ISD::Constant)
    return false;

  Imm = (int32_t)cast<ConstantSDNode>(N)->getZExtValue();
  if (N->getValueType(0) == MVT::i32)
    return Imm == (int32_t)cast<ConstantSDNode>(N)->getZExtValue();
  else
    return Imm == (int64_t)cast<ConstantSDNode>(N)->getZExtValue();
}

static bool isIntS32Immediate(SDValue Op, int32_t &Imm) {
  return isIntS32Immediate(Op.getNode(), Imm);
}

/// SelectAddressRegReg - Given the specified addressed, check to see if it
/// can be represented as an indexed [r+r] operation.  Returns false if it
/// can be more efficiently represented with [r+imm].
bool MBlazeDAGToDAGISel::
SelectAddrRegReg(SDNode *Op, SDValue N, SDValue &Base, SDValue &Index) {
  if (N.getOpcode() == ISD::FrameIndex) return false;
  if (N.getOpcode() == ISD::TargetExternalSymbol ||
      N.getOpcode() == ISD::TargetGlobalAddress)
    return false;  // direct calls.

  int32_t imm = 0;
  if (N.getOpcode() == ISD::ADD || N.getOpcode() == ISD::OR) {
    if (isIntS32Immediate(N.getOperand(1), imm))
      return false;    // r+i

    if (N.getOperand(0).getOpcode() == ISD::TargetJumpTable ||
        N.getOperand(1).getOpcode() == ISD::TargetJumpTable)
      return false; // jump tables.

    Base = N.getOperand(1);
    Index = N.getOperand(0);
    return true;
  }

  return false;
}

/// Returns true if the address N can be represented by a base register plus
/// a signed 32-bit displacement [r+imm], and if it is not better
/// represented as reg+reg.
bool MBlazeDAGToDAGISel::
SelectAddrRegImm(SDNode *Op, SDValue N, SDValue &Disp, SDValue &Base) {
  // If this can be more profitably realized as r+r, fail.
  if (SelectAddrRegReg(Op, N, Disp, Base))
    return false;

  if (N.getOpcode() == ISD::ADD || N.getOpcode() == ISD::OR) {
    int32_t imm = 0;
    if (isIntS32Immediate(N.getOperand(1), imm)) {
      Disp = CurDAG->getTargetConstant(imm, MVT::i32);
      if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N.getOperand(0))) {
        Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType());
      } else {
        Base = N.getOperand(0);
      }
      DEBUG( errs() << "WESLEY: Using Operand Immediate\n" );
      return true; // [r+i]
    }
  } else if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N)) {
    // Loading from a constant address.
    uint32_t Imm = CN->getZExtValue();
    Disp = CurDAG->getTargetConstant(Imm, CN->getValueType(0));
    Base = CurDAG->getRegister(MBlaze::R0, CN->getValueType(0));
    DEBUG( errs() << "WESLEY: Using Constant Node\n" );
    return true;
  }

  Disp = CurDAG->getTargetConstant(0, TM.getTargetLowering()->getPointerTy());
  if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N))
    Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType());
  else
    Base = N;
  return true;      // [r+0]
}

/// getGlobalBaseReg - Output the instructions required to put the
/// GOT address into a register.
SDNode *MBlazeDAGToDAGISel::getGlobalBaseReg() {
  unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF);
  return CurDAG->getRegister(GlobalBaseReg, TLI.getPointerTy()).getNode();
}

/// Select instructions not customized! Used for
/// expanded, promoted and normal instructions
SDNode* MBlazeDAGToDAGISel::Select(SDNode *Node) {
  unsigned Opcode = Node->getOpcode();
  DebugLoc dl = Node->getDebugLoc();

  // Dump information about the Node being selected
  DEBUG(errs() << "Selecting: "; Node->dump(CurDAG); errs() << "\n");

  // If we have a custom node, we already have selected!
  if (Node->isMachineOpcode()) {
    DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n");
    return NULL;
  }

  ///
  // Instruction Selection not handled by the auto-generated
  // tablegen selection should be handled here.
  ///
  switch(Opcode) {
    default: break;

    // Get target GOT address.
    case ISD::GLOBAL_OFFSET_TABLE:
      return getGlobalBaseReg();

    case ISD::FrameIndex: {
        SDValue imm = CurDAG->getTargetConstant(0, MVT::i32);
        int FI = dyn_cast<FrameIndexSDNode>(Node)->getIndex();
        EVT VT = Node->getValueType(0);
        SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
        unsigned Opc = MBlaze::ADDI;
        if (Node->hasOneUse())
          return CurDAG->SelectNodeTo(Node, Opc, VT, TFI, imm);
        return CurDAG->getMachineNode(Opc, dl, VT, TFI, imm);
    }

    /// Handle direct and indirect calls when using PIC. On PIC, when
    /// GOT is smaller than about 64k (small code) the GA target is
    /// loaded with only one instruction. Otherwise GA's target must
    /// be loaded with 3 instructions.
    case MBlazeISD::JmpLink: {
      if (TM.getRelocationModel() == Reloc::PIC_) {
        SDValue Chain  = Node->getOperand(0);
        SDValue Callee = Node->getOperand(1);
        SDValue R20Reg = CurDAG->getRegister(MBlaze::R20, MVT::i32);
        SDValue InFlag(0, 0);

        if ( (isa<GlobalAddressSDNode>(Callee)) ||
             (isa<ExternalSymbolSDNode>(Callee)) )
        {
          /// Direct call for global addresses and external symbols
          SDValue GPReg = CurDAG->getRegister(MBlaze::R15, MVT::i32);

          // Use load to get GOT target
          SDValue Ops[] = { Callee, GPReg, Chain };
          SDValue Load = SDValue(CurDAG->getMachineNode(MBlaze::LW, dl,
                                 MVT::i32, MVT::Other, Ops, 3), 0);
          Chain = Load.getValue(1);

          // Call target must be on T9
          Chain = CurDAG->getCopyToReg(Chain, dl, R20Reg, Load, InFlag);
        } else
          /// Indirect call
          Chain = CurDAG->getCopyToReg(Chain, dl, R20Reg, Callee, InFlag);

        // Emit Jump and Link Register
        SDNode *ResNode = CurDAG->getMachineNode(MBlaze::BRLID, dl, MVT::Other,
                                                 MVT::Flag, R20Reg, Chain);
        Chain  = SDValue(ResNode, 0);
        InFlag = SDValue(ResNode, 1);
        ReplaceUses(SDValue(Node, 0), Chain);
        ReplaceUses(SDValue(Node, 1), InFlag);
        return ResNode;
      }
    }
  }

  // Select the default instruction
  SDNode *ResNode = SelectCode(Node);

  DEBUG(errs() << "=> ");
  if (ResNode == NULL || ResNode == Node)
    DEBUG(Node->dump(CurDAG));
  else
    DEBUG(ResNode->dump(CurDAG));
  DEBUG(errs() << "\n");
  return ResNode;
}

/// createMBlazeISelDag - This pass converts a legalized DAG into a
/// MBlaze-specific DAG, ready for instruction scheduling.
FunctionPass *llvm::createMBlazeISelDag(MBlazeTargetMachine &TM) {
  return new MBlazeDAGToDAGISel(TM);
}
<|endoftext|>


<commit_before>//===-- PPCBranchSelector.cpp - Emit long conditional branches ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a pass that scans a machine function to determine which
// conditional branches need more than 16 bits of displacement to reach their
// target basic block.  It does this in two passes; a calculation of basic block
// positions pass, and a branch pseudo op to machine branch opcode pass.  This
// pass should be run last, just before the assembly printer.
//
//===----------------------------------------------------------------------===//

#include "PPC.h"
#include "MCTargetDesc/PPCPredicates.h"
#include "PPCInstrBuilder.h"
#include "PPCInstrInfo.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetSubtargetInfo.h"
using namespace llvm;

#define DEBUG_TYPE "ppc-branch-select"

STATISTIC(NumExpanded, "Number of branches expanded to long format");

namespace llvm {
  void initializePPCBSelPass(PassRegistry&);
}

namespace {
  struct PPCBSel : public MachineFunctionPass {
    static char ID;
    PPCBSel() : MachineFunctionPass(ID) {
      initializePPCBSelPass(*PassRegistry::getPassRegistry());
    }

    /// BlockSizes - The sizes of the basic blocks in the function.
    std::vector<unsigned> BlockSizes;

    bool runOnMachineFunction(MachineFunction &Fn) override;

    MachineFunctionProperties getRequiredProperties() const override {
      return MachineFunctionProperties().set(
          MachineFunctionProperties::Property::NoVRegs);
    }

    const char *getPassName() const override {
      return "PowerPC Branch Selector";
    }
  };
  char PPCBSel::ID = 0;
}

INITIALIZE_PASS(PPCBSel, "ppc-branch-select", "PowerPC Branch Selector",
                false, false)

/// createPPCBranchSelectionPass - returns an instance of the Branch Selection
/// Pass
///
FunctionPass *llvm::createPPCBranchSelectionPass() {
  return new PPCBSel();
}

bool PPCBSel::runOnMachineFunction(MachineFunction &Fn) {
  const PPCInstrInfo *TII =
      static_cast<const PPCInstrInfo *>(Fn.getSubtarget().getInstrInfo());
  // Give the blocks of the function a dense, in-order, numbering.
  Fn.RenumberBlocks();
  BlockSizes.resize(Fn.getNumBlockIDs());

  auto GetAlignmentAdjustment =
    [TII](MachineBasicBlock &MBB, unsigned Offset) -> unsigned {
    unsigned Align = MBB.getAlignment();
    if (!Align)
      return 0;

    unsigned AlignAmt = 1 << Align;
    unsigned ParentAlign = MBB.getParent()->getAlignment();

    if (Align <= ParentAlign)
      return OffsetToAlignment(Offset, AlignAmt);

    // The alignment of this MBB is larger than the function's alignment, so we
    // can't tell whether or not it will insert nops. Assume that it will.
    return AlignAmt + OffsetToAlignment(Offset, AlignAmt);
  };

  // Measure each MBB and compute a size for the entire function.
  unsigned FuncSize = 0;
  for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
       ++MFI) {
    MachineBasicBlock *MBB = &*MFI;

    // The end of the previous block may have extra nops if this block has an
    // alignment requirement.
    if (MBB->getNumber() > 0) {
      unsigned AlignExtra = GetAlignmentAdjustment(*MBB, FuncSize);
      BlockSizes[MBB->getNumber()-1] += AlignExtra;
      FuncSize += AlignExtra;
    }

    unsigned BlockSize = 0;
    for (MachineInstr &MI : *MBB)
      BlockSize += TII->getInstSizeInBytes(MI);

    BlockSizes[MBB->getNumber()] = BlockSize;
    FuncSize += BlockSize;
  }

  // If the entire function is smaller than the displacement of a branch field,
  // we know we don't need to shrink any branches in this function.  This is a
  // common case.
  if (FuncSize < (1 << 15)) {
    BlockSizes.clear();
    return false;
  }

  // For each conditional branch, if the offset to its destination is larger
  // than the offset field allows, transform it into a long branch sequence
  // like this:
  //   short branch:
  //     bCC MBB
  //   long branch:
  //     b!CC $PC+8
  //     b MBB
  //
  bool MadeChange = true;
  bool EverMadeChange = false;
  while (MadeChange) {
    // Iteratively expand branches until we reach a fixed point.
    MadeChange = false;

    for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
         ++MFI) {
      MachineBasicBlock &MBB = *MFI;
      unsigned MBBStartOffset = 0;
      for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
           I != E; ++I) {
        MachineBasicBlock *Dest = nullptr;
        if (I->getOpcode() == PPC::BCC && !I->getOperand(2).isImm())
          Dest = I->getOperand(2).getMBB();
        else if ((I->getOpcode() == PPC::BC || I->getOpcode() == PPC::BCn) &&
                 !I->getOperand(1).isImm())
          Dest = I->getOperand(1).getMBB();
        else if ((I->getOpcode() == PPC::BDNZ8 || I->getOpcode() == PPC::BDNZ ||
                  I->getOpcode() == PPC::BDZ8  || I->getOpcode() == PPC::BDZ) &&
                 !I->getOperand(0).isImm())
          Dest = I->getOperand(0).getMBB();

        if (!Dest) {
          MBBStartOffset += TII->getInstSizeInBytes(*I);
          continue;
        }

        // Determine the offset from the current branch to the destination
        // block.
        int BranchSize;
        if (Dest->getNumber() <= MBB.getNumber()) {
          // If this is a backwards branch, the delta is the offset from the
          // start of this block to this branch, plus the sizes of all blocks
          // from this block to the dest.
          BranchSize = MBBStartOffset;

          for (unsigned i = Dest->getNumber(), e = MBB.getNumber(); i != e; ++i)
            BranchSize += BlockSizes[i];
        } else {
          // Otherwise, add the size of the blocks between this block and the
          // dest to the number of bytes left in this block.
          BranchSize = -MBBStartOffset;

          for (unsigned i = MBB.getNumber(), e = Dest->getNumber(); i != e; ++i)
            BranchSize += BlockSizes[i];
        }

        // If this branch is in range, ignore it.
        if (isInt<16>(BranchSize)) {
          MBBStartOffset += 4;
          continue;
        }

        // Otherwise, we have to expand it to a long branch.
        MachineInstr &OldBranch = *I;
        DebugLoc dl = OldBranch.getDebugLoc();

        if (I->getOpcode() == PPC::BCC) {
          // The BCC operands are:
          // 0. PPC branch predicate
          // 1. CR register
          // 2. Target MBB
          PPC::Predicate Pred = (PPC::Predicate)I->getOperand(0).getImm();
          unsigned CRReg = I->getOperand(1).getReg();

          // Jump over the uncond branch inst (i.e. $PC+8) on opposite condition.
          BuildMI(MBB, I, dl, TII->get(PPC::BCC))
            .addImm(PPC::InvertPredicate(Pred)).addReg(CRReg).addImm(2);
        } else if (I->getOpcode() == PPC::BC) {
          unsigned CRBit = I->getOperand(0).getReg();
          BuildMI(MBB, I, dl, TII->get(PPC::BCn)).addReg(CRBit).addImm(2);
        } else if (I->getOpcode() == PPC::BCn) {
          unsigned CRBit = I->getOperand(0).getReg();
          BuildMI(MBB, I, dl, TII->get(PPC::BC)).addReg(CRBit).addImm(2);
        } else if (I->getOpcode() == PPC::BDNZ) {
          BuildMI(MBB, I, dl, TII->get(PPC::BDZ)).addImm(2);
        } else if (I->getOpcode() == PPC::BDNZ8) {
          BuildMI(MBB, I, dl, TII->get(PPC::BDZ8)).addImm(2);
        } else if (I->getOpcode() == PPC::BDZ) {
          BuildMI(MBB, I, dl, TII->get(PPC::BDNZ)).addImm(2);
        } else if (I->getOpcode() == PPC::BDZ8) {
          BuildMI(MBB, I, dl, TII->get(PPC::BDNZ8)).addImm(2);
        } else {
           llvm_unreachable("Unhandled branch type!");
        }

        // Uncond branch to the real destination.
        I = BuildMI(MBB, I, dl, TII->get(PPC::B)).addMBB(Dest);

        // Remove the old branch from the function.
        OldBranch.eraseFromParent();

        // Remember that this instruction is 8-bytes, increase the size of the
        // block by 4, remember to iterate.
        BlockSizes[MBB.getNumber()] += 4;
        MBBStartOffset += 8;
        ++NumExpanded;
        MadeChange = true;
      }
    }
    EverMadeChange |= MadeChange;
  }

  BlockSizes.clear();
  return true;
}
<commit_msg>[PowerPC] During branch relaxation, recompute padding offsets before each iteration<commit_after>//===-- PPCBranchSelector.cpp - Emit long conditional branches ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a pass that scans a machine function to determine which
// conditional branches need more than 16 bits of displacement to reach their
// target basic block.  It does this in two passes; a calculation of basic block
// positions pass, and a branch pseudo op to machine branch opcode pass.  This
// pass should be run last, just before the assembly printer.
//
//===----------------------------------------------------------------------===//

#include "PPC.h"
#include "MCTargetDesc/PPCPredicates.h"
#include "PPCInstrBuilder.h"
#include "PPCInstrInfo.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetSubtargetInfo.h"
using namespace llvm;

#define DEBUG_TYPE "ppc-branch-select"

STATISTIC(NumExpanded, "Number of branches expanded to long format");

namespace llvm {
  void initializePPCBSelPass(PassRegistry&);
}

namespace {
  struct PPCBSel : public MachineFunctionPass {
    static char ID;
    PPCBSel() : MachineFunctionPass(ID) {
      initializePPCBSelPass(*PassRegistry::getPassRegistry());
    }

    // The sizes of the basic blocks in the function (the first
    // element of the pair); the second element of the pair is the amount of the
    // size that is due to potential padding.
    std::vector<std::pair<unsigned, unsigned>> BlockSizes;

    bool runOnMachineFunction(MachineFunction &Fn) override;

    MachineFunctionProperties getRequiredProperties() const override {
      return MachineFunctionProperties().set(
          MachineFunctionProperties::Property::NoVRegs);
    }

    const char *getPassName() const override {
      return "PowerPC Branch Selector";
    }
  };
  char PPCBSel::ID = 0;
}

INITIALIZE_PASS(PPCBSel, "ppc-branch-select", "PowerPC Branch Selector",
                false, false)

/// createPPCBranchSelectionPass - returns an instance of the Branch Selection
/// Pass
///
FunctionPass *llvm::createPPCBranchSelectionPass() {
  return new PPCBSel();
}

bool PPCBSel::runOnMachineFunction(MachineFunction &Fn) {
  const PPCInstrInfo *TII =
      static_cast<const PPCInstrInfo *>(Fn.getSubtarget().getInstrInfo());
  // Give the blocks of the function a dense, in-order, numbering.
  Fn.RenumberBlocks();
  BlockSizes.resize(Fn.getNumBlockIDs());

  auto GetAlignmentAdjustment =
    [TII](MachineBasicBlock &MBB, unsigned Offset) -> unsigned {
    unsigned Align = MBB.getAlignment();
    if (!Align)
      return 0;

    unsigned AlignAmt = 1 << Align;
    unsigned ParentAlign = MBB.getParent()->getAlignment();

    if (Align <= ParentAlign)
      return OffsetToAlignment(Offset, AlignAmt);

    // The alignment of this MBB is larger than the function's alignment, so we
    // can't tell whether or not it will insert nops. Assume that it will.
    return AlignAmt + OffsetToAlignment(Offset, AlignAmt);
  };

  // Measure each MBB and compute a size for the entire function.
  unsigned FuncSize = 0;
  for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
       ++MFI) {
    MachineBasicBlock *MBB = &*MFI;

    // The end of the previous block may have extra nops if this block has an
    // alignment requirement.
    if (MBB->getNumber() > 0) {
      unsigned AlignExtra = GetAlignmentAdjustment(*MBB, FuncSize);

      auto &BS = BlockSizes[MBB->getNumber()-1];
      BS.first += AlignExtra;
      BS.second = AlignExtra;

      FuncSize += AlignExtra;
    }

    unsigned BlockSize = 0;
    for (MachineInstr &MI : *MBB)
      BlockSize += TII->getInstSizeInBytes(MI);

    BlockSizes[MBB->getNumber()].first = BlockSize;
    FuncSize += BlockSize;
  }

  // If the entire function is smaller than the displacement of a branch field,
  // we know we don't need to shrink any branches in this function.  This is a
  // common case.
  if (FuncSize < (1 << 15)) {
    BlockSizes.clear();
    return false;
  }

  // For each conditional branch, if the offset to its destination is larger
  // than the offset field allows, transform it into a long branch sequence
  // like this:
  //   short branch:
  //     bCC MBB
  //   long branch:
  //     b!CC $PC+8
  //     b MBB
  //
  bool MadeChange = true;
  bool EverMadeChange = false;
  while (MadeChange) {
    // Iteratively expand branches until we reach a fixed point.
    MadeChange = false;

    for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
         ++MFI) {
      MachineBasicBlock &MBB = *MFI;
      unsigned MBBStartOffset = 0;
      for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
           I != E; ++I) {
        MachineBasicBlock *Dest = nullptr;
        if (I->getOpcode() == PPC::BCC && !I->getOperand(2).isImm())
          Dest = I->getOperand(2).getMBB();
        else if ((I->getOpcode() == PPC::BC || I->getOpcode() == PPC::BCn) &&
                 !I->getOperand(1).isImm())
          Dest = I->getOperand(1).getMBB();
        else if ((I->getOpcode() == PPC::BDNZ8 || I->getOpcode() == PPC::BDNZ ||
                  I->getOpcode() == PPC::BDZ8  || I->getOpcode() == PPC::BDZ) &&
                 !I->getOperand(0).isImm())
          Dest = I->getOperand(0).getMBB();

        if (!Dest) {
          MBBStartOffset += TII->getInstSizeInBytes(*I);
          continue;
        }

        // Determine the offset from the current branch to the destination
        // block.
        int BranchSize;
        if (Dest->getNumber() <= MBB.getNumber()) {
          // If this is a backwards branch, the delta is the offset from the
          // start of this block to this branch, plus the sizes of all blocks
          // from this block to the dest.
          BranchSize = MBBStartOffset;

          for (unsigned i = Dest->getNumber(), e = MBB.getNumber(); i != e; ++i)
            BranchSize += BlockSizes[i].first;
        } else {
          // Otherwise, add the size of the blocks between this block and the
          // dest to the number of bytes left in this block.
          BranchSize = -MBBStartOffset;

          for (unsigned i = MBB.getNumber(), e = Dest->getNumber(); i != e; ++i)
            BranchSize += BlockSizes[i].first;
        }

        // If this branch is in range, ignore it.
        if (isInt<16>(BranchSize)) {
          MBBStartOffset += 4;
          continue;
        }

        // Otherwise, we have to expand it to a long branch.
        MachineInstr &OldBranch = *I;
        DebugLoc dl = OldBranch.getDebugLoc();

        if (I->getOpcode() == PPC::BCC) {
          // The BCC operands are:
          // 0. PPC branch predicate
          // 1. CR register
          // 2. Target MBB
          PPC::Predicate Pred = (PPC::Predicate)I->getOperand(0).getImm();
          unsigned CRReg = I->getOperand(1).getReg();

          // Jump over the uncond branch inst (i.e. $PC+8) on opposite condition.
          BuildMI(MBB, I, dl, TII->get(PPC::BCC))
            .addImm(PPC::InvertPredicate(Pred)).addReg(CRReg).addImm(2);
        } else if (I->getOpcode() == PPC::BC) {
          unsigned CRBit = I->getOperand(0).getReg();
          BuildMI(MBB, I, dl, TII->get(PPC::BCn)).addReg(CRBit).addImm(2);
        } else if (I->getOpcode() == PPC::BCn) {
          unsigned CRBit = I->getOperand(0).getReg();
          BuildMI(MBB, I, dl, TII->get(PPC::BC)).addReg(CRBit).addImm(2);
        } else if (I->getOpcode() == PPC::BDNZ) {
          BuildMI(MBB, I, dl, TII->get(PPC::BDZ)).addImm(2);
        } else if (I->getOpcode() == PPC::BDNZ8) {
          BuildMI(MBB, I, dl, TII->get(PPC::BDZ8)).addImm(2);
        } else if (I->getOpcode() == PPC::BDZ) {
          BuildMI(MBB, I, dl, TII->get(PPC::BDNZ)).addImm(2);
        } else if (I->getOpcode() == PPC::BDZ8) {
          BuildMI(MBB, I, dl, TII->get(PPC::BDNZ8)).addImm(2);
        } else {
           llvm_unreachable("Unhandled branch type!");
        }

        // Uncond branch to the real destination.
        I = BuildMI(MBB, I, dl, TII->get(PPC::B)).addMBB(Dest);

        // Remove the old branch from the function.
        OldBranch.eraseFromParent();

        // Remember that this instruction is 8-bytes, increase the size of the
        // block by 4, remember to iterate.
        BlockSizes[MBB.getNumber()].first += 4;
        MBBStartOffset += 8;
        ++NumExpanded;
        MadeChange = true;
      }
    }

    if (MadeChange) {
      // If we're going to iterate again, make sure we've updated our
      // padding-based contributions to the block sizes.
      unsigned Offset = 0;
      for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
           ++MFI) {
        MachineBasicBlock *MBB = &*MFI;

        if (MBB->getNumber() > 0) {
          auto &BS = BlockSizes[MBB->getNumber()-1];
          BS.first -= BS.second;
          Offset -= BS.second;

          unsigned AlignExtra = GetAlignmentAdjustment(*MBB, Offset);

          BS.first += AlignExtra;
          BS.second = AlignExtra;

          Offset += AlignExtra;
        }

        Offset += BlockSizes[MBB->getNumber()].first;
      }
    }

    EverMadeChange |= MadeChange;
  }

  BlockSizes.clear();
  return true;
}
<|endoftext|>