<commit_before>/**
* @file Main.cpp
*/
#include "GLFWEW.h"
#include "Texture.h"
#include "Shader.h"
#include "OffscreenBuffer.h"
#include <glm/gtc/matrix_transform.hpp>
#include <iostream>
#include <vector>

/// _f[^^.
struct Vertex
{
  glm::vec3 position; ///< W.
  glm::vec4 color; ///< F.
  glm::vec2 texCoord; ///< eNX`W.
};

/// _f[^.
const Vertex vertices[] = {
  { {-0.5f, -0.3f, 0.5f}, {0.0f, 1.0f, 0.0f, 1.0f}, {0.0f, 0.0f} },
  { { 0.3f, -0.3f, 0.5f}, {0.0f, 0.0f, 1.0f, 1.0f}, {1.0f, 0.0f} },
  { { 0.3f,  0.5f, 0.5f}, {1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 1.0f} },
  { {-0.5f,  0.5f, 0.5f}, {0.0f, 0.0f, 1.0f, 1.0f}, {0.0f, 1.0f} },

  { {-0.3f,  0.3f, 0.1f}, {0.0f, 0.0f, 1.0f, 1.0f}, {0.0f, 1.0f} },
  { {-0.3f, -0.5f, 0.1f}, {0.0f, 1.0f, 1.0f, 1.0f}, {0.0f, 0.0f} },
  { { 0.5f, -0.5f, 0.1f}, {0.0f, 0.0f, 1.0f, 1.0f}, {1.0f, 0.0f} },
  { { 0.5f, -0.5f, 0.1f}, {1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 0.0f} },
  { { 0.5f,  0.3f, 0.1f}, {1.0f, 1.0f, 0.0f, 1.0f}, {1.0f, 1.0f} },
  { {-0.3f,  0.3f, 0.1f}, {1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 1.0f} },
};

/// CfbNXf[^.
const GLuint indices[] = {
  0, 1, 2, 2, 3, 0,
  4, 5, 6, 7, 8, 9,
};

/**
* Vertex Buffer Object쐬.
*
* @param size _f[^̃TCY.
* @param data _f[^ւ̃|C^.
*
* @return 쐬VBO.
*/
GLuint CreateVBO(GLsizeiptr size, const GLvoid* data)
{
  GLuint vbo = 0;
  glGenBuffers(1, &vbo);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
  glBindBuffer(GL_ARRAY_BUFFER, 0);
  return vbo;
}

/**
* Index Buffer Object쐬.
*
* @param size CfbNXf[^̃TCY.
* @param data CfbNXf[^ւ̃|C^.
*
* @return 쐬IBO.
*/
GLuint CreateIBO(GLsizeiptr size, const GLvoid* data)
{
  GLuint ibo = 0;
  glGenBuffers(1, &ibo);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  return ibo;
}

/**
* _Agr[gݒ肷.
*
* @param index _Agr[g̃CfbNX.
* @param cls   _f[^^.
* @param mbr   _Agr[gɐݒ肷cls̃oϐ.
*/
#define SetVertexAttribPointer(index, cls, mbr) SetVertexAttribPointerI( \
  index, \
  sizeof(cls::mbr) / sizeof(float), \
  sizeof(cls), \
  reinterpret_cast<GLvoid*>(offsetof(cls, mbr)))

void SetVertexAttribPointerI(GLuint index, GLint size, GLsizei stride, const GLvoid* pointer)
{
  glEnableVertexAttribArray(index);
  glVertexAttribPointer(index, size, GL_FLOAT, GL_FALSE, stride, pointer);
}

/**
* Vertex Array Object쐬.
*
* @param vbo VAOɊ֘AtVBO.
* @param ibo VAOɊ֘AtIBO.
*
* @return 쐬VAO.
*/
GLuint CreateVAO(GLuint vbo, GLuint ibo)
{
  GLuint vao = 0;
  glGenVertexArrays(1, &vao);
  glBindVertexArray(vao);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  SetVertexAttribPointer(0, Vertex, position);
  SetVertexAttribPointer(1, Vertex, color);
  SetVertexAttribPointer(2, Vertex, texCoord);
  glBindVertexArray(0);
  glDeleteBuffers(1, &vbo);
  glDeleteBuffers(1, &ibo);
  return vao;
}

/// Gg[|Cg.
int main()
{
  GLFWEW::Window& window = GLFWEW::Window::Instance();
  if (!window.Init(800, 600, "OpenGL Tutorial")) {
    return 1;
  }

  const GLuint vbo = CreateVBO(sizeof(vertices), vertices);
  const GLuint ibo = CreateIBO(sizeof(indices), indices);
  const GLuint vao = CreateVAO(vbo, ibo);
  const GLuint shaderProgram = Shader::CreateProgramFromFile("Res/Tutorial.vert", "Res/Tutorial.frag");
  if (!vbo || !ibo || !vao || !shaderProgram) {
    return 1;
  }

  // eNX`f[^.
  TexturePtr tex = Texture::LoadFromFile("Res/sample.bmp");
  if (!tex) {
    return 1;
  }

  const OffscreenBufferPtr offscreen = OffscreenBuffer::Create(800, 600);

  glEnable(GL_DEPTH_TEST);

  // C[v.
  while (!window.ShouldClose()) {
    glBindFramebuffer(GL_FRAMEBUFFER, offscreen->GetFramebuffer());
    glClearColor(0.1f, 0.3f, 0.5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // _]ړ.
    static float degree = 0.0f;
    degree += 0.1f;
    if (degree >= 360.0f) { degree -= 360.0f; }
    const glm::vec3 viewPos = glm::rotate(glm::mat4(), glm::radians(degree), glm::vec3(0, 1, 0)) * glm::vec4(2, 3, 3, 1);

    glUseProgram(shaderProgram);
    const GLint matMVPLoc = glGetUniformLocation(shaderProgram, "matMVP");
    if (matMVPLoc >= 0) {
      const glm::mat4x4 matProj =
        glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);
      const glm::mat4x4 matView =
        glm::lookAt(viewPos, glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
      const glm::mat4x4 matMVP = matProj * matView;
      glUniformMatrix4fv(matMVPLoc, 1, GL_FALSE, &matMVP[0][0]);
    }
    const GLint colorSamplerLoc = glGetUniformLocation(shaderProgram, "colorSampler");
    if (colorSamplerLoc >= 0) {
      glUniform1i(colorSamplerLoc, 0);
      glActiveTexture(GL_TEXTURE0);
      glBindTexture(GL_TEXTURE_2D, tex->Id());
    }
    glBindVertexArray(vao);
    glDrawElements(
      GL_TRIANGLES, sizeof(indices)/sizeof(indices[0]),
      GL_UNSIGNED_INT, reinterpret_cast<const GLvoid*>(0));

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glClearColor(0.5f, 0.3f, 0.1f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    if (colorSamplerLoc >= 0) {
      glBindTexture(GL_TEXTURE_2D, offscreen->GetTexutre());
    }
    glDrawElements(
      GL_TRIANGLES, sizeof(indices) / sizeof(indices[0]),
      GL_UNSIGNED_INT, reinterpret_cast<const GLvoid*>(0));

    window.SwapBuffers();
  }

  glDeleteProgram(shaderProgram);
  glDeleteVertexArrays(1, &vao);

  return 0;
}<commit_msg>第05回3章まで実装.<commit_after>/**
* @file Main.cpp
*/
#include "GLFWEW.h"
#include "Texture.h"
#include "Shader.h"
#include "OffscreenBuffer.h"
#include <glm/gtc/matrix_transform.hpp>
#include <iostream>
#include <vector>

/// _f[^^.
struct Vertex
{
  glm::vec3 position; ///< W.
  glm::vec4 color; ///< F.
  glm::vec2 texCoord; ///< eNX`W.
};

/// _f[^.
const Vertex vertices[] = {
  { {-0.5f, -0.3f, 0.5f}, {0.0f, 1.0f, 0.0f, 1.0f}, {0.0f, 0.0f} },
  { { 0.3f, -0.3f, 0.5f}, {0.0f, 0.0f, 1.0f, 1.0f}, {1.0f, 0.0f} },
  { { 0.3f,  0.5f, 0.5f}, {1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 1.0f} },
  { {-0.5f,  0.5f, 0.5f}, {0.0f, 0.0f, 1.0f, 1.0f}, {0.0f, 1.0f} },

  { {-0.3f,  0.3f, 0.1f}, {0.0f, 0.0f, 1.0f, 1.0f}, {0.0f, 1.0f} },
  { {-0.3f, -0.5f, 0.1f}, {0.0f, 1.0f, 1.0f, 1.0f}, {0.0f, 0.0f} },
  { { 0.5f, -0.5f, 0.1f}, {0.0f, 0.0f, 1.0f, 1.0f}, {1.0f, 0.0f} },
  { { 0.5f, -0.5f, 0.1f}, {1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 0.0f} },
  { { 0.5f,  0.3f, 0.1f}, {1.0f, 1.0f, 0.0f, 1.0f}, {1.0f, 1.0f} },
  { {-0.3f,  0.3f, 0.1f}, {1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 1.0f} },

  { {-1.0f,-1.0f, 0.5f}, {1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 0.0f} },
  { { 1.0f,-1.0f, 0.5f}, {1.0f, 1.0f, 1.0f, 1.0f}, {0.0f, 0.0f} },
  { { 1.0f, 1.0f, 0.5f}, {1.0f, 1.0f, 1.0f, 1.0f}, {0.0f, 1.0f} },
  { {-1.0f, 1.0f, 0.5f}, {1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f} },
};

/// CfbNXf[^.
const GLuint indices[] = {
  0, 1, 2, 2, 3, 0,
  4, 5, 6, 7, 8, 9,
  10, 11, 12, 12, 13, 10,
};

/**
* `f[^.
*/
struct RenderingPart
{
  GLvoid* offset; ///< `JnCfbNX̃oCgItZbg.
  GLsizei size; ///< `悷CfbNX.
};

/**
* RenderingPart쐬.
*
* @param offset `JnCfbNX̃ItZbg(CfbNXP).
* @param size `悷CfbNX.
*
* @return 쐬`IuWFNg.
*/
constexpr RenderingPart MakeRenderingPart(GLsizei offset, GLsizei size) {
  return { reinterpret_cast<GLvoid*>(offset * sizeof(GLuint)), size };
}

/**
* `f[^Xg.
*/
static const RenderingPart renderingParts[] = {
  MakeRenderingPart(0, 12),
  MakeRenderingPart(12, 6),
};

/**
* Vertex Buffer Object쐬.
*
* @param size _f[^̃TCY.
* @param data _f[^ւ̃|C^.
*
* @return 쐬VBO.
*/
GLuint CreateVBO(GLsizeiptr size, const GLvoid* data)
{
  GLuint vbo = 0;
  glGenBuffers(1, &vbo);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
  glBindBuffer(GL_ARRAY_BUFFER, 0);
  return vbo;
}

/**
* Index Buffer Object쐬.
*
* @param size CfbNXf[^̃TCY.
* @param data CfbNXf[^ւ̃|C^.
*
* @return 쐬IBO.
*/
GLuint CreateIBO(GLsizeiptr size, const GLvoid* data)
{
  GLuint ibo = 0;
  glGenBuffers(1, &ibo);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  return ibo;
}

/**
* _Agr[gݒ肷.
*
* @param index _Agr[g̃CfbNX.
* @param cls   _f[^^.
* @param mbr   _Agr[gɐݒ肷cls̃oϐ.
*/
#define SetVertexAttribPointer(index, cls, mbr) SetVertexAttribPointerI( \
  index, \
  sizeof(cls::mbr) / sizeof(float), \
  sizeof(cls), \
  reinterpret_cast<GLvoid*>(offsetof(cls, mbr)))

void SetVertexAttribPointerI(GLuint index, GLint size, GLsizei stride, const GLvoid* pointer)
{
  glEnableVertexAttribArray(index);
  glVertexAttribPointer(index, size, GL_FLOAT, GL_FALSE, stride, pointer);
}

/**
* Vertex Array Object쐬.
*
* @param vbo VAOɊ֘AtVBO.
* @param ibo VAOɊ֘AtIBO.
*
* @return 쐬VAO.
*/
GLuint CreateVAO(GLuint vbo, GLuint ibo)
{
  GLuint vao = 0;
  glGenVertexArrays(1, &vao);
  glBindVertexArray(vao);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  SetVertexAttribPointer(0, Vertex, position);
  SetVertexAttribPointer(1, Vertex, color);
  SetVertexAttribPointer(2, Vertex, texCoord);
  glBindVertexArray(0);
  glDeleteBuffers(1, &vbo);
  glDeleteBuffers(1, &ibo);
  return vao;
}

/// Gg[|Cg.
int main()
{
  GLFWEW::Window& window = GLFWEW::Window::Instance();
  if (!window.Init(800, 600, "OpenGL Tutorial")) {
    return 1;
  }

  const GLuint vbo = CreateVBO(sizeof(vertices), vertices);
  const GLuint ibo = CreateIBO(sizeof(indices), indices);
  const GLuint vao = CreateVAO(vbo, ibo);
  const GLuint shaderProgram = Shader::CreateProgramFromFile("Res/Tutorial.vert", "Res/Tutorial.frag");
  if (!vbo || !ibo || !vao || !shaderProgram) {
    return 1;
  }

  // eNX`f[^.
  TexturePtr tex = Texture::LoadFromFile("Res/sample.bmp");
  if (!tex) {
    return 1;
  }

  const OffscreenBufferPtr offscreen = OffscreenBuffer::Create(800, 600);

  glEnable(GL_DEPTH_TEST);

  // C[v.
  while (!window.ShouldClose()) {
    glBindFramebuffer(GL_FRAMEBUFFER, offscreen->GetFramebuffer());
    glClearColor(0.1f, 0.3f, 0.5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // _]ړ.
    static float degree = 0.0f;
    degree += 0.1f;
    if (degree >= 360.0f) { degree -= 360.0f; }
    const glm::vec3 viewPos = glm::rotate(glm::mat4(), glm::radians(degree), glm::vec3(0, 1, 0)) * glm::vec4(2, 3, 3, 1);

    glUseProgram(shaderProgram);
    const GLint matMVPLoc = glGetUniformLocation(shaderProgram, "matMVP");
    if (matMVPLoc >= 0) {
      const glm::mat4x4 matProj =
        glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);
      const glm::mat4x4 matView =
        glm::lookAt(viewPos, glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
      const glm::mat4x4 matMVP = matProj * matView;
      glUniformMatrix4fv(matMVPLoc, 1, GL_FALSE, &matMVP[0][0]);
    }
    const GLint colorSamplerLoc = glGetUniformLocation(shaderProgram, "colorSampler");
    if (colorSamplerLoc >= 0) {
      glUniform1i(colorSamplerLoc, 0);
      glActiveTexture(GL_TEXTURE0);
      glBindTexture(GL_TEXTURE_2D, tex->Id());
    }
    glBindVertexArray(vao);
    glDrawElements(GL_TRIANGLES, renderingParts[0].size, GL_UNSIGNED_INT, renderingParts[0].offset);

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glClearColor(0.5f, 0.3f, 0.1f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    if (colorSamplerLoc >= 0) {
      glBindTexture(GL_TEXTURE_2D, offscreen->GetTexutre());
    }
    if (matMVPLoc >= 0) {
      glUniformMatrix4fv(matMVPLoc, 1, GL_FALSE, &glm::mat4()[0][0]);
    }
    glDrawElements(GL_TRIANGLES, renderingParts[1].size, GL_UNSIGNED_INT, renderingParts[1].offset);

    window.SwapBuffers();
  }

  glDeleteProgram(shaderProgram);
  glDeleteVertexArrays(1, &vao);

  return 0;
}<|endoftext|>


<commit_before>#include "unittest/catch.h"

#include <fcntl.h>
#include <iostream>
#include <map>
#include <string>
#include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
#include <vector>

#include <boost/filesystem.hpp>
#include <gsl/string_span>

#include "base-utils/configFileWriter.h"
#include "log/assertions.h"
#include "base-utils/executionContent.h"
#include "base-utils/tmpFile.h"

using std::cout;
using std::endl;
using std::map;
using std::string;
using std::stringstream;
using std::vector;

using boost::filesystem::current_path;
using boost::system::error_code;
using boost::system::errc::success;
using gsl::czstring;
using gsl::zstring;

using execHelper::test::baseUtils::ConfigFileWriter;
using execHelper::test::baseUtils::ExecutionContent;
using execHelper::test::baseUtils::TmpFile;
using execHelper::test::baseUtils::YamlWriter;

namespace {
    using Command = string;
    using Commands = vector<string>;
    using CommandLineRaw = vector<zstring<>>;
    using CommandLine = vector<string>;
    using ReturnCode = int;

    using ConfigFile = TmpFile;
    using OutputFile = ExecutionContent;
    using OutputFiles = map<Command, OutputFile>;

    static czstring<> EXEC_HELPER_BINARY="exec-helper";
    static czstring<> COMMAND_KEY = "commands";
    static czstring<> COMMAND_LINE_COMMAND_KEY = "command-line-command";
    static czstring<> COMMAND_LINE_COMMAND_LINE_KEY = "command-line";

    const ReturnCode SUCCESS = EXIT_SUCCESS;

    void childProcessExecute(const CommandLineRaw& line, const string& workingDir) noexcept {
        ReturnCode returnCode;

        error_code error;
        current_path(workingDir, error);
        expectsMessage(error == success, "Either works or fix the test");

        // Suppress output
        int fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
        expectsMessage(fd >= 0, "Either works or fix the test");
        returnCode = dup2(fd, 1);
        expectsMessage(returnCode >= 0, "Either works or fix the test");
        close(fd);

        if ((returnCode = execvp(line[0], &(line[0]))) == -1) {
            cout << "Could not execvp command: " << strerror(errno) << " (" << errno << ")" << endl;
        }
        // execvp replaces the process: the return code for valid execvp calls should be obtained from the parent
        expectsMessage(false, "Either works or fix the test");
    }

    ReturnCode waitForChild(pid_t pid) noexcept {
        pid_t ret;
        ReturnCode status;
        while ((ret = waitpid(pid, &status, 0)) == -1) {
            if (errno != EINTR) {
                break;
            }
        }
        expectsMessage(ret != -1, "Either works or fix the test");
        if(status == 0) {
            return 0;
        }
        if (WIFEXITED(status) && WEXITSTATUS(status)) {
            return WEXITSTATUS(status);
        }
        return status;
    }

    int execute(const CommandLineRaw& commandLine, const string& workingDir = ".") {
        pid_t pid = fork();
        REQUIRE(pid != -1);
        if(pid == 0) {
            childProcessExecute(commandLine, workingDir);
        }
        return waitForChild(pid);
    }

    int execute(const CommandLine& commandLine, const string& workingDir = ".") {
        CommandLineRaw rawLine;
        for(const auto& arg : commandLine) {
            rawLine.push_back(strdup(arg.c_str()));
        }
        rawLine.push_back(nullptr);
        return execute(rawLine, workingDir);
    }

} // namespace

namespace execHelper {
namespace integration {
    /**
     * Implements @ref execute-multiple-statements-predefined-order
     */
    SCENARIO("Execution order of a command consisting of one predefined statement", "[execute-multiple-statements][execute-multiple-statements-predefined-order][scenario-execute-multiple-statements-predefined-order-single]") {
        GIVEN("A valid configuration with multiple commands consisting of one predefined, valid, successful statement") {
            const Commands commands({"command1", "command2", "command3", "command4"});
            YamlWriter yaml;
            OutputFiles output;

            for(const auto& command : commands) {
                output.emplace(command, OutputFile());

                yaml[COMMAND_KEY][command] = "Execute the command";
                yaml[command] = COMMAND_LINE_COMMAND_KEY;
                yaml[COMMAND_LINE_COMMAND_KEY][command][COMMAND_LINE_COMMAND_LINE_KEY].push_back("sed");
                yaml[COMMAND_LINE_COMMAND_KEY][command][COMMAND_LINE_COMMAND_LINE_KEY].push_back("-i");
                yaml[COMMAND_LINE_COMMAND_KEY][command][COMMAND_LINE_COMMAND_LINE_KEY].push_back("'$ a\\" + output.at(command).getIterationContent() + "'");
                yaml[COMMAND_LINE_COMMAND_KEY][command][COMMAND_LINE_COMMAND_LINE_KEY].push_back(output.at(command).getPath());

            }

            ConfigFileWriter config;
            config.write(yaml);

            WHEN("we call each of these commands separately") {
                for(const auto& command : commands) {
                    const ReturnCode returnCode = execute({"exec-helper", command, "--settings-file", config.getFilename()}, config.getDirectory());

                    THEN("the call should succeed") {
                        REQUIRE(returnCode == SUCCESS);
                    }

                    THEN("the associated predefined statement should be called exactly once") {
                        REQUIRE(output.at(command).getNumberOfExecutions() == 1U);
                    }

                    THEN("no other predefined statements should have been called") {
                        for(const auto& otherCommand : commands) {
                            if(command != otherCommand) {
                                REQUIRE(output.at(otherCommand).getNumberOfExecutions() == 0U);
                            }
                        }
                    }
                }
            }
        }
    }
} // namespace integration
} // namespace execHelper
<commit_msg>New: Test: Implemented execute-multiple-statements-predefined-order-multiple scenario<commit_after>#include "unittest/catch.h"

#include <fcntl.h>
#include <iostream>
#include <map>
#include <string>
#include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
#include <vector>

#include <boost/filesystem.hpp>
#include <gsl/string_span>

#include "base-utils/configFileWriter.h"
#include "log/assertions.h"
#include "base-utils/executionContent.h"
#include "base-utils/tmpFile.h"

using std::cout;
using std::endl;
using std::map;
using std::string;
using std::stringstream;
using std::to_string;
using std::vector;

using boost::filesystem::current_path;
using boost::system::error_code;
using boost::system::errc::success;
using gsl::czstring;
using gsl::zstring;

using execHelper::test::baseUtils::ConfigFileWriter;
using execHelper::test::baseUtils::ExecutionContent;
using execHelper::test::baseUtils::TmpFile;
using execHelper::test::baseUtils::YamlWriter;

namespace {
    using Command = string;
    using Commands = vector<string>;
    using CommandLineRaw = vector<zstring<>>;
    using CommandLine = vector<string>;
    using ReturnCode = int;

    using ConfigFile = TmpFile;
    using OutputFile = ExecutionContent;
    using OutputFiles = map<Command, OutputFile>;

    static czstring<> EXEC_HELPER_BINARY="exec-helper";
    static czstring<> COMMAND_KEY = "commands";
    static czstring<> COMMAND_LINE_COMMAND_KEY = "command-line-command";
    static czstring<> COMMAND_LINE_COMMAND_LINE_KEY = "command-line";

    const ReturnCode SUCCESS = EXIT_SUCCESS;

    void childProcessExecute(const CommandLineRaw& line, const string& workingDir) noexcept {
        ReturnCode returnCode;

        error_code error;
        current_path(workingDir, error);
        expectsMessage(error == success, "Either works or fix the test");

        // Suppress output
        int fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
        expectsMessage(fd >= 0, "Either works or fix the test");
        returnCode = dup2(fd, 1);
        expectsMessage(returnCode >= 0, "Either works or fix the test");
        close(fd);

        if ((returnCode = execvp(line[0], &(line[0]))) == -1) {
            cout << "Could not execvp command: " << strerror(errno) << " (" << errno << ")" << endl;
        }
        // execvp replaces the process: the return code for valid execvp calls should be obtained from the parent
        expectsMessage(false, "Either works or fix the test");
    }

    ReturnCode waitForChild(pid_t pid) noexcept {
        pid_t ret;
        ReturnCode status;
        while ((ret = waitpid(pid, &status, 0)) == -1) {
            if (errno != EINTR) {
                break;
            }
        }
        expectsMessage(ret != -1, "Either works or fix the test");
        if(status == 0) {
            return 0;
        }
        if (WIFEXITED(status) && WEXITSTATUS(status)) {
            return WEXITSTATUS(status);
        }
        return status;
    }

    int execute(const CommandLineRaw& commandLine, const string& workingDir = ".") {
        pid_t pid = fork();
        REQUIRE(pid != -1);
        if(pid == 0) {
            childProcessExecute(commandLine, workingDir);
        }
        return waitForChild(pid);
    }

    int execute(const CommandLine& commandLine, const string& workingDir = ".") {
        CommandLineRaw rawLine;
        for(const auto& arg : commandLine) {
            rawLine.push_back(strdup(arg.c_str()));
        }
        rawLine.push_back(nullptr);
        return execute(rawLine, workingDir);
    }

} // namespace

namespace execHelper {
namespace integration {
    /**
     * Implements @ref execute-multiple-statements-predefined-order
     */
    SCENARIO("Execution order of a command consisting of one predefined statement", "[execute-multiple-statements][execute-multiple-statements-predefined-order][scenario-execute-multiple-statements-predefined-order-single]") {
        GIVEN("A valid configuration with multiple commands consisting of one predefined, valid, successful statement") {
            const Commands commands({"command1", "command2", "command3", "command4"});
            YamlWriter yaml;
            OutputFiles output;

            for(const auto& command : commands) {
                output.emplace(command, OutputFile());

                yaml[COMMAND_KEY][command] = "Execute the command";
                yaml[command] = COMMAND_LINE_COMMAND_KEY;
                yaml[COMMAND_LINE_COMMAND_KEY][command][COMMAND_LINE_COMMAND_LINE_KEY].push_back("sed");
                yaml[COMMAND_LINE_COMMAND_KEY][command][COMMAND_LINE_COMMAND_LINE_KEY].push_back("-i");
                yaml[COMMAND_LINE_COMMAND_KEY][command][COMMAND_LINE_COMMAND_LINE_KEY].push_back("'$ a\\" + output.at(command).getIterationContent() + "'");
                yaml[COMMAND_LINE_COMMAND_KEY][command][COMMAND_LINE_COMMAND_LINE_KEY].push_back(output.at(command).getPath());

            }

            ConfigFileWriter config;
            config.write(yaml);

            WHEN("we call each of these commands separately") {
                for(const auto& command : commands) {
                    const ReturnCode returnCode = execute({EXEC_HELPER_BINARY, command, "--settings-file", config.getFilename()}, config.getDirectory());

                    THEN("the call should succeed") {
                        REQUIRE(returnCode == SUCCESS);
                    }

                    THEN("the associated predefined statement should be called exactly once") {
                        REQUIRE(output.at(command).getNumberOfExecutions() == 1U);
                    }

                    THEN("no other predefined statements should have been called") {
                        for(const auto& otherCommand : commands) {
                            if(command != otherCommand) {
                                REQUIRE(output.at(otherCommand).getNumberOfExecutions() == 0U);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * Implements @ref scenario-execute-multiple-statements-predefined-order-multiple
     */
    SCENARIO("Scenario: Execution order of commands consisting of multiple predefined statements", "[execute-multiple-statements][execute-multiple-statements-predefined-order][scenario-execute-multiple-statements-predefined-order-multiple]") {
        GIVEN("A valid configuration with multiple commands consisting of multiple, predefined, valid, successful statements") {
            const Commands commands({"command1", "command2", "command3", "command4"});
            YamlWriter yaml;
            OutputFiles output;

            const unsigned int NB_OF_SUBCOMMANDS = 3U;

            for(const auto& command : commands) {
                output.emplace(command, OutputFile());

                Commands subcommands;
                for(unsigned int i = 0; i < NB_OF_SUBCOMMANDS; ++i) {
                    string subcommand = command;
                    subcommand.append("-subcommand").append(to_string(i));
                    subcommands.emplace_back(subcommand);
                }

                yaml[COMMAND_KEY][command] = "Execute the command";
                yaml[command] = subcommands;

                for(const auto& subcommand : subcommands) {
                    yaml[subcommand] = COMMAND_LINE_COMMAND_KEY;
                    yaml[COMMAND_LINE_COMMAND_KEY][subcommand][COMMAND_LINE_COMMAND_LINE_KEY].push_back("sed");
                    yaml[COMMAND_LINE_COMMAND_KEY][subcommand][COMMAND_LINE_COMMAND_LINE_KEY].push_back("-i");
                    yaml[COMMAND_LINE_COMMAND_KEY][subcommand][COMMAND_LINE_COMMAND_LINE_KEY].push_back("'$ a\\" + output.at(command).getIterationContent() + "'");
                    yaml[COMMAND_LINE_COMMAND_KEY][subcommand][COMMAND_LINE_COMMAND_LINE_KEY].push_back(output.at(command).getPath());
                }
            }

            ConfigFileWriter config;
            config.write(yaml);

            WHEN("we call each of these commands separately") {
                for(const auto& command : commands) {
                    const ReturnCode returnCode = execute({EXEC_HELPER_BINARY, command, "--settings-file", config.getFilename()}, config.getDirectory());

                    THEN("the call should succeed") {
                        REQUIRE(returnCode == SUCCESS);
                    }

                    THEN("the associated predefined statements should be called the expected number of times in the right order") {
                        REQUIRE(output.at(command).getNumberOfExecutions() == NB_OF_SUBCOMMANDS);
                    }

                    THEN("no other predefined statements should have been called") {
                        for(const auto& otherCommand : commands) {
                            if(command != otherCommand) {
                                REQUIRE(output.at(otherCommand).getNumberOfExecutions() == 0U);
                            }
                        }
                    }
                }
            }
        }
    }
} // namespace integration
} // namespace execHelper
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: templdlg.hxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: obo $ $Date: 2005-04-13 10:37:35 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _SVTOOLS_TEMPLDLG_HXX
#define _SVTOOLS_TEMPLDLG_HXX

#ifndef INCLUDED_SVTDLLAPI_H
#include "svtools/svtdllapi.h"
#endif

#ifndef _SV_BUTTON_HXX
#include <vcl/button.hxx>
#endif
#ifndef _SV_DIALOG_HXX
#include <vcl/dialog.hxx>
#endif
#ifndef _SV_FIXED_HXX
#include <vcl/fixed.hxx>
#endif

struct SvtTmplDlg_Impl;

// class SvtDocumentTemplateDialog ---------------------------------------

class SvtTemplateWindow;

class SVT_DLLPUBLIC SvtDocumentTemplateDialog : public ModalDialog
{
private:
    FixedLine           aLine;
    PushButton          aManageBtn;
    PushButton          aEditBtn;
    OKButton            aOKBtn;
    CancelButton        aCancelBtn;
    HelpButton          aHelpBtn;

    SvtTmplDlg_Impl*    pImpl;

    DECL_DLLPRIVATE_LINK(           SelectHdl_Impl, SvtTemplateWindow* );
    DECL_DLLPRIVATE_LINK(           DoubleClickHdl_Impl, SvtTemplateWindow* );
    DECL_DLLPRIVATE_LINK(           NewFolderHdl_Impl, SvtTemplateWindow* );
    DECL_DLLPRIVATE_LINK(           SendFocusHdl_Impl, SvtTemplateWindow* );
    DECL_DLLPRIVATE_LINK(           OKHdl_Impl, PushButton* );
    DECL_DLLPRIVATE_LINK(           OrganizerHdl_Impl, PushButton* );
    DECL_DLLPRIVATE_LINK(           UpdateHdl_Impl, Timer* );

public:
    SvtDocumentTemplateDialog( Window* pParent );

    /** ctor for calling the dialog for selection only, not for opening a document

If you use this ctor, the dialog will behave differently in the following areas:

The Edit button will be hidden.

Upon pressing em>Open, the selected file will not be opened. Instead, it's
                URL is available (see <method>GetSelectedFileURL</method>).

    */
    struct SelectOnly { };
    SvtDocumentTemplateDialog( Window* _pParent, SelectOnly );

    ~SvtDocumentTemplateDialog();

    sal_Bool    IsFileSelected( ) const;
    String      GetSelectedFileURL( ) const;

    void        SelectTemplateFolder();

private:
    SVT_DLLPRIVATE void InitImpl( );
};

#endif // _SVTOOLS_TEMPLDLG_HXX

<commit_msg>INTEGRATION: CWS ooo19126 (1.12.140); FILE MERGED 2005/09/05 14:51:13 rt 1.12.140.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: templdlg.hxx,v $
 *
 *  $Revision: 1.13 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 14:07:40 $
 *
 *  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 _SVTOOLS_TEMPLDLG_HXX
#define _SVTOOLS_TEMPLDLG_HXX

#ifndef INCLUDED_SVTDLLAPI_H
#include "svtools/svtdllapi.h"
#endif

#ifndef _SV_BUTTON_HXX
#include <vcl/button.hxx>
#endif
#ifndef _SV_DIALOG_HXX
#include <vcl/dialog.hxx>
#endif
#ifndef _SV_FIXED_HXX
#include <vcl/fixed.hxx>
#endif

struct SvtTmplDlg_Impl;

// class SvtDocumentTemplateDialog ---------------------------------------

class SvtTemplateWindow;

class SVT_DLLPUBLIC SvtDocumentTemplateDialog : public ModalDialog
{
private:
    FixedLine           aLine;
    PushButton          aManageBtn;
    PushButton          aEditBtn;
    OKButton            aOKBtn;
    CancelButton        aCancelBtn;
    HelpButton          aHelpBtn;

    SvtTmplDlg_Impl*    pImpl;

    DECL_DLLPRIVATE_LINK(           SelectHdl_Impl, SvtTemplateWindow* );
    DECL_DLLPRIVATE_LINK(           DoubleClickHdl_Impl, SvtTemplateWindow* );
    DECL_DLLPRIVATE_LINK(           NewFolderHdl_Impl, SvtTemplateWindow* );
    DECL_DLLPRIVATE_LINK(           SendFocusHdl_Impl, SvtTemplateWindow* );
    DECL_DLLPRIVATE_LINK(           OKHdl_Impl, PushButton* );
    DECL_DLLPRIVATE_LINK(           OrganizerHdl_Impl, PushButton* );
    DECL_DLLPRIVATE_LINK(           UpdateHdl_Impl, Timer* );

public:
    SvtDocumentTemplateDialog( Window* pParent );

    /** ctor for calling the dialog for selection only, not for opening a document

If you use this ctor, the dialog will behave differently in the following areas:

The Edit button will be hidden.

Upon pressing em>Open, the selected file will not be opened. Instead, it's
                URL is available (see <method>GetSelectedFileURL</method>).

    */
    struct SelectOnly { };
    SvtDocumentTemplateDialog( Window* _pParent, SelectOnly );

    ~SvtDocumentTemplateDialog();

    sal_Bool    IsFileSelected( ) const;
    String      GetSelectedFileURL( ) const;

    void        SelectTemplateFolder();

private:
    SVT_DLLPRIVATE void InitImpl( );
};

#endif // _SVTOOLS_TEMPLDLG_HXX

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: testtool.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 20:32:37 $
 *
 *  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 SVTOOLS_TESTTOOL_HXX
#define SVTOOLS_TESTTOOL_HXX

#ifndef _SOLAR_H
#include <tools/solar.h>
#endif
#ifndef _LINK_HXX //autogen
#include <tools/link.hxx>
#endif
#ifndef _STRING_HXX
#include <tools/string.hxx>
#endif

class Application;
class SvStream;

class StatementFlow;
class CommunicationManager;
class CommunicationLink;
#if OSL_DEBUG_LEVEL > 1
class EditWindow;
#endif
class ImplRC;

class RemoteControl
{
    friend class StatementFlow;

    BOOL         m_bIdleInserted;
#if OSL_DEBUG_LEVEL > 1
    EditWindow *m_pDbgWin;
#endif
    ImplRC* pImplRC;

public:
    RemoteControl();
    ~RemoteControl();
    BOOL QueCommands( ULONG nServiceId, SvStream *pIn );
    SvStream* GetReturnStream();

    DECL_LINK( IdleHdl,   Application* );
    DECL_LINK( CommandHdl, Application* );

    DECL_LINK( QueCommandsEvent, CommunicationLink* );
    ULONG nStoredServiceId;
    SvStream *pStoredStream;

    void ExecuteURL( String &aURL );

protected:
    CommunicationManager *pServiceMgr;
    SvStream *pRetStream;
};

#endif // SVTOOLS_TESTTOOL_HXX
<commit_msg>INTEGRATION: CWS changefileheader (1.4.546); FILE MERGED 2008/04/01 15:44:25 thb 1.4.546.2: #i85898# Stripping all external header guards 2008/03/31 13:00:57 rt 1.4.546.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: testtool.hxx,v $
 * $Revision: 1.5 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#ifndef SVTOOLS_TESTTOOL_HXX
#define SVTOOLS_TESTTOOL_HXX

#include <tools/solar.h>
#include <tools/link.hxx>
#include <tools/string.hxx>

class Application;
class SvStream;

class StatementFlow;
class CommunicationManager;
class CommunicationLink;
#if OSL_DEBUG_LEVEL > 1
class EditWindow;
#endif
class ImplRC;

class RemoteControl
{
    friend class StatementFlow;

    BOOL         m_bIdleInserted;
#if OSL_DEBUG_LEVEL > 1
    EditWindow *m_pDbgWin;
#endif
    ImplRC* pImplRC;

public:
    RemoteControl();
    ~RemoteControl();
    BOOL QueCommands( ULONG nServiceId, SvStream *pIn );
    SvStream* GetReturnStream();

    DECL_LINK( IdleHdl,   Application* );
    DECL_LINK( CommandHdl, Application* );

    DECL_LINK( QueCommandsEvent, CommunicationLink* );
    ULONG nStoredServiceId;
    SvStream *pStoredStream;

    void ExecuteURL( String &aURL );

protected:
    CommunicationManager *pServiceMgr;
    SvStream *pRetStream;
};

#endif // SVTOOLS_TESTTOOL_HXX
<|endoftext|>


<commit_before>//===--- ModuleManager.cpp - Module Manager ---------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the ModuleManager class, which manages a set of loaded
//  modules for the ASTReader.
//
//===----------------------------------------------------------------------===//
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/ModuleMap.h"
#include "clang/Serialization/GlobalModuleIndex.h"
#include "clang/Serialization/ModuleManager.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"

#ifndef NDEBUG
#include "llvm/Support/GraphWriter.h"
#endif

using namespace clang;
using namespace serialization;

ModuleFile *ModuleManager::lookup(StringRef Name) {
  const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
                                           /*cacheFailure=*/false);
  if (Entry)
    return lookup(Entry);

  return nullptr;
}

ModuleFile *ModuleManager::lookup(const FileEntry *File) {
  llvm::DenseMap<const FileEntry *, ModuleFile *>::iterator Known
    = Modules.find(File);
  if (Known == Modules.end())
    return nullptr;

  return Known->second;
}

llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) {
  const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
                                           /*cacheFailure=*/false);
  return InMemoryBuffers[Entry];
}

ModuleManager::AddModuleResult
ModuleManager::addModule(StringRef FileName, ModuleKind Type,
                         SourceLocation ImportLoc, ModuleFile *ImportedBy,
                         unsigned Generation,
                         off_t ExpectedSize, time_t ExpectedModTime,
                         ModuleFile *&Module,
                         std::string &ErrorStr) {
  Module = nullptr;

  // Look for the file entry. This only fails if the expected size or
  // modification time differ.
  const FileEntry *Entry;
  if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, Entry)) {
    ErrorStr = "module file out of date";
    return OutOfDate;
  }

  if (!Entry && FileName != "-") {
    ErrorStr = "module file not found";
    return Missing;
  }

  // Check whether we already loaded this module, before
  ModuleFile *&ModuleEntry = Modules[Entry];
  bool NewModule = false;
  if (!ModuleEntry) {
    // Allocate a new module.
    ModuleFile *New = new ModuleFile(Type, Generation);
    New->Index = Chain.size();
    New->FileName = FileName.str();
    New->File = Entry;
    New->ImportLoc = ImportLoc;
    Chain.push_back(New);
    NewModule = true;
    ModuleEntry = New;

    New->InputFilesValidationTimestamp = 0;
    if (New->Kind == MK_Module) {
      std::string TimestampFilename = New->getTimestampFilename();
      vfs::Status Status;
      // A cached stat value would be fine as well.
      if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status))
        New->InputFilesValidationTimestamp =
            Status.getLastModificationTime().toEpochTime();
    }

    // Load the contents of the module
    if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) {
      // The buffer was already provided for us.
      assert(Buffer && "Passed null buffer");
      New->Buffer.reset(Buffer);
    } else {
      // Open the AST file.
      llvm::error_code ec;
      if (FileName == "-") {
        ec = llvm::MemoryBuffer::getSTDIN(New->Buffer);
        if (ec)
          ErrorStr = ec.message();
      } else
        New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr));

      if (!New->Buffer)
        return Missing;
    }

    // Initialize the stream
    New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(),
                         (const unsigned char *)New->Buffer->getBufferEnd());
  }

  if (ImportedBy) {
    ModuleEntry->ImportedBy.insert(ImportedBy);
    ImportedBy->Imports.insert(ModuleEntry);
  } else {
    if (!ModuleEntry->DirectlyImported)
      ModuleEntry->ImportLoc = ImportLoc;

    ModuleEntry->DirectlyImported = true;
  }

  Module = ModuleEntry;
  return NewModule? NewlyLoaded : AlreadyLoaded;
}

void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last,
                                  ModuleMap *modMap) {
  if (first == last)
    return;

  // The first file entry is about to be rebuilt (or there was an error), so
  // there should be no references to it. Remove it from the cache to close it,
  // as Windows doesn't seem to allow renaming over an open file.
  FileMgr.invalidateCache((*first)->File);

  // Collect the set of module file pointers that we'll be removing.
  llvm::SmallPtrSet<ModuleFile *, 4> victimSet(first, last);

  // Remove any references to the now-destroyed modules.
  for (unsigned i = 0, n = Chain.size(); i != n; ++i) {
    Chain[i]->ImportedBy.remove_if([&](ModuleFile *MF) {
      return victimSet.count(MF);
    });
  }

  // Delete the modules and erase them from the various structures.
  for (ModuleIterator victim = first; victim != last; ++victim) {
    Modules.erase((*victim)->File);

    if (modMap) {
      StringRef ModuleName = (*victim)->ModuleName;
      if (Module *mod = modMap->findModule(ModuleName)) {
        mod->setASTFile(nullptr);
      }
    }
    delete *victim;
  }

  // Remove the modules from the chain.
  Chain.erase(first, last);
}

void ModuleManager::addInMemoryBuffer(StringRef FileName,
                                      llvm::MemoryBuffer *Buffer) {

  const FileEntry *Entry = FileMgr.getVirtualFile(FileName,
                                                  Buffer->getBufferSize(), 0);
  InMemoryBuffers[Entry] = Buffer;
}

ModuleManager::VisitState *ModuleManager::allocateVisitState() {
  // Fast path: if we have a cached state, use it.
  if (FirstVisitState) {
    VisitState *Result = FirstVisitState;
    FirstVisitState = FirstVisitState->NextState;
    Result->NextState = nullptr;
    return Result;
  }

  // Allocate and return a new state.
  return new VisitState(size());
}

void ModuleManager::returnVisitState(VisitState *State) {
  assert(State->NextState == nullptr && "Visited state is in list?");
  State->NextState = FirstVisitState;
  FirstVisitState = State;
}

void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) {
  GlobalIndex = Index;
  if (!GlobalIndex) {
    ModulesInCommonWithGlobalIndex.clear();
    return;
  }

  // Notify the global module index about all of the modules we've already
  // loaded.
  for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
    if (!GlobalIndex->loadedModuleFile(Chain[I])) {
      ModulesInCommonWithGlobalIndex.push_back(Chain[I]);
    }
  }
}

void ModuleManager::moduleFileAccepted(ModuleFile *MF) {
  if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF))
    return;

  ModulesInCommonWithGlobalIndex.push_back(MF);
}

ModuleManager::ModuleManager(FileManager &FileMgr)
  : FileMgr(FileMgr), GlobalIndex(), FirstVisitState(nullptr) {}

ModuleManager::~ModuleManager() {
  for (unsigned i = 0, e = Chain.size(); i != e; ++i)
    delete Chain[e - i - 1];
  delete FirstVisitState;
}

void
ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
                     void *UserData,
                     llvm::SmallPtrSet<ModuleFile *, 4> *ModuleFilesHit) {
  // If the visitation order vector is the wrong size, recompute the order.
  if (VisitOrder.size() != Chain.size()) {
    unsigned N = size();
    VisitOrder.clear();
    VisitOrder.reserve(N);

    // Record the number of incoming edges for each module. When we
    // encounter a module with no incoming edges, push it into the queue
    // to seed the queue.
    SmallVector<ModuleFile *, 4> Queue;
    Queue.reserve(N);
    llvm::SmallVector<unsigned, 4> UnusedIncomingEdges;
    UnusedIncomingEdges.reserve(size());
    for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) {
      if (unsigned Size = (*M)->ImportedBy.size())
        UnusedIncomingEdges.push_back(Size);
      else {
        UnusedIncomingEdges.push_back(0);
        Queue.push_back(*M);
      }
    }

    // Traverse the graph, making sure to visit a module before visiting any
    // of its dependencies.
    unsigned QueueStart = 0;
    while (QueueStart < Queue.size()) {
      ModuleFile *CurrentModule = Queue[QueueStart++];
      VisitOrder.push_back(CurrentModule);

      // For any module that this module depends on, push it on the
      // stack (if it hasn't already been marked as visited).
      for (llvm::SetVector<ModuleFile *>::iterator
             M = CurrentModule->Imports.begin(),
             MEnd = CurrentModule->Imports.end();
           M != MEnd; ++M) {
        // Remove our current module as an impediment to visiting the
        // module we depend on. If we were the last unvisited module
        // that depends on this particular module, push it into the
        // queue to be visited.
        unsigned &NumUnusedEdges = UnusedIncomingEdges[(*M)->Index];
        if (NumUnusedEdges && (--NumUnusedEdges == 0))
          Queue.push_back(*M);
      }
    }

    assert(VisitOrder.size() == N && "Visitation order is wrong?");

    delete FirstVisitState;
    FirstVisitState = nullptr;
  }

  VisitState *State = allocateVisitState();
  unsigned VisitNumber = State->NextVisitNumber++;

  // If the caller has provided us with a hit-set that came from the global
  // module index, mark every module file in common with the global module
  // index that is *not* in that set as 'visited'.
  if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
    for (unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
    {
      ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
      if (!ModuleFilesHit->count(M))
        State->VisitNumber[M->Index] = VisitNumber;
    }
  }

  for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
    ModuleFile *CurrentModule = VisitOrder[I];
    // Should we skip this module file?
    if (State->VisitNumber[CurrentModule->Index] == VisitNumber)
      continue;

    // Visit the module.
    assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1);
    State->VisitNumber[CurrentModule->Index] = VisitNumber;
    if (!Visitor(*CurrentModule, UserData))
      continue;

    // The visitor has requested that cut off visitation of any
    // module that the current module depends on. To indicate this
    // behavior, we mark all of the reachable modules as having been visited.
    ModuleFile *NextModule = CurrentModule;
    do {
      // For any module that this module depends on, push it on the
      // stack (if it hasn't already been marked as visited).
      for (llvm::SetVector<ModuleFile *>::iterator
             M = NextModule->Imports.begin(),
             MEnd = NextModule->Imports.end();
           M != MEnd; ++M) {
        if (State->VisitNumber[(*M)->Index] != VisitNumber) {
          State->Stack.push_back(*M);
          State->VisitNumber[(*M)->Index] = VisitNumber;
        }
      }

      if (State->Stack.empty())
        break;

      // Pop the next module off the stack.
      NextModule = State->Stack.pop_back_val();
    } while (true);
  }

  returnVisitState(State);
}

/// \brief Perform a depth-first visit of the current module.
static bool visitDepthFirst(ModuleFile &M,
                            bool (*Visitor)(ModuleFile &M, bool Preorder,
                                            void *UserData),
                            void *UserData,
                            SmallVectorImpl<bool> &Visited) {
  // Preorder visitation
  if (Visitor(M, /*Preorder=*/true, UserData))
    return true;

  // Visit children
  for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(),
                                            IMEnd = M.Imports.end();
       IM != IMEnd; ++IM) {
    if (Visited[(*IM)->Index])
      continue;
    Visited[(*IM)->Index] = true;

    if (visitDepthFirst(**IM, Visitor, UserData, Visited))
      return true;
  }

  // Postorder visitation
  return Visitor(M, /*Preorder=*/false, UserData);
}

void ModuleManager::visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder,
                                                    void *UserData),
                                    void *UserData) {
  SmallVector<bool, 16> Visited(size(), false);
  for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
    if (Visited[Chain[I]->Index])
      continue;
    Visited[Chain[I]->Index] = true;

    if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited))
      return;
  }
}

bool ModuleManager::lookupModuleFile(StringRef FileName,
                                     off_t ExpectedSize,
                                     time_t ExpectedModTime,
                                     const FileEntry *&File) {
  // Open the file immediately to ensure there is no race between stat'ing and
  // opening the file.
  File = FileMgr.getFile(FileName, /*openFile=*/true, /*cacheFailure=*/false);

  if (!File && FileName != "-") {
    return false;
  }

  if ((ExpectedSize && ExpectedSize != File->getSize()) ||
      (ExpectedModTime && ExpectedModTime != File->getModificationTime()))
    // Do not destroy File, as it may be referenced. If we need to rebuild it,
    // it will be destroyed by removeModules.
    return true;

  return false;
}

#ifndef NDEBUG
namespace llvm {
  template<>
  struct GraphTraits<ModuleManager> {
    typedef ModuleFile NodeType;
    typedef llvm::SetVector<ModuleFile *>::const_iterator ChildIteratorType;
    typedef ModuleManager::ModuleConstIterator nodes_iterator;

    static ChildIteratorType child_begin(NodeType *Node) {
      return Node->Imports.begin();
    }

    static ChildIteratorType child_end(NodeType *Node) {
      return Node->Imports.end();
    }

    static nodes_iterator nodes_begin(const ModuleManager &Manager) {
      return Manager.begin();
    }

    static nodes_iterator nodes_end(const ModuleManager &Manager) {
      return Manager.end();
    }
  };

  template<>
  struct DOTGraphTraits<ModuleManager> : public DefaultDOTGraphTraits {
    explicit DOTGraphTraits(bool IsSimple = false)
      : DefaultDOTGraphTraits(IsSimple) { }

    static bool renderGraphFromBottomUp() {
      return true;
    }

    std::string getNodeLabel(ModuleFile *M, const ModuleManager&) {
      return M->ModuleName;
    }
  };
}

void ModuleManager::viewGraph() {
  llvm::ViewGraph(*this, "Modules");
}
#endif
<commit_msg>Invalidate the file system cache entries for files that may rebuild<commit_after>//===--- ModuleManager.cpp - Module Manager ---------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the ModuleManager class, which manages a set of loaded
//  modules for the ASTReader.
//
//===----------------------------------------------------------------------===//
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/ModuleMap.h"
#include "clang/Serialization/GlobalModuleIndex.h"
#include "clang/Serialization/ModuleManager.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"

#ifndef NDEBUG
#include "llvm/Support/GraphWriter.h"
#endif

using namespace clang;
using namespace serialization;

ModuleFile *ModuleManager::lookup(StringRef Name) {
  const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
                                           /*cacheFailure=*/false);
  if (Entry)
    return lookup(Entry);

  return nullptr;
}

ModuleFile *ModuleManager::lookup(const FileEntry *File) {
  llvm::DenseMap<const FileEntry *, ModuleFile *>::iterator Known
    = Modules.find(File);
  if (Known == Modules.end())
    return nullptr;

  return Known->second;
}

llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) {
  const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
                                           /*cacheFailure=*/false);
  return InMemoryBuffers[Entry];
}

ModuleManager::AddModuleResult
ModuleManager::addModule(StringRef FileName, ModuleKind Type,
                         SourceLocation ImportLoc, ModuleFile *ImportedBy,
                         unsigned Generation,
                         off_t ExpectedSize, time_t ExpectedModTime,
                         ModuleFile *&Module,
                         std::string &ErrorStr) {
  Module = nullptr;

  // Look for the file entry. This only fails if the expected size or
  // modification time differ.
  const FileEntry *Entry;
  if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, Entry)) {
    ErrorStr = "module file out of date";
    return OutOfDate;
  }

  if (!Entry && FileName != "-") {
    ErrorStr = "module file not found";
    return Missing;
  }

  // Check whether we already loaded this module, before
  ModuleFile *&ModuleEntry = Modules[Entry];
  bool NewModule = false;
  if (!ModuleEntry) {
    // Allocate a new module.
    ModuleFile *New = new ModuleFile(Type, Generation);
    New->Index = Chain.size();
    New->FileName = FileName.str();
    New->File = Entry;
    New->ImportLoc = ImportLoc;
    Chain.push_back(New);
    NewModule = true;
    ModuleEntry = New;

    New->InputFilesValidationTimestamp = 0;
    if (New->Kind == MK_Module) {
      std::string TimestampFilename = New->getTimestampFilename();
      vfs::Status Status;
      // A cached stat value would be fine as well.
      if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status))
        New->InputFilesValidationTimestamp =
            Status.getLastModificationTime().toEpochTime();
    }

    // Load the contents of the module
    if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) {
      // The buffer was already provided for us.
      assert(Buffer && "Passed null buffer");
      New->Buffer.reset(Buffer);
    } else {
      // Open the AST file.
      llvm::error_code ec;
      if (FileName == "-") {
        ec = llvm::MemoryBuffer::getSTDIN(New->Buffer);
        if (ec)
          ErrorStr = ec.message();
      } else
        New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr));

      if (!New->Buffer)
        return Missing;
    }

    // Initialize the stream
    New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(),
                         (const unsigned char *)New->Buffer->getBufferEnd());
  }

  if (ImportedBy) {
    ModuleEntry->ImportedBy.insert(ImportedBy);
    ImportedBy->Imports.insert(ModuleEntry);
  } else {
    if (!ModuleEntry->DirectlyImported)
      ModuleEntry->ImportLoc = ImportLoc;

    ModuleEntry->DirectlyImported = true;
  }

  Module = ModuleEntry;
  return NewModule? NewlyLoaded : AlreadyLoaded;
}

static void invalidateFileCacheForFileAndImporters(
    ModuleFile *F, FileManager &FileMgr,
    llvm::SmallPtrSetImpl<ModuleFile *> &VictimSet) {
  assert(VictimSet.count(F) && "removeModules() missing ancestor of module "
         "that failed to load");
  FileMgr.invalidateCache(F->File);
  F->File = nullptr;
  for (ModuleFile *Importer : F->ImportedBy)
    invalidateFileCacheForFileAndImporters(Importer, FileMgr, VictimSet);
}

void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last,
                                  ModuleMap *modMap) {
  if (first == last)
    return;

  // Collect the set of module file pointers that we'll be removing.
  llvm::SmallPtrSet<ModuleFile *, 4> victimSet(first, last);

  // The last module file caused the load failure, so it and its ancestors in
  // the module dependency tree will be rebuilt (or there was an error), so
  // there should be no references to them. Remove them from the cache,
  // since rebuilding them will create new files at the old locations.
  invalidateFileCacheForFileAndImporters(*(last-1), FileMgr, victimSet);
  assert((*first)->File == nullptr && "non-dependent module loaded");

  // Remove any references to the now-destroyed modules.
  for (unsigned i = 0, n = Chain.size(); i != n; ++i) {
    Chain[i]->ImportedBy.remove_if([&](ModuleFile *MF) {
      return victimSet.count(MF);
    });
  }

  // Delete the modules and erase them from the various structures.
  for (ModuleIterator victim = first; victim != last; ++victim) {
    Modules.erase((*victim)->File);

    if (modMap) {
      StringRef ModuleName = (*victim)->ModuleName;
      if (Module *mod = modMap->findModule(ModuleName)) {
        mod->setASTFile(nullptr);
      }
    }
    delete *victim;
  }

  // Remove the modules from the chain.
  Chain.erase(first, last);
}

void ModuleManager::addInMemoryBuffer(StringRef FileName,
                                      llvm::MemoryBuffer *Buffer) {

  const FileEntry *Entry = FileMgr.getVirtualFile(FileName,
                                                  Buffer->getBufferSize(), 0);
  InMemoryBuffers[Entry] = Buffer;
}

ModuleManager::VisitState *ModuleManager::allocateVisitState() {
  // Fast path: if we have a cached state, use it.
  if (FirstVisitState) {
    VisitState *Result = FirstVisitState;
    FirstVisitState = FirstVisitState->NextState;
    Result->NextState = nullptr;
    return Result;
  }

  // Allocate and return a new state.
  return new VisitState(size());
}

void ModuleManager::returnVisitState(VisitState *State) {
  assert(State->NextState == nullptr && "Visited state is in list?");
  State->NextState = FirstVisitState;
  FirstVisitState = State;
}

void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) {
  GlobalIndex = Index;
  if (!GlobalIndex) {
    ModulesInCommonWithGlobalIndex.clear();
    return;
  }

  // Notify the global module index about all of the modules we've already
  // loaded.
  for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
    if (!GlobalIndex->loadedModuleFile(Chain[I])) {
      ModulesInCommonWithGlobalIndex.push_back(Chain[I]);
    }
  }
}

void ModuleManager::moduleFileAccepted(ModuleFile *MF) {
  if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF))
    return;

  ModulesInCommonWithGlobalIndex.push_back(MF);
}

ModuleManager::ModuleManager(FileManager &FileMgr)
  : FileMgr(FileMgr), GlobalIndex(), FirstVisitState(nullptr) {}

ModuleManager::~ModuleManager() {
  for (unsigned i = 0, e = Chain.size(); i != e; ++i)
    delete Chain[e - i - 1];
  delete FirstVisitState;
}

void
ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
                     void *UserData,
                     llvm::SmallPtrSet<ModuleFile *, 4> *ModuleFilesHit) {
  // If the visitation order vector is the wrong size, recompute the order.
  if (VisitOrder.size() != Chain.size()) {
    unsigned N = size();
    VisitOrder.clear();
    VisitOrder.reserve(N);

    // Record the number of incoming edges for each module. When we
    // encounter a module with no incoming edges, push it into the queue
    // to seed the queue.
    SmallVector<ModuleFile *, 4> Queue;
    Queue.reserve(N);
    llvm::SmallVector<unsigned, 4> UnusedIncomingEdges;
    UnusedIncomingEdges.reserve(size());
    for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) {
      if (unsigned Size = (*M)->ImportedBy.size())
        UnusedIncomingEdges.push_back(Size);
      else {
        UnusedIncomingEdges.push_back(0);
        Queue.push_back(*M);
      }
    }

    // Traverse the graph, making sure to visit a module before visiting any
    // of its dependencies.
    unsigned QueueStart = 0;
    while (QueueStart < Queue.size()) {
      ModuleFile *CurrentModule = Queue[QueueStart++];
      VisitOrder.push_back(CurrentModule);

      // For any module that this module depends on, push it on the
      // stack (if it hasn't already been marked as visited).
      for (llvm::SetVector<ModuleFile *>::iterator
             M = CurrentModule->Imports.begin(),
             MEnd = CurrentModule->Imports.end();
           M != MEnd; ++M) {
        // Remove our current module as an impediment to visiting the
        // module we depend on. If we were the last unvisited module
        // that depends on this particular module, push it into the
        // queue to be visited.
        unsigned &NumUnusedEdges = UnusedIncomingEdges[(*M)->Index];
        if (NumUnusedEdges && (--NumUnusedEdges == 0))
          Queue.push_back(*M);
      }
    }

    assert(VisitOrder.size() == N && "Visitation order is wrong?");

    delete FirstVisitState;
    FirstVisitState = nullptr;
  }

  VisitState *State = allocateVisitState();
  unsigned VisitNumber = State->NextVisitNumber++;

  // If the caller has provided us with a hit-set that came from the global
  // module index, mark every module file in common with the global module
  // index that is *not* in that set as 'visited'.
  if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
    for (unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
    {
      ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
      if (!ModuleFilesHit->count(M))
        State->VisitNumber[M->Index] = VisitNumber;
    }
  }

  for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
    ModuleFile *CurrentModule = VisitOrder[I];
    // Should we skip this module file?
    if (State->VisitNumber[CurrentModule->Index] == VisitNumber)
      continue;

    // Visit the module.
    assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1);
    State->VisitNumber[CurrentModule->Index] = VisitNumber;
    if (!Visitor(*CurrentModule, UserData))
      continue;

    // The visitor has requested that cut off visitation of any
    // module that the current module depends on. To indicate this
    // behavior, we mark all of the reachable modules as having been visited.
    ModuleFile *NextModule = CurrentModule;
    do {
      // For any module that this module depends on, push it on the
      // stack (if it hasn't already been marked as visited).
      for (llvm::SetVector<ModuleFile *>::iterator
             M = NextModule->Imports.begin(),
             MEnd = NextModule->Imports.end();
           M != MEnd; ++M) {
        if (State->VisitNumber[(*M)->Index] != VisitNumber) {
          State->Stack.push_back(*M);
          State->VisitNumber[(*M)->Index] = VisitNumber;
        }
      }

      if (State->Stack.empty())
        break;

      // Pop the next module off the stack.
      NextModule = State->Stack.pop_back_val();
    } while (true);
  }

  returnVisitState(State);
}

/// \brief Perform a depth-first visit of the current module.
static bool visitDepthFirst(ModuleFile &M,
                            bool (*Visitor)(ModuleFile &M, bool Preorder,
                                            void *UserData),
                            void *UserData,
                            SmallVectorImpl<bool> &Visited) {
  // Preorder visitation
  if (Visitor(M, /*Preorder=*/true, UserData))
    return true;

  // Visit children
  for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(),
                                            IMEnd = M.Imports.end();
       IM != IMEnd; ++IM) {
    if (Visited[(*IM)->Index])
      continue;
    Visited[(*IM)->Index] = true;

    if (visitDepthFirst(**IM, Visitor, UserData, Visited))
      return true;
  }

  // Postorder visitation
  return Visitor(M, /*Preorder=*/false, UserData);
}

void ModuleManager::visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder,
                                                    void *UserData),
                                    void *UserData) {
  SmallVector<bool, 16> Visited(size(), false);
  for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
    if (Visited[Chain[I]->Index])
      continue;
    Visited[Chain[I]->Index] = true;

    if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited))
      return;
  }
}

bool ModuleManager::lookupModuleFile(StringRef FileName,
                                     off_t ExpectedSize,
                                     time_t ExpectedModTime,
                                     const FileEntry *&File) {
  // Open the file immediately to ensure there is no race between stat'ing and
  // opening the file.
  File = FileMgr.getFile(FileName, /*openFile=*/true, /*cacheFailure=*/false);

  if (!File && FileName != "-") {
    return false;
  }

  if ((ExpectedSize && ExpectedSize != File->getSize()) ||
      (ExpectedModTime && ExpectedModTime != File->getModificationTime()))
    // Do not destroy File, as it may be referenced. If we need to rebuild it,
    // it will be destroyed by removeModules.
    return true;

  return false;
}

#ifndef NDEBUG
namespace llvm {
  template<>
  struct GraphTraits<ModuleManager> {
    typedef ModuleFile NodeType;
    typedef llvm::SetVector<ModuleFile *>::const_iterator ChildIteratorType;
    typedef ModuleManager::ModuleConstIterator nodes_iterator;

    static ChildIteratorType child_begin(NodeType *Node) {
      return Node->Imports.begin();
    }

    static ChildIteratorType child_end(NodeType *Node) {
      return Node->Imports.end();
    }

    static nodes_iterator nodes_begin(const ModuleManager &Manager) {
      return Manager.begin();
    }

    static nodes_iterator nodes_end(const ModuleManager &Manager) {
      return Manager.end();
    }
  };

  template<>
  struct DOTGraphTraits<ModuleManager> : public DefaultDOTGraphTraits {
    explicit DOTGraphTraits(bool IsSimple = false)
      : DefaultDOTGraphTraits(IsSimple) { }

    static bool renderGraphFromBottomUp() {
      return true;
    }

    std::string getNodeLabel(ModuleFile *M, const ModuleManager&) {
      return M->ModuleName;
    }
  };
}

void ModuleManager::viewGraph() {
  llvm::ViewGraph(*this, "Modules");
}
#endif
<|endoftext|>


<commit_before>//===-- PIC16MemSelOpt.cpp - PIC16 banksel optimizer  --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the pass which optimizes the emitting of banksel
// instructions before accessing data memory. This currently works within
// a basic block only and keep tracks of the last accessed memory bank.
// If memory access continues to be in the same bank it just makes banksel
// immediate, which is a part of the insn accessing the data memory, from 1
// to zero. The asm printer emits a banksel only if that immediate is 1.
//
// FIXME: this is not implemented yet.  The banksel pass only works on local
// basic blocks.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "pic16-codegen"
#include "PIC16.h"
#include "PIC16ABINames.h"
#include "PIC16InstrInfo.h"
#include "PIC16MCAsmInfo.h"
#include "PIC16TargetMachine.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/GlobalValue.h"
#include "llvm/DerivedTypes.h"

using namespace llvm;

namespace {
  struct MemSelOpt : public MachineFunctionPass {
    static char ID;
    MemSelOpt() : MachineFunctionPass(&ID) {}

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addPreservedID(MachineLoopInfoID);
      AU.addPreservedID(MachineDominatorsID);
      MachineFunctionPass::getAnalysisUsage(AU);
    }

    virtual bool runOnMachineFunction(MachineFunction &MF);

    virtual const char *getPassName() const {
      return "PIC16 Memsel Optimizer";
    }

   bool processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB);
   bool processInstruction(MachineInstr *MI);

  private:
    const TargetInstrInfo *TII; // Machine instruction info.
    MachineBasicBlock *MBB;     // Current basic block
    std::string CurBank;

  };
  char MemSelOpt::ID = 0;
}

FunctionPass *llvm::createPIC16MemSelOptimizerPass() {
  return new MemSelOpt();
}

/// runOnMachineFunction - Loop over all of the basic blocks, transforming FP
/// register references into FP stack references.
///
bool MemSelOpt::runOnMachineFunction(MachineFunction &MF) {
  TII = MF.getTarget().getInstrInfo();
  bool Changed = false;
  for (MachineFunction::iterator I = MF.begin(), E = MF.end();
       I != E; ++I) {
    Changed |= processBasicBlock(MF, *I);
  }

  return Changed;
}

/// processBasicBlock - Loop over all of the instructions in the basic block,
/// transforming FP instructions into their stack form.
///
bool MemSelOpt::processBasicBlock(MachineFunction &MF, MachineBasicBlock &BB) {
  bool Changed = false;
  MBB = &BB;

  // Let us assume that when entering a basic block now bank is selected.
  // Ideally we should look at the predecessors for this information.
  CurBank="";

  for (MachineBasicBlock::iterator I = BB.begin(); I != BB.end(); ++I) {
    Changed |= processInstruction(I);
  }
  return Changed;
}

bool MemSelOpt::processInstruction(MachineInstr *MI) {
  bool Changed = false;

  unsigned NumOperands = MI->getNumOperands();
  if (NumOperands == 0) return false;

  // If this insn is not going to access any memory, return.
  const TargetInstrDesc &TID = TII->get(MI->getOpcode());
  if (!(TID.isBranch() || TID.isCall() || TID.mayLoad() || TID.mayStore()))
    return false;

  // Scan for the memory address operand.
  // FIXME: Should we use standard interfaces like memoperands_iterator,
  // hasMemOperand() etc ?
  int MemOpPos = -1;
  for (unsigned i = 0; i < NumOperands; i++) {
    MachineOperand Op = MI->getOperand(i);
    if (Op.getType() ==  MachineOperand::MO_GlobalAddress ||
        Op.getType() ==  MachineOperand::MO_ExternalSymbol ||
        Op.getType() ==  MachineOperand::MO_MachineBasicBlock) {
      // We found one mem operand. Next one may be BS.
      MemOpPos = i;
      break;
    }
  }

  // If we did not find an insn accessing memory. Continue.
  if (MemOpPos == -1) return Changed;

  // Get the MemOp.
  MachineOperand &Op = MI->getOperand(MemOpPos);

  // If this is a pagesel material, handle it first.
  if (MI->getOpcode() == PIC16::CALL ||
      MI->getOpcode() == PIC16::br_uncond) {
    DebugLoc dl = MI->getDebugLoc();
    BuildMI(*MBB, MI, dl, TII->get(PIC16::pagesel)).
      addOperand(Op);
    return true;
  }

  // Get the section name(NewBank) for MemOp.
  // This assumes that the section names for globals are already set by
  // AsmPrinter->doInitialization.
  std::string NewBank = CurBank;
  if (Op.getType() ==  MachineOperand::MO_GlobalAddress &&
      Op.getGlobal()->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) {
    NewBank = Op.getGlobal()->getSection();
  } else if (Op.getType() ==  MachineOperand::MO_ExternalSymbol) {
    // External Symbol is generated for temp data and arguments. They are
    // in fpdata.<functionname>.# section.
    std::string Sym = Op.getSymbolName();
    NewBank = PAN::getSectionNameForSym(Sym);
  }

  // If the section is shared section, do not emit banksel.
  if (NewBank == PAN::getSharedUDataSectionName())
    return Changed;

  // If the previous and new section names are same, we don't need to
  // emit banksel.
  if (NewBank.compare(CurBank) != 0 ) {
    DebugLoc dl = MI->getDebugLoc();
    BuildMI(*MBB, MI, dl, TII->get(PIC16::banksel)).
      addOperand(Op);
    Changed = true;
    CurBank = NewBank;
  }

  return Changed;
}

<commit_msg>fixes to pagesel/banksel inserter. 1. restore these across direct/indirect calls. 2. restore pagesel for any macros with gotos.<commit_after>//===-- PIC16MemSelOpt.cpp - PIC16 banksel optimizer  --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the pass which optimizes the emitting of banksel
// instructions before accessing data memory. This currently works within
// a basic block only and keep tracks of the last accessed memory bank.
// If memory access continues to be in the same bank it just makes banksel
// immediate, which is a part of the insn accessing the data memory, from 1
// to zero. The asm printer emits a banksel only if that immediate is 1.
//
// FIXME: this is not implemented yet.  The banksel pass only works on local
// basic blocks.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "pic16-codegen"
#include "PIC16.h"
#include "PIC16ABINames.h"
#include "PIC16InstrInfo.h"
#include "PIC16MCAsmInfo.h"
#include "PIC16TargetMachine.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/GlobalValue.h"
#include "llvm/DerivedTypes.h"

using namespace llvm;

namespace {
  struct MemSelOpt : public MachineFunctionPass {
    static char ID;
    MemSelOpt() : MachineFunctionPass(&ID) {}

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addPreservedID(MachineLoopInfoID);
      AU.addPreservedID(MachineDominatorsID);
      MachineFunctionPass::getAnalysisUsage(AU);
    }

    virtual bool runOnMachineFunction(MachineFunction &MF);

    virtual const char *getPassName() const {
      return "PIC16 Memsel Optimizer";
    }

   bool processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB);
   bool processInstruction(MachineInstr *MI);

  private:
    const TargetInstrInfo *TII; // Machine instruction info.
    MachineBasicBlock *MBB;     // Current basic block
    std::string CurBank;
    int PageChanged;

  };
  char MemSelOpt::ID = 0;
}

FunctionPass *llvm::createPIC16MemSelOptimizerPass() {
  return new MemSelOpt();
}

/// runOnMachineFunction - Loop over all of the basic blocks, transforming FP
/// register references into FP stack references.
///
bool MemSelOpt::runOnMachineFunction(MachineFunction &MF) {
  TII = MF.getTarget().getInstrInfo();
  bool Changed = false;
  for (MachineFunction::iterator I = MF.begin(), E = MF.end();
       I != E; ++I) {
    Changed |= processBasicBlock(MF, *I);
  }

  return Changed;
}

/// processBasicBlock - Loop over all of the instructions in the basic block,
/// transforming FP instructions into their stack form.
///
bool MemSelOpt::processBasicBlock(MachineFunction &MF, MachineBasicBlock &BB) {
  bool Changed = false;
  MBB = &BB;

  // Let us assume that when entering a basic block now bank is selected.
  // Ideally we should look at the predecessors for this information.
  CurBank="";
  PageChanged=0;

  MachineBasicBlock::iterator I;
  for (I = BB.begin(); I != BB.end(); ++I) {
    Changed |= processInstruction(I);

    // if the page has changed insert a page sel before
    // any instruction that needs one
    if (PageChanged == 1)
    {
      // Restore the page if it was changed, before leaving the basic block,
      // because it may be required by the goto terminator or the fall thru
      // basic blcok.
      // If the terminator is return, we don't need to restore since there
      // is no goto or fall thru basic block.
      if ((I->getOpcode() == PIC16::sublw_3) || //macro has goto
          (I->getOpcode() == PIC16::sublw_6) || //macro has goto
          (I->getOpcode() == PIC16::addlwc)  || //macro has goto
          (TII->get(I->getOpcode()).isBranch()))
      {
        DebugLoc dl = I->getDebugLoc();
        BuildMI(*MBB, I, dl, TII->get(PIC16::pagesel)).addExternalSymbol("$");
        Changed = true;
        PageChanged = 0;
      }
    }
  }

   // The basic block is over, but if we did not find any goto yet,
   // we haven't restored the page.
   // Restore the page if it was changed, before leaving the basic block,
   // because it may be required by fall thru basic blcok.
   // If the terminator is return, we don't need to restore since there
   // is fall thru basic block.
   if (PageChanged == 1) {
      // save the end pointer before we move back to last insn.
     MachineBasicBlock::iterator J = I;
     I--;
     const TargetInstrDesc &TID = TII->get(I->getOpcode());
     if (! TID.isReturn())
     {
       DebugLoc dl = I->getDebugLoc();
       BuildMI(*MBB, J, dl,
               TII->get(PIC16::pagesel)).addExternalSymbol("$");
       Changed = true;
       PageChanged = 0;
     }
   }

  return Changed;
}

bool MemSelOpt::processInstruction(MachineInstr *MI) {
  bool Changed = false;

  unsigned NumOperands = MI->getNumOperands();
  if (NumOperands == 0) return false;

  // If this insn is not going to access any memory, return.
  const TargetInstrDesc &TID = TII->get(MI->getOpcode());
  if (!(TID.isBranch() || TID.isCall() || TID.mayLoad() || TID.mayStore()))
    return false;

  // The first thing we should do is that record if banksel/pagesel are
  // changed in an unknown way. This can happend via any type of call.
  // We do it here first before scanning of MemOp / BBOp as the indirect
  // call insns do not have any operands, but they still may change bank/page.
  if (TID.isCall()) {
    // Record that we have changed the page, so that we can restore it
    // before basic block ends.
    // We require to signal that a page anc bank change happened even for
    // indirect calls.
    PageChanged = 1;

    // When a call is made, there may be banksel for variables in callee.
    // Hence the banksel in caller needs to be reset.
    CurBank = "";
  }

  // Scan for the memory address operand.
  // FIXME: Should we use standard interfaces like memoperands_iterator,
  // hasMemOperand() etc ?
  int MemOpPos = -1;
  int BBOpPos = -1;
  for (unsigned i = 0; i < NumOperands; i++) {
    MachineOperand Op = MI->getOperand(i);
    if (Op.getType() ==  MachineOperand::MO_GlobalAddress ||
        Op.getType() ==  MachineOperand::MO_ExternalSymbol) {
      // We found one mem operand. Next one may be BS.
      MemOpPos = i;
    }
    if (Op.getType() ==  MachineOperand::MO_MachineBasicBlock) {
      // We found one BB operand. Next one may be pagesel.
      BBOpPos = i;
    }
  }

  // If we did not find an insn accessing memory. Continue.
  if ((MemOpPos == -1) &&
      (BBOpPos == -1))
    return false;
  assert ((BBOpPos != MemOpPos) && "operand can only be of one type");

  // If this is a pagesel material, handle it first.
  // CALL and br_ucond insns use MemOp (GA or ES) and not BBOp.
  // Pagesel is required only for a direct call.
  if ((MI->getOpcode() == PIC16::CALL)) {
    // Get the BBOp.
    MachineOperand &MemOp = MI->getOperand(MemOpPos);
    DebugLoc dl = MI->getDebugLoc();
    BuildMI(*MBB, MI, dl, TII->get(PIC16::pagesel)).addOperand(MemOp);

    // CALL and br_ucond needs only pagesel. so we are done.
    return true;
  }

  // Pagesel is handled. Now, add a Banksel if needed.
  if (MemOpPos == -1) return Changed;
  // Get the MemOp.
  MachineOperand &Op = MI->getOperand(MemOpPos);

  // Get the section name(NewBank) for MemOp.
  // This assumes that the section names for globals are already set by
  // AsmPrinter->doInitialization.
  std::string NewBank = CurBank;
  bool hasExternalLinkage = false;
  if (Op.getType() ==  MachineOperand::MO_GlobalAddress &&
      Op.getGlobal()->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) {
    if (Op.getGlobal()->hasExternalLinkage())
      hasExternalLinkage= true;
    NewBank = Op.getGlobal()->getSection();
  } else if (Op.getType() ==  MachineOperand::MO_ExternalSymbol) {
    // External Symbol is generated for temp data and arguments. They are
    // in fpdata.<functionname>.# section.
    std::string Sym = Op.getSymbolName();
    NewBank = PAN::getSectionNameForSym(Sym);
  }

  // If the section is shared section, do not emit banksel.
  if (NewBank == PAN::getSharedUDataSectionName())
    return Changed;

  // If the previous and new section names are same, we don't need to
  // emit banksel.
  if (NewBank.compare(CurBank) != 0 || hasExternalLinkage) {
    DebugLoc dl = MI->getDebugLoc();
    BuildMI(*MBB, MI, dl, TII->get(PIC16::banksel)).
      addOperand(Op);
    Changed = true;
    CurBank = NewBank;
  }

  return Changed;
}

<|endoftext|>


<commit_before>//===-- PowerPCSubtarget.cpp - PPC Subtarget Information ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the PPC specific subclass of TargetSubtargetInfo.
//
//===----------------------------------------------------------------------===//

#include "PPCSubtarget.h"
#include "PPC.h"
#include "PPCRegisterInfo.h"
#include "PPCTargetMachine.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineScheduler.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetMachine.h"
#include <cstdlib>

using namespace llvm;

#define DEBUG_TYPE "ppc-subtarget"

#define GET_SUBTARGETINFO_TARGET_DESC
#define GET_SUBTARGETINFO_CTOR
#include "PPCGenSubtargetInfo.inc"

static cl::opt<bool> UseSubRegLiveness("ppc-track-subreg-liveness",
cl::desc("Enable subregister liveness tracking for PPC"), cl::Hidden);

static cl::opt<bool> QPXStackUnaligned("qpx-stack-unaligned",
  cl::desc("Even when QPX is enabled the stack is not 32-byte aligned"),
  cl::Hidden);

PPCSubtarget &PPCSubtarget::initializeSubtargetDependencies(StringRef CPU,
                                                            StringRef FS) {
  initializeEnvironment();
  initSubtargetFeatures(CPU, FS);
  return *this;
}

PPCSubtarget::PPCSubtarget(const Triple &TT, const std::string &CPU,
                           const std::string &FS, const PPCTargetMachine &TM)
    : PPCGenSubtargetInfo(TT, CPU, FS), TargetTriple(TT),
      IsPPC64(TargetTriple.getArch() == Triple::ppc64 ||
              TargetTriple.getArch() == Triple::ppc64le),
      TM(TM), FrameLowering(initializeSubtargetDependencies(CPU, FS)),
      InstrInfo(*this), TLInfo(TM, *this) {}

void PPCSubtarget::initializeEnvironment() {
  StackAlignment = 16;
  DarwinDirective = PPC::DIR_NONE;
  HasMFOCRF = false;
  Has64BitSupport = false;
  Use64BitRegs = false;
  UseCRBits = false;
  HasHardFloat = false;
  HasAltivec = false;
  HasSPE = false;
  HasQPX = false;
  HasVSX = false;
  HasP8Vector = false;
  HasP8Altivec = false;
  HasP8Crypto = false;
  HasP9Vector = false;
  HasP9Altivec = false;
  HasFCPSGN = false;
  HasFSQRT = false;
  HasFRE = false;
  HasFRES = false;
  HasFRSQRTE = false;
  HasFRSQRTES = false;
  HasRecipPrec = false;
  HasSTFIWX = false;
  HasLFIWAX = false;
  HasFPRND = false;
  HasFPCVT = false;
  HasISEL = false;
  HasBPERMD = false;
  HasExtDiv = false;
  HasCMPB = false;
  HasLDBRX = false;
  IsBookE = false;
  HasOnlyMSYNC = false;
  IsPPC4xx = false;
  IsPPC6xx = false;
  IsE500 = false;
  FeatureMFTB = false;
  DeprecatedDST = false;
  HasLazyResolverStubs = false;
  HasICBT = false;
  HasInvariantFunctionDescriptors = false;
  HasPartwordAtomics = false;
  HasDirectMove = false;
  IsQPXStackUnaligned = false;
  HasHTM = false;
  HasFusion = false;
  HasFloat128 = false;
  IsISA3_0 = false;
  UseLongCalls = false;

  HasPOPCNTD = POPCNTD_Unavailable;
}

void PPCSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
  // Determine default and user specified characteristics
  std::string CPUName = CPU;
  if (CPUName.empty() || CPU == "generic") {
    // If cross-compiling with -march=ppc64le without -mcpu
    if (TargetTriple.getArch() == Triple::ppc64le)
      CPUName = "ppc64le";
    else
      CPUName = "generic";
  }

  // Initialize scheduling itinerary for the specified CPU.
  InstrItins = getInstrItineraryForCPU(CPUName);

  // Parse features string.
  ParseSubtargetFeatures(CPUName, FS);

  // If the user requested use of 64-bit regs, but the cpu selected doesn't
  // support it, ignore.
  if (IsPPC64 && has64BitSupport())
    Use64BitRegs = true;

  // Set up darwin-specific properties.
  if (isDarwin())
    HasLazyResolverStubs = true;

  // QPX requires a 32-byte aligned stack. Note that we need to do this if
  // we're compiling for a BG/Q system regardless of whether or not QPX
  // is enabled because external functions will assume this alignment.
  IsQPXStackUnaligned = QPXStackUnaligned;
  StackAlignment = getPlatformStackAlignment();

  // Determine endianness.
  // FIXME: Part of the TargetMachine.
  IsLittleEndian = (TargetTriple.getArch() == Triple::ppc64le);
}

/// Return true if accesses to the specified global have to go through a dyld
/// lazy resolution stub.  This means that an extra load is required to get the
/// address of the global.
bool PPCSubtarget::hasLazyResolverStub(const GlobalValue *GV) const {
  if (!HasLazyResolverStubs)
    return false;
  if (!TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
    return true;
  // 32 bit macho has no relocation for a-b if a is undefined, even if b is in
  // the section that is being relocated. This means we have to use o load even
  // for GVs that are known to be local to the dso.
  if (GV->isDeclarationForLinker() || GV->hasCommonLinkage())
    return true;
  return false;
}

// Embedded cores need aggressive scheduling (and some others also benefit).
static bool needsAggressiveScheduling(unsigned Directive) {
  switch (Directive) {
  default: return false;
  case PPC::DIR_440:
  case PPC::DIR_A2:
  case PPC::DIR_E500mc:
  case PPC::DIR_E5500:
  case PPC::DIR_PWR7:
  case PPC::DIR_PWR8:
  // FIXME: Same as P8 until POWER9 scheduling info is available
  case PPC::DIR_PWR9:
    return true;
  }
}

bool PPCSubtarget::enableMachineScheduler() const {
  // Enable MI scheduling for the embedded cores.
  // FIXME: Enable this for all cores (some additional modeling
  // may be necessary).
  return needsAggressiveScheduling(DarwinDirective);
}

// This overrides the PostRAScheduler bit in the SchedModel for each CPU.
bool PPCSubtarget::enablePostRAScheduler() const { return true; }

PPCGenSubtargetInfo::AntiDepBreakMode PPCSubtarget::getAntiDepBreakMode() const {
  return TargetSubtargetInfo::ANTIDEP_ALL;
}

void PPCSubtarget::getCriticalPathRCs(RegClassVector &CriticalPathRCs) const {
  CriticalPathRCs.clear();
  CriticalPathRCs.push_back(isPPC64() ?
                            &PPC::G8RCRegClass : &PPC::GPRCRegClass);
}

void PPCSubtarget::overrideSchedPolicy(MachineSchedPolicy &Policy,
                                       unsigned NumRegionInstrs) const {
  if (needsAggressiveScheduling(DarwinDirective)) {
    Policy.OnlyTopDown = false;
    Policy.OnlyBottomUp = false;
  }

  // Spilling is generally expensive on all PPC cores, so always enable
  // register-pressure tracking.
  Policy.ShouldTrackPressure = true;
}

bool PPCSubtarget::useAA() const {
  // Use AA during code generation for the embedded cores.
  return needsAggressiveScheduling(DarwinDirective);
}

bool PPCSubtarget::enableSubRegLiveness() const {
  return UseSubRegLiveness;
}

unsigned char
PPCSubtarget::classifyGlobalReference(const GlobalValue *GV) const {
  // Note that currently we don't generate non-pic references.
  // If a caller wants that, this will have to be updated.

  // Large code model always uses the TOC even for local symbols.
  if (TM.getCodeModel() == CodeModel::Large)
    return PPCII::MO_PIC_FLAG | PPCII::MO_NLP_FLAG;

  if (TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
    return PPCII::MO_PIC_FLAG;
  return PPCII::MO_PIC_FLAG | PPCII::MO_NLP_FLAG;
}

bool PPCSubtarget::isELFv2ABI() const { return TM.isELFv2ABI(); }
bool PPCSubtarget::isPPC64() const { return TM.isPPC64(); }
<commit_msg>Initialize variable added in r328617.<commit_after>//===-- PowerPCSubtarget.cpp - PPC Subtarget Information ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the PPC specific subclass of TargetSubtargetInfo.
//
//===----------------------------------------------------------------------===//

#include "PPCSubtarget.h"
#include "PPC.h"
#include "PPCRegisterInfo.h"
#include "PPCTargetMachine.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineScheduler.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetMachine.h"
#include <cstdlib>

using namespace llvm;

#define DEBUG_TYPE "ppc-subtarget"

#define GET_SUBTARGETINFO_TARGET_DESC
#define GET_SUBTARGETINFO_CTOR
#include "PPCGenSubtargetInfo.inc"

static cl::opt<bool> UseSubRegLiveness("ppc-track-subreg-liveness",
cl::desc("Enable subregister liveness tracking for PPC"), cl::Hidden);

static cl::opt<bool> QPXStackUnaligned("qpx-stack-unaligned",
  cl::desc("Even when QPX is enabled the stack is not 32-byte aligned"),
  cl::Hidden);

PPCSubtarget &PPCSubtarget::initializeSubtargetDependencies(StringRef CPU,
                                                            StringRef FS) {
  initializeEnvironment();
  initSubtargetFeatures(CPU, FS);
  return *this;
}

PPCSubtarget::PPCSubtarget(const Triple &TT, const std::string &CPU,
                           const std::string &FS, const PPCTargetMachine &TM)
    : PPCGenSubtargetInfo(TT, CPU, FS), TargetTriple(TT),
      IsPPC64(TargetTriple.getArch() == Triple::ppc64 ||
              TargetTriple.getArch() == Triple::ppc64le),
      TM(TM), FrameLowering(initializeSubtargetDependencies(CPU, FS)),
      InstrInfo(*this), TLInfo(TM, *this) {}

void PPCSubtarget::initializeEnvironment() {
  StackAlignment = 16;
  DarwinDirective = PPC::DIR_NONE;
  HasMFOCRF = false;
  Has64BitSupport = false;
  Use64BitRegs = false;
  UseCRBits = false;
  HasHardFloat = false;
  HasAltivec = false;
  HasSPE = false;
  HasQPX = false;
  HasVSX = false;
  HasP8Vector = false;
  HasP8Altivec = false;
  HasP8Crypto = false;
  HasP9Vector = false;
  HasP9Altivec = false;
  HasFCPSGN = false;
  HasFSQRT = false;
  HasFRE = false;
  HasFRES = false;
  HasFRSQRTE = false;
  HasFRSQRTES = false;
  HasRecipPrec = false;
  HasSTFIWX = false;
  HasLFIWAX = false;
  HasFPRND = false;
  HasFPCVT = false;
  HasISEL = false;
  HasBPERMD = false;
  HasExtDiv = false;
  HasCMPB = false;
  HasLDBRX = false;
  IsBookE = false;
  HasOnlyMSYNC = false;
  IsPPC4xx = false;
  IsPPC6xx = false;
  IsE500 = false;
  FeatureMFTB = false;
  DeprecatedDST = false;
  HasLazyResolverStubs = false;
  HasICBT = false;
  HasInvariantFunctionDescriptors = false;
  HasPartwordAtomics = false;
  HasDirectMove = false;
  IsQPXStackUnaligned = false;
  HasHTM = false;
  HasFusion = false;
  HasFloat128 = false;
  IsISA3_0 = false;
  UseLongCalls = false;
  SecurePlt = false;

  HasPOPCNTD = POPCNTD_Unavailable;
}

void PPCSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
  // Determine default and user specified characteristics
  std::string CPUName = CPU;
  if (CPUName.empty() || CPU == "generic") {
    // If cross-compiling with -march=ppc64le without -mcpu
    if (TargetTriple.getArch() == Triple::ppc64le)
      CPUName = "ppc64le";
    else
      CPUName = "generic";
  }

  // Initialize scheduling itinerary for the specified CPU.
  InstrItins = getInstrItineraryForCPU(CPUName);

  // Parse features string.
  ParseSubtargetFeatures(CPUName, FS);

  // If the user requested use of 64-bit regs, but the cpu selected doesn't
  // support it, ignore.
  if (IsPPC64 && has64BitSupport())
    Use64BitRegs = true;

  // Set up darwin-specific properties.
  if (isDarwin())
    HasLazyResolverStubs = true;

  // QPX requires a 32-byte aligned stack. Note that we need to do this if
  // we're compiling for a BG/Q system regardless of whether or not QPX
  // is enabled because external functions will assume this alignment.
  IsQPXStackUnaligned = QPXStackUnaligned;
  StackAlignment = getPlatformStackAlignment();

  // Determine endianness.
  // FIXME: Part of the TargetMachine.
  IsLittleEndian = (TargetTriple.getArch() == Triple::ppc64le);
}

/// Return true if accesses to the specified global have to go through a dyld
/// lazy resolution stub.  This means that an extra load is required to get the
/// address of the global.
bool PPCSubtarget::hasLazyResolverStub(const GlobalValue *GV) const {
  if (!HasLazyResolverStubs)
    return false;
  if (!TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
    return true;
  // 32 bit macho has no relocation for a-b if a is undefined, even if b is in
  // the section that is being relocated. This means we have to use o load even
  // for GVs that are known to be local to the dso.
  if (GV->isDeclarationForLinker() || GV->hasCommonLinkage())
    return true;
  return false;
}

// Embedded cores need aggressive scheduling (and some others also benefit).
static bool needsAggressiveScheduling(unsigned Directive) {
  switch (Directive) {
  default: return false;
  case PPC::DIR_440:
  case PPC::DIR_A2:
  case PPC::DIR_E500mc:
  case PPC::DIR_E5500:
  case PPC::DIR_PWR7:
  case PPC::DIR_PWR8:
  // FIXME: Same as P8 until POWER9 scheduling info is available
  case PPC::DIR_PWR9:
    return true;
  }
}

bool PPCSubtarget::enableMachineScheduler() const {
  // Enable MI scheduling for the embedded cores.
  // FIXME: Enable this for all cores (some additional modeling
  // may be necessary).
  return needsAggressiveScheduling(DarwinDirective);
}

// This overrides the PostRAScheduler bit in the SchedModel for each CPU.
bool PPCSubtarget::enablePostRAScheduler() const { return true; }

PPCGenSubtargetInfo::AntiDepBreakMode PPCSubtarget::getAntiDepBreakMode() const {
  return TargetSubtargetInfo::ANTIDEP_ALL;
}

void PPCSubtarget::getCriticalPathRCs(RegClassVector &CriticalPathRCs) const {
  CriticalPathRCs.clear();
  CriticalPathRCs.push_back(isPPC64() ?
                            &PPC::G8RCRegClass : &PPC::GPRCRegClass);
}

void PPCSubtarget::overrideSchedPolicy(MachineSchedPolicy &Policy,
                                       unsigned NumRegionInstrs) const {
  if (needsAggressiveScheduling(DarwinDirective)) {
    Policy.OnlyTopDown = false;
    Policy.OnlyBottomUp = false;
  }

  // Spilling is generally expensive on all PPC cores, so always enable
  // register-pressure tracking.
  Policy.ShouldTrackPressure = true;
}

bool PPCSubtarget::useAA() const {
  // Use AA during code generation for the embedded cores.
  return needsAggressiveScheduling(DarwinDirective);
}

bool PPCSubtarget::enableSubRegLiveness() const {
  return UseSubRegLiveness;
}

unsigned char
PPCSubtarget::classifyGlobalReference(const GlobalValue *GV) const {
  // Note that currently we don't generate non-pic references.
  // If a caller wants that, this will have to be updated.

  // Large code model always uses the TOC even for local symbols.
  if (TM.getCodeModel() == CodeModel::Large)
    return PPCII::MO_PIC_FLAG | PPCII::MO_NLP_FLAG;

  if (TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
    return PPCII::MO_PIC_FLAG;
  return PPCII::MO_PIC_FLAG | PPCII::MO_NLP_FLAG;
}

bool PPCSubtarget::isELFv2ABI() const { return TM.isELFv2ABI(); }
bool PPCSubtarget::isPPC64() const { return TM.isPPC64(); }
<|endoftext|>