<commit_before>//
// Created by 欧文韬 on 2015/7/5.
//

#include <assert.h>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <string>
#include <sstream>
#include <list>
#include <ctime>
#include <algorithm>

#include "hiredis_happ.h"

#include "hiredis/adapters/libuv.h"

#ifdef __cplusplus
extern "C" {
#endif

#if defined(_MSC_VER)
    #include <winsock2.h>
    #include <process.h>
    #include <sys/locking.h>
    #include <Windows.h>
    #define THREAD_SPIN_COUNT 2000

    typedef HANDLE thread_t;
    #define THREAD_FUNC unsigned __stdcall
    #define THREAD_CREATE(threadvar, fn, arg) do { \
        uintptr_t threadhandle = _beginthreadex(NULL,0,fn,(arg),0,NULL); \
        (threadvar) = (thread_t) threadhandle; \
    } while (0)
    #define THREAD_JOIN(th) WaitForSingleObject(th, INFINITE)
    #define THREAD_RETURN return (0)

    #define THREAD_SLEEP_MS(TM) Sleep(TM)
#elif defined(__GNUC__) || defined(__clang__)
#include <pthread.h>
#include <errno.h>
#include <unistd.h>

typedef pthread_t thread_t;
#define THREAD_FUNC void*
#define THREAD_CREATE(threadvar, fn, arg) \
        pthread_create(&(threadvar), NULL, fn, arg)
#define THREAD_JOIN(th) pthread_join(th, NULL)
#define THREAD_RETURN pthread_exit (NULL); return NULL

#define THREAD_SLEEP_MS(TM) ((TM > 1000)? sleep(TM / 1000): usleep(0)); usleep((TM % 1000) * 1000)
#endif

#ifdef __cplusplus
}
#endif

static hiredis::happ::cluster g_clu;
static uv_loop_t* main_loop;
static pthread_mutex_t g_mutex;
static std::list<std::string> g_cmds;

static void on_connect_cbk(hiredis::happ::cluster*, hiredis::happ::connection* conn) {
    redisLibuvAttach(conn->get_context(), main_loop);
}

static std::string pick_word(const std::string& cmd_line, int i) {
    if (i < 0) {
        return "";
    }

    std::stringstream ss;
    ss.str(cmd_line);

    std::string ret;
    while(ss>> ret && i-- > 0);
    return ret;
}

static void dump_callback(hiredis::happ::cmd_exec* cmd, struct redisAsyncContext*, void* r, void* p) {
    assert(p == reinterpret_cast<void*>(dump_callback));
    g_clu.dump(std::cout, reinterpret_cast<redisReply*>(r), 0);
}

static void on_timer_proc(uv_timer_t* handle) {
    static time_t sec = time(NULL);
    static time_t usec = 0;

    usec += 100000;
    if (usec > 10000000) {
        sec += usec / 10000000;
        usec %= 10000000;
    }

    // 提取命令
    pthread_mutex_lock(&g_mutex);
    std::list<std::string> pending_cmds;
    if(!g_cmds.empty()) {
        pending_cmds.swap(g_cmds);
    }
    pthread_mutex_unlock(&g_mutex);

    // 执行命令
    while(!pending_cmds.empty()) {
        std::string cmd_line = pending_cmds.front();
        pending_cmds.pop_front();

        std::string cmd = pick_word(cmd_line, 0);
        std::transform(cmd.begin(), cmd.end(), cmd.begin(), ::toupper);
        hiredis::happ::cmd_exec::callback_fn_t cbk = dump_callback;
        int k = 1;
        if ("INFO" == cmd || "MULTI" == cmd || "EXEC" == cmd || "SLAVEOF" == cmd || "CONFIG" == cmd || "SHUTDOWN" == cmd ||
            "CLUSTER" == cmd) {
            k = -1;
        } else if ("SCRIPT" == cmd) {
            k = 2;
        } else if ("EVALSHA" == cmd || "EVAL" == cmd) {
            k = 3;
        } else if ("SUBSCRIBE" == cmd || "UNSUBSCRIBE" == cmd) {
            cbk = NULL;
        }
        std::string cmd_key = pick_word(cmd_line, k);
        if (cmd_key.empty()) {
            g_clu.exec(NULL, 0, cbk, reinterpret_cast<void*>(cbk), cmd.c_str());
        } else {
            g_clu.exec(cmd_key.c_str(), cmd_key.size(), cbk, reinterpret_cast<void*>(cbk), cmd.c_str());
        }
    }

    g_clu.proc(sec, usec);
}

static THREAD_FUNC proc_uv_thd(void *) {
    uv_run(main_loop, UV_RUN_DEFAULT);

    THREAD_RETURN;
}

static void on_log_fn(const char* content) {
    puts(content);
}

int main(int argc, char* argv[]) {
    if (argc < 3) {
        printf("usage: %s <ip> <port>\n", argv[0]);
        return 0;
    }

    const char* ip = argv[1];
    long lport = 0;
    lport = strtol(argv[2], NULL, 10);
    uint16_t port = static_cast<uint16_t>(lport);

    g_clu.init(ip, port);

    main_loop = uv_default_loop();
    // 事件分发器
    g_clu.set_on_connect(on_connect_cbk);

    // 设置定时器
    uv_timer_t timer_obj;
    uv_timer_init(main_loop, &timer_obj);
    uv_timer_start(&timer_obj, on_timer_proc, 1000, 100);

    // 设置日志
    g_clu.set_log_writer(on_log_fn, on_log_fn, 65536);

    g_clu.start();

    thread_t uv_thd;
    pthread_mutex_init(&g_mutex, NULL);
    THREAD_CREATE(uv_thd, proc_uv_thd, NULL);

    std::string cmd;
    while(std::getline(std::cin, cmd)) {
        if (cmd.empty()) {
            continue;
        }

        // 追加命令
        pthread_mutex_lock(&g_mutex);
        g_cmds.push_back(cmd);
        pthread_mutex_unlock(&g_mutex);

        cmd.clear();
    }

    uv_stop(main_loop);
    THREAD_JOIN(uv_thd);
    pthread_mutex_destroy(&g_mutex);

    g_clu.reset();

    return 0;
}
<commit_msg>补充连接信息<commit_after>//
// Created by 欧文韬 on 2015/7/5.
//

#include <assert.h>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <string>
#include <sstream>
#include <list>
#include <ctime>
#include <algorithm>

#include "hiredis_happ.h"

#include "hiredis/adapters/libuv.h"

#ifdef __cplusplus
extern "C" {
#endif

#if defined(_MSC_VER)
    #include <winsock2.h>
    #include <process.h>
    #include <sys/locking.h>
    #include <Windows.h>
    #define THREAD_SPIN_COUNT 2000

    typedef HANDLE thread_t;
    #define THREAD_FUNC unsigned __stdcall
    #define THREAD_CREATE(threadvar, fn, arg) do { \
        uintptr_t threadhandle = _beginthreadex(NULL,0,fn,(arg),0,NULL); \
        (threadvar) = (thread_t) threadhandle; \
    } while (0)
    #define THREAD_JOIN(th) WaitForSingleObject(th, INFINITE)
    #define THREAD_RETURN return (0)

    #define THREAD_SLEEP_MS(TM) Sleep(TM)
#elif defined(__GNUC__) || defined(__clang__)
#include <pthread.h>
#include <errno.h>
#include <unistd.h>

typedef pthread_t thread_t;
#define THREAD_FUNC void*
#define THREAD_CREATE(threadvar, fn, arg) \
        pthread_create(&(threadvar), NULL, fn, arg)
#define THREAD_JOIN(th) pthread_join(th, NULL)
#define THREAD_RETURN pthread_exit (NULL); return NULL

#define THREAD_SLEEP_MS(TM) ((TM > 1000)? sleep(TM / 1000): usleep(0)); usleep((TM % 1000) * 1000)
#endif

#ifdef __cplusplus
}
#endif

static hiredis::happ::cluster g_clu;
static uv_loop_t* main_loop;
static pthread_mutex_t g_mutex;
static std::list<std::string> g_cmds;

static void on_connect_cbk(hiredis::happ::cluster*, hiredis::happ::connection* conn) {
    redisLibuvAttach(conn->get_context(), main_loop);
    if (NULL != conn) {
        printf("start connect to %s", conn->get_context());
    } else {
        printf("error: connection not found when connect");
    }
}

static void on_connected_cbk(hiredis::happ::cluster*, hiredis::happ::connection* conn, const struct redisAsyncContext* c, int status) {
    redisLibuvAttach(conn->get_context(), main_loop);
    if (NULL == conn) {
        printf("error: connection not found when connected");
        return;
    }

    if (REDIS_OK == status) {
        printf("%s connected success", conn->get_key().name.c_str());
    } else {
        char no_msg[] = "none";
        printf("%s connected failed, status %d, err: %d, msg %s",
           conn->get_key().name.c_str(),
           status, c? c->err: 0,
           (c && c->errstr)? c->errstr: no_msg
        );
    }
}

static std::string pick_word(const std::string& cmd_line, int i) {
    if (i < 0) {
        return "";
    }

    std::stringstream ss;
    ss.str(cmd_line);

    std::string ret;
    while(ss>> ret && i-- > 0);
    return ret;
}

static void dump_callback(hiredis::happ::cmd_exec* cmd, struct redisAsyncContext*, void* r, void* p) {
    assert(p == reinterpret_cast<void*>(dump_callback));
    g_clu.dump(std::cout, reinterpret_cast<redisReply*>(r), 0);
}

static void on_timer_proc(uv_timer_t* handle) {
    static time_t sec = time(NULL);
    static time_t usec = 0;

    usec += 100000;
    if (usec > 10000000) {
        sec += usec / 10000000;
        usec %= 10000000;
    }

    // 提取命令
    pthread_mutex_lock(&g_mutex);
    std::list<std::string> pending_cmds;
    if(!g_cmds.empty()) {
        pending_cmds.swap(g_cmds);
    }
    pthread_mutex_unlock(&g_mutex);

    // 执行命令
    while(!pending_cmds.empty()) {
        std::string cmd_line = pending_cmds.front();
        pending_cmds.pop_front();

        std::string cmd = pick_word(cmd_line, 0);
        std::transform(cmd.begin(), cmd.end(), cmd.begin(), ::toupper);
        hiredis::happ::cmd_exec::callback_fn_t cbk = dump_callback;
        int k = 1;
        if ("INFO" == cmd || "MULTI" == cmd || "EXEC" == cmd || "SLAVEOF" == cmd || "CONFIG" == cmd || "SHUTDOWN" == cmd ||
            "CLUSTER" == cmd) {
            k = -1;
        } else if ("SCRIPT" == cmd) {
            k = 2;
        } else if ("EVALSHA" == cmd || "EVAL" == cmd) {
            k = 3;
        } else if ("SUBSCRIBE" == cmd || "UNSUBSCRIBE" == cmd) {
            cbk = NULL;
        }
        std::string cmd_key = pick_word(cmd_line, k);
        if (cmd_key.empty()) {
            g_clu.exec(NULL, 0, cbk, reinterpret_cast<void*>(cbk), cmd.c_str());
        } else {
            g_clu.exec(cmd_key.c_str(), cmd_key.size(), cbk, reinterpret_cast<void*>(cbk), cmd.c_str());
        }
    }

    g_clu.proc(sec, usec);
}

static THREAD_FUNC proc_uv_thd(void *) {
    uv_run(main_loop, UV_RUN_DEFAULT);

    THREAD_RETURN;
}

static void on_log_fn(const char* content) {
    puts(content);
}

int main(int argc, char* argv[]) {
    if (argc < 3) {
        printf("usage: %s <ip> <port>\n", argv[0]);
        return 0;
    }

    const char* ip = argv[1];
    long lport = 0;
    lport = strtol(argv[2], NULL, 10);
    uint16_t port = static_cast<uint16_t>(lport);

    g_clu.init(ip, port);

    main_loop = uv_default_loop();
    // 事件分发器
    g_clu.set_on_connect(on_connect_cbk);
    g_clu.set_on_connected(on_connected_cbk);

    // 设置定时器
    uv_timer_t timer_obj;
    uv_timer_init(main_loop, &timer_obj);
    uv_timer_start(&timer_obj, on_timer_proc, 1000, 100);

    // 设置日志
    g_clu.set_log_writer(on_log_fn, on_log_fn, 65536);

    g_clu.start();

    thread_t uv_thd;
    pthread_mutex_init(&g_mutex, NULL);
    THREAD_CREATE(uv_thd, proc_uv_thd, NULL);

    std::string cmd;
    while(std::getline(std::cin, cmd)) {
        if (cmd.empty()) {
            continue;
        }

        // 追加命令
        pthread_mutex_lock(&g_mutex);
        g_cmds.push_back(cmd);
        pthread_mutex_unlock(&g_mutex);

        cmd.clear();
    }

    uv_stop(main_loop);
    THREAD_JOIN(uv_thd);
    pthread_mutex_destroy(&g_mutex);

    g_clu.reset();

    return 0;
}
<|endoftext|>


<commit_before>/* GStreamer
 * Copyright (C) 2015 Raimo Jrvi <raimo.jarvi@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
 * USA
 */

#include "gstbdagrabber.h"
#include "gstbdautil.h"

GstBdaGrabber::GstBdaGrabber (GstBdaSrc * bda_src)
:  bda_src (bda_src)
{
}

GstBdaGrabber::~GstBdaGrabber ()
{
}

STDMETHODIMP_ (ULONG) GstBdaGrabber::AddRef ()
{
  // Reference counting is not implemented.
  return 1;
}

STDMETHODIMP_ (ULONG) GstBdaGrabber::Release ()
{
  // Reference counting is not implemented.
  return 1;
}

STDMETHODIMP GstBdaGrabber::QueryInterface (REFIID riid, void **object)
{
  return E_NOTIMPL;
}

STDMETHODIMP GstBdaGrabber::SampleCB (double time, IMediaSample * sample)
{
  BYTE *data = NULL;
  HRESULT hr = sample->GetPointer(&data);

  if (FAILED (hr)) {
    GST_ERROR_OBJECT (bda_src, "Unable to get sample data: %s (0x%lx)",
        bda_err_to_str (hr).c_str(), hr);
    return S_FALSE;
  }

  bda_src->sample_received (bda_src, data, sample->GetActualDataLength ());

  return S_OK;
}

STDMETHODIMP GstBdaGrabber::BufferCB (double time, BYTE * buffer, long bufferLen)
{
  return E_FAIL;
}
<commit_msg>Fix compiler warnings about unused parameters<commit_after>/* GStreamer
 * Copyright (C) 2015 Raimo Jrvi <raimo.jarvi@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
 * USA
 */

#include "gstbdagrabber.h"
#include "gstbdautil.h"

GstBdaGrabber::GstBdaGrabber (GstBdaSrc * bda_src)
:  bda_src (bda_src)
{
}

GstBdaGrabber::~GstBdaGrabber ()
{
}

STDMETHODIMP_ (ULONG) GstBdaGrabber::AddRef ()
{
  // Reference counting is not implemented.
  return 1;
}

STDMETHODIMP_ (ULONG) GstBdaGrabber::Release ()
{
  // Reference counting is not implemented.
  return 1;
}

STDMETHODIMP GstBdaGrabber::QueryInterface (REFIID /*riid */ , void ** /*object */ )
{
  return E_NOTIMPL;
}

STDMETHODIMP GstBdaGrabber::SampleCB (double /*time */ , IMediaSample * sample)
{
  BYTE *data = NULL;
  HRESULT hr = sample->GetPointer(&data);

  if (FAILED (hr)) {
    GST_ERROR_OBJECT (bda_src, "Unable to get sample data: %s (0x%lx)",
        bda_err_to_str (hr).c_str(), hr);
    return S_FALSE;
  }

  bda_src->sample_received (bda_src, data, sample->GetActualDataLength ());

  return S_OK;
}

STDMETHODIMP GstBdaGrabber::BufferCB (double /*time */ , BYTE * /*buffer */ , long /*bufferLen */ )
{
  return E_FAIL;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkPath.h"
#include "include/utils/SkParsePath.h"
#include "samplecode/Sample.h"

#include "src/core/SkGeometry.h"

namespace {

//////////////////////////////////////////////////////////////////////////////

static SkPoint rotate90(const SkPoint& p) { return {p.fY, -p.fX}; }
static SkPoint rotate180(const SkPoint& p) { return p * -1; }
static SkPoint setLength(SkPoint p, float len) {
    if (!p.setLength(len)) {
        SkDebugf("Failed to set point length\n");
    }
    return p;
}
static bool isClockwise(const SkPoint& a, const SkPoint& b) { return a.cross(b) > 0; }

//////////////////////////////////////////////////////////////////////////////

// Testing ground for a new stroker implementation
class SkPathStroker2 {
public:
    // Returns the fill path
    SkPath getFillPath(const SkPath& path, const SkPaint& paint);

private:
    struct PathSegment {
        SkPath::Verb fVerb;
        SkPoint fPoints[4];
    };

    float fRadius;
    SkPaint::Cap fCap;
    SkPaint::Join fJoin;
    SkPath fInnerPath, fOuterPath;
    SkPath *fInner = &fInnerPath, *fOuter = &fOuterPath;

    // Initialize stroker state
    void initForPath(const SkPath& path, const SkPaint& paint);

    // Strokes a line segment
    void strokeLine(const PathSegment& line, bool needsMove);

    // Adds an endcap to fOuter
    enum class CapLocation { Start, End };
    void endcap(CapLocation loc);

    // Adds a join between the two segments
    void join(const PathSegment& prev, const PathSegment& curr);

    // Appends path in reverse to result
    static void appendPathReversed(const SkPath* path, SkPath* result);

    // Returns the segment unit normal
    static SkPoint unitNormal(const PathSegment& seg, float t);

    // Returns squared magnitude of line segments.
    static float squaredLineLength(const PathSegment& lineSeg);
};

void SkPathStroker2::initForPath(const SkPath& path, const SkPaint& paint) {
    fRadius = paint.getStrokeWidth() / 2;
    fCap = paint.getStrokeCap();
    fJoin = paint.getStrokeJoin();
    fInnerPath.rewind();
    fOuterPath.rewind();
    fInner = &fInnerPath;
    fOuter = &fOuterPath;
}

SkPath SkPathStroker2::getFillPath(const SkPath& path, const SkPaint& paint) {
    initForPath(path, paint);

    // Trace the inner and outer paths simultaneously. Inner will therefore be
    // recorded in reverse from how we trace the outline.
    SkPath::Iter it(path, false);
    PathSegment segment, prevSegment;
    bool firstSegment = true;
    while ((segment.fVerb = it.next(segment.fPoints)) != SkPath::kDone_Verb) {
        // Join to the previous segment
        if (!firstSegment) {
            join(prevSegment, segment);
        }

        // Stroke the current segment
        switch (segment.fVerb) {
            case SkPath::kLine_Verb:
                strokeLine(segment, firstSegment);
                break;
            case SkPath::kMove_Verb:
                // Don't care about multiple contours currently
                continue;
            default:
                SkDebugf("Unhandled path verb %d\n", segment.fVerb);
                break;
        }

        std::swap(segment, prevSegment);
        firstSegment = false;
    }

    // Open contour => endcap at the end
    const bool isClosed = path.isLastContourClosed();
    if (isClosed) {
        SkDebugf("Unhandled closed contour\n");
    } else {
        endcap(CapLocation::End);
    }

    // Walk inner path in reverse, appending to result
    appendPathReversed(fInner, fOuter);
    endcap(CapLocation::Start);

    return fOuterPath;
}

void SkPathStroker2::strokeLine(const PathSegment& line, bool needsMove) {
    const SkPoint tangent = line.fPoints[1] - line.fPoints[0];
    const SkPoint normal = rotate90(tangent);
    const SkPoint offset = setLength(normal, fRadius);
    if (needsMove) {
        fOuter->moveTo(line.fPoints[0] + offset);
        fInner->moveTo(line.fPoints[0] - offset);
    }
    fOuter->lineTo(line.fPoints[1] + offset);
    fInner->lineTo(line.fPoints[1] - offset);
}

void SkPathStroker2::endcap(CapLocation loc) {
    const auto buttCap = [this](CapLocation loc) {
        if (loc == CapLocation::Start) {
            // Back at the start of the path: just close the stroked outline
            fOuter->close();
        } else {
            // Inner last pt == first pt when appending in reverse
            SkPoint innerLastPt;
            fInner->getLastPt(&innerLastPt);
            fOuter->lineTo(innerLastPt);
        }
    };

    switch (fCap) {
        case SkPaint::kButt_Cap:
            buttCap(loc);
            break;
        default:
            SkDebugf("Unhandled endcap %d\n", fCap);
            buttCap(loc);
            break;
    }
}

void SkPathStroker2::join(const PathSegment& prev, const PathSegment& curr) {
    const auto miterJoin = [this](const PathSegment& prev, const PathSegment& curr) {
        // Common path endpoint of the two segments is the midpoint of the miter line.
        const SkPoint miterMidpt = curr.fPoints[0];

        SkPoint before = unitNormal(prev, 1);
        SkPoint after = unitNormal(curr, 0);

        // Check who's inside and who's outside.
        SkPath *outer = fOuter, *inner = fInner;
        if (!isClockwise(before, after)) {
            std::swap(inner, outer);
            before = rotate180(before);
            after = rotate180(after);
        }

        const float cosTheta = before.dot(after);
        if (SkScalarNearlyZero(1 - cosTheta)) {
            // Nearly identical normals: don't bother.
            return;
        }

        // Before and after have the same origin and magnitude, so before+after is the diagonal of
        // their rhombus. Origin of this vector is the midpoint of the miter line.
        SkPoint miterVec = before + after;

        // Note the relationship (draw a right triangle with the miter line as its hypoteneuse):
        //     sin(theta/2) = strokeWidth / miterLength
        // so miterLength = strokeWidth / sin(theta/2)
        // where miterLength is the length of the miter from outer point to inner corner.
        // miterVec's origin is the midpoint of the miter line, so we use strokeWidth/2.
        // Sqrt is just an application of half-angle identities.
        const float sinHalfTheta = sqrtf(0.5 * (1 + cosTheta));
        const float halfMiterLength = fRadius / sinHalfTheta;
        miterVec.setLength(halfMiterLength);  // TODO: miter length limit

        // Outer: connect to the miter point, and then to t=0 (on outside stroke) of next segment.
        const SkPoint dest = setLength(after, fRadius);
        outer->lineTo(miterMidpt + miterVec);
        outer->lineTo(miterMidpt + dest);

        // Inner miter is more involved. We're already at t=1 (on inside stroke) of 'prev'.
        // Check 2 cases to see we can directly connect to the inner miter point
        // (midpoint - miterVec), or if we need to add extra "loop" geometry.
        const SkPoint prevUnitTangent = rotate90(before);
        const float radiusSquared = fRadius * fRadius;
        // 'alpha' is angle between prev tangent and the curr inwards normal
        const float cosAlpha = prevUnitTangent.dot(-after);
        // Solve triangle for len^2:  radius^2 = len^2 + (radius * sin(alpha))^2
        // This is the point at which the inside "corner" of curr at t=0 will lie on a
        // line connecting the inner and outer corners of prev at t=0. If len is below
        // this threshold, the inside corner of curr will "poke through" the start of prev,
        // and we'll need the inner loop geometry.
        const float threshold1 = radiusSquared * cosAlpha * cosAlpha;
        // Solve triangle for len^2:  halfMiterLen^2 = radius^2 + len^2
        // This is the point at which the inner miter point will lie on the inner stroke
        // boundary of the curr segment. If len is below this threshold, the miter point
        // moves 'inside' of the stroked outline, and we'll need the inner loop geometry.
        const float threshold2 = halfMiterLength * halfMiterLength - radiusSquared;
        // If a segment length is smaller than the larger of the two thresholds,
        // we'll have to add the inner loop geometry.
        const float maxLenSqd = std::max(threshold1, threshold2);
        const bool needsInnerLoop =
                squaredLineLength(prev) < maxLenSqd || squaredLineLength(curr) < maxLenSqd;
        if (needsInnerLoop) {
            // Connect to the miter midpoint (common path endpoint of the two segments),
            // and then to t=0 (on inside) of the next segment. This adds an interior "loop" of
            // geometry that handles edge cases where segment lengths are shorter than the
            // stroke width.
            inner->lineTo(miterMidpt);
            inner->lineTo(miterMidpt - dest);
        } else {
            // Directly connect to inner miter point.
            inner->setLastPt(miterMidpt - miterVec);
        }
    };

    switch (fJoin) {
        case SkPaint::kMiter_Join:
            miterJoin(prev, curr);
            break;
        default:
            SkDebugf("Unhandled join %d\n", fJoin);
            miterJoin(prev, curr);
            break;
    }
}

void SkPathStroker2::appendPathReversed(const SkPath* path, SkPath* result) {
    const int numVerbs = path->countVerbs();
    const int numPoints = path->countPoints();
    std::unique_ptr<uint8_t[]> verbs = std::make_unique<uint8_t[]>(numVerbs);
    std::unique_ptr<SkPoint[]> points = std::make_unique<SkPoint[]>(numPoints);

    path->getVerbs(verbs.get(), numVerbs);
    path->getPoints(points.get(), numPoints);

    for (int i = numVerbs - 1, j = numPoints; i >= 0; i--) {
        auto verb = static_cast<SkPath::Verb>(verbs[i]);
        switch (verb) {
            case SkPath::kLine_Verb: {
                j -= 1;
                SkASSERT(j >= 1);
                result->lineTo(points[j - 1]);
                break;
            }
            case SkPath::kMove_Verb:
                // Ignore
                break;
            default:
                SkASSERT(false);
                break;
        }
    }
}

SkPoint SkPathStroker2::unitNormal(const PathSegment& seg, float t) {
    if (seg.fVerb != SkPath::kLine_Verb) {
        SkDebugf("Unhandled verb for unit normal %d\n", seg.fVerb);
    }

    (void)t;  // Not needed for lines
    const SkPoint tangent = seg.fPoints[1] - seg.fPoints[0];
    const SkPoint normal = rotate90(tangent);
    return setLength(normal, 1);
}

float SkPathStroker2::squaredLineLength(const PathSegment& lineSeg) {
    SkASSERT(lineSeg.fVerb == SkPath::kLine_Verb);
    const SkPoint diff = lineSeg.fPoints[1] - lineSeg.fPoints[0];
    return diff.dot(diff);
}

}  // namespace

//////////////////////////////////////////////////////////////////////////////

class SimpleStroker : public Sample {
    bool fShowSkiaStroke, fShowHidden;
    float fWidth = 175;
    SkPaint fPtsPaint, fStrokePaint, fNewFillPaint, fHiddenPaint;
    static constexpr int kN = 3;

public:
    SkPoint fPts[kN];

    SimpleStroker() : fShowSkiaStroke(true), fShowHidden(false) {
        fPts[0] = {500, 200};
        fPts[1] = {300, 200};
        fPts[2] = {100, 100};

        fPtsPaint.setAntiAlias(true);
        fPtsPaint.setStrokeWidth(10);
        fPtsPaint.setStrokeCap(SkPaint::kRound_Cap);

        fStrokePaint.setAntiAlias(true);
        fStrokePaint.setStyle(SkPaint::kStroke_Style);
        fStrokePaint.setColor(0x80FF0000);

        fNewFillPaint.setAntiAlias(true);
        fNewFillPaint.setColor(0x8000FF00);

        fHiddenPaint.setAntiAlias(true);
        fHiddenPaint.setStyle(SkPaint::kStroke_Style);
        fHiddenPaint.setColor(0xFF0000FF);
    }

    void toggle(bool& value) { value = !value; }

protected:
    SkString name() override { return SkString("SimpleStroker"); }

    bool onChar(SkUnichar uni) override {
        switch (uni) {
            case '1':
                this->toggle(fShowSkiaStroke);
                return true;
            case '2':
                this->toggle(fShowHidden);
                return true;
            case '-':
                fWidth -= 5;
                return true;
            case '=':
                fWidth += 5;
                return true;
            default:
                break;
        }
        return false;
    }

    void makePath(SkPath* path) {
        path->moveTo(fPts[0]);
        for (int i = 1; i < kN; ++i) {
            path->lineTo(fPts[i]);
        }
    }

    void onDrawContent(SkCanvas* canvas) override {
        canvas->drawColor(0xFFEEEEEE);

        SkPath path;
        this->makePath(&path);

        fStrokePaint.setStrokeWidth(fWidth);

        // The correct result
        if (fShowSkiaStroke) {
            canvas->drawPath(path, fStrokePaint);
        }

        // Simple stroker result
        SkPathStroker2 stroker;
        SkPath fillPath = stroker.getFillPath(path, fStrokePaint);
        canvas->drawPath(fillPath, fNewFillPaint);

        if (fShowHidden) {
            canvas->drawPath(fillPath, fHiddenPaint);
        }

        canvas->drawPoints(SkCanvas::kPoints_PointMode, kN, fPts, fPtsPaint);
    }

    Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
        const SkScalar tol = 4;
        const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2);
        for (int i = 0; i < kN; ++i) {
            if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) {
                return new Click([this, i](Click* c) {
                    fPts[i] = c->fCurr;
                    return true;
                });
            }
        }
        return nullptr;
    }

private:
    typedef Sample INHERITED;
};

DEF_SAMPLE(return new SimpleStroker;)
<commit_msg>Add path recorder class (toy stroker)<commit_after>/*
 * Copyright 2020 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkPath.h"
#include "include/utils/SkParsePath.h"
#include "samplecode/Sample.h"

#include "src/core/SkGeometry.h"

namespace {

//////////////////////////////////////////////////////////////////////////////

static SkPoint rotate90(const SkPoint& p) { return {p.fY, -p.fX}; }
static SkPoint rotate180(const SkPoint& p) { return p * -1; }
static SkPoint setLength(SkPoint p, float len) {
    if (!p.setLength(len)) {
        SkDebugf("Failed to set point length\n");
    }
    return p;
}
static bool isClockwise(const SkPoint& a, const SkPoint& b) { return a.cross(b) > 0; }

//////////////////////////////////////////////////////////////////////////////
// Testing ground for a new stroker implementation

/** Helper class for constructing paths, with undo support */
class PathRecorder {
public:
    SkPath getPath() const {
        return SkPath::Make(fPoints.data(), fPoints.size(), fVerbs.data(), fVerbs.size(), nullptr,
                            0, SkPathFillType::kWinding);
    }

    void moveTo(SkPoint p) {
        fVerbs.push_back(SkPath::kMove_Verb);
        fPoints.push_back(p);
    }

    void lineTo(SkPoint p) {
        fVerbs.push_back(SkPath::kLine_Verb);
        fPoints.push_back(p);
    }

    void close() { fVerbs.push_back(SkPath::kClose_Verb); }

    void rewind() {
        fVerbs.clear();
        fPoints.clear();
    }

    int countPoints() const { return fPoints.size(); }

    int countVerbs() const { return fVerbs.size(); }

    bool getLastPt(SkPoint* lastPt) const {
        if (fPoints.empty()) {
            return false;
        }
        *lastPt = fPoints.back();
        return true;
    }

    void setLastPt(SkPoint lastPt) {
        if (fPoints.empty()) {
            moveTo(lastPt);
        } else {
            fPoints.back().set(lastPt.fX, lastPt.fY);
        }
    }

    const std::vector<uint8_t>& verbs() const { return fVerbs; }

    const std::vector<SkPoint>& points() const { return fPoints; }

private:
    std::vector<uint8_t> fVerbs;
    std::vector<SkPoint> fPoints;
};

class SkPathStroker2 {
public:
    // Returns the fill path
    SkPath getFillPath(const SkPath& path, const SkPaint& paint);

private:
    struct PathSegment {
        SkPath::Verb fVerb;
        SkPoint fPoints[4];
    };

    float fRadius;
    SkPaint::Cap fCap;
    SkPaint::Join fJoin;
    PathRecorder fInner, fOuter;

    // Initialize stroker state
    void initForPath(const SkPath& path, const SkPaint& paint);

    // Strokes a line segment
    void strokeLine(const PathSegment& line, bool needsMove);

    // Adds an endcap to fOuter
    enum class CapLocation { Start, End };
    void endcap(CapLocation loc);

    // Adds a join between the two segments
    void join(const PathSegment& prev, const PathSegment& curr);

    // Appends path in reverse to result
    static void appendPathReversed(const PathRecorder& path, PathRecorder* result);

    // Returns the segment unit normal
    static SkPoint unitNormal(const PathSegment& seg, float t);

    // Returns squared magnitude of line segments.
    static float squaredLineLength(const PathSegment& lineSeg);
};

void SkPathStroker2::initForPath(const SkPath& path, const SkPaint& paint) {
    fRadius = paint.getStrokeWidth() / 2;
    fCap = paint.getStrokeCap();
    fJoin = paint.getStrokeJoin();
    fInner.rewind();
    fOuter.rewind();
}

SkPath SkPathStroker2::getFillPath(const SkPath& path, const SkPaint& paint) {
    initForPath(path, paint);

    // Trace the inner and outer paths simultaneously. Inner will therefore be
    // recorded in reverse from how we trace the outline.
    SkPath::Iter it(path, false);
    PathSegment segment, prevSegment;
    bool firstSegment = true;
    while ((segment.fVerb = it.next(segment.fPoints)) != SkPath::kDone_Verb) {
        // Join to the previous segment
        if (!firstSegment) {
            join(prevSegment, segment);
        }

        // Stroke the current segment
        switch (segment.fVerb) {
            case SkPath::kLine_Verb:
                strokeLine(segment, firstSegment);
                break;
            case SkPath::kMove_Verb:
                // Don't care about multiple contours currently
                continue;
            default:
                SkDebugf("Unhandled path verb %d\n", segment.fVerb);
                break;
        }

        std::swap(segment, prevSegment);
        firstSegment = false;
    }

    // Open contour => endcap at the end
    const bool isClosed = path.isLastContourClosed();
    if (isClosed) {
        SkDebugf("Unhandled closed contour\n");
    } else {
        endcap(CapLocation::End);
    }

    // Walk inner path in reverse, appending to result
    appendPathReversed(fInner, &fOuter);
    endcap(CapLocation::Start);

    return fOuter.getPath();
}

void SkPathStroker2::strokeLine(const PathSegment& line, bool needsMove) {
    const SkPoint tangent = line.fPoints[1] - line.fPoints[0];
    const SkPoint normal = rotate90(tangent);
    const SkPoint offset = setLength(normal, fRadius);
    if (needsMove) {
        fOuter.moveTo(line.fPoints[0] + offset);
        fInner.moveTo(line.fPoints[0] - offset);
    }
    fOuter.lineTo(line.fPoints[1] + offset);
    fInner.lineTo(line.fPoints[1] - offset);
}

void SkPathStroker2::endcap(CapLocation loc) {
    const auto buttCap = [this](CapLocation loc) {
        if (loc == CapLocation::Start) {
            // Back at the start of the path: just close the stroked outline
            fOuter.close();
        } else {
            // Inner last pt == first pt when appending in reverse
            SkPoint innerLastPt;
            fInner.getLastPt(&innerLastPt);
            fOuter.lineTo(innerLastPt);
        }
    };

    switch (fCap) {
        case SkPaint::kButt_Cap:
            buttCap(loc);
            break;
        default:
            SkDebugf("Unhandled endcap %d\n", fCap);
            buttCap(loc);
            break;
    }
}

void SkPathStroker2::join(const PathSegment& prev, const PathSegment& curr) {
    const auto miterJoin = [this](const PathSegment& prev, const PathSegment& curr) {
        // Common path endpoint of the two segments is the midpoint of the miter line.
        const SkPoint miterMidpt = curr.fPoints[0];

        SkPoint before = unitNormal(prev, 1);
        SkPoint after = unitNormal(curr, 0);

        // Check who's inside and who's outside.
        PathRecorder *outer = &fOuter, *inner = &fInner;
        if (!isClockwise(before, after)) {
            std::swap(inner, outer);
            before = rotate180(before);
            after = rotate180(after);
        }

        const float cosTheta = before.dot(after);
        if (SkScalarNearlyZero(1 - cosTheta)) {
            // Nearly identical normals: don't bother.
            return;
        }

        // Before and after have the same origin and magnitude, so before+after is the diagonal of
        // their rhombus. Origin of this vector is the midpoint of the miter line.
        SkPoint miterVec = before + after;

        // Note the relationship (draw a right triangle with the miter line as its hypoteneuse):
        //     sin(theta/2) = strokeWidth / miterLength
        // so miterLength = strokeWidth / sin(theta/2)
        // where miterLength is the length of the miter from outer point to inner corner.
        // miterVec's origin is the midpoint of the miter line, so we use strokeWidth/2.
        // Sqrt is just an application of half-angle identities.
        const float sinHalfTheta = sqrtf(0.5 * (1 + cosTheta));
        const float halfMiterLength = fRadius / sinHalfTheta;
        miterVec.setLength(halfMiterLength);  // TODO: miter length limit

        // Outer: connect to the miter point, and then to t=0 (on outside stroke) of next segment.
        const SkPoint dest = setLength(after, fRadius);
        outer->lineTo(miterMidpt + miterVec);
        outer->lineTo(miterMidpt + dest);

        // Inner miter is more involved. We're already at t=1 (on inside stroke) of 'prev'.
        // Check 2 cases to see we can directly connect to the inner miter point
        // (midpoint - miterVec), or if we need to add extra "loop" geometry.
        const SkPoint prevUnitTangent = rotate90(before);
        const float radiusSquared = fRadius * fRadius;
        // 'alpha' is angle between prev tangent and the curr inwards normal
        const float cosAlpha = prevUnitTangent.dot(-after);
        // Solve triangle for len^2:  radius^2 = len^2 + (radius * sin(alpha))^2
        // This is the point at which the inside "corner" of curr at t=0 will lie on a
        // line connecting the inner and outer corners of prev at t=0. If len is below
        // this threshold, the inside corner of curr will "poke through" the start of prev,
        // and we'll need the inner loop geometry.
        const float threshold1 = radiusSquared * cosAlpha * cosAlpha;
        // Solve triangle for len^2:  halfMiterLen^2 = radius^2 + len^2
        // This is the point at which the inner miter point will lie on the inner stroke
        // boundary of the curr segment. If len is below this threshold, the miter point
        // moves 'inside' of the stroked outline, and we'll need the inner loop geometry.
        const float threshold2 = halfMiterLength * halfMiterLength - radiusSquared;
        // If a segment length is smaller than the larger of the two thresholds,
        // we'll have to add the inner loop geometry.
        const float maxLenSqd = std::max(threshold1, threshold2);
        const bool needsInnerLoop =
                squaredLineLength(prev) < maxLenSqd || squaredLineLength(curr) < maxLenSqd;
        if (needsInnerLoop) {
            // Connect to the miter midpoint (common path endpoint of the two segments),
            // and then to t=0 (on inside) of the next segment. This adds an interior "loop" of
            // geometry that handles edge cases where segment lengths are shorter than the
            // stroke width.
            inner->lineTo(miterMidpt);
            inner->lineTo(miterMidpt - dest);
        } else {
            // Directly connect to inner miter point.
            inner->setLastPt(miterMidpt - miterVec);
        }
    };

    switch (fJoin) {
        case SkPaint::kMiter_Join:
            miterJoin(prev, curr);
            break;
        default:
            SkDebugf("Unhandled join %d\n", fJoin);
            miterJoin(prev, curr);
            break;
    }
}

void SkPathStroker2::appendPathReversed(const PathRecorder& path, PathRecorder* result) {
    const int numVerbs = path.countVerbs();
    const int numPoints = path.countPoints();
    const std::vector<uint8_t>& verbs = path.verbs();
    const std::vector<SkPoint>& points = path.points();

    for (int i = numVerbs - 1, j = numPoints; i >= 0; i--) {
        auto verb = static_cast<SkPath::Verb>(verbs[i]);
        switch (verb) {
            case SkPath::kLine_Verb: {
                j -= 1;
                SkASSERT(j >= 1);
                result->lineTo(points[j - 1]);
                break;
            }
            case SkPath::kMove_Verb:
                // Ignore
                break;
            default:
                SkASSERT(false);
                break;
        }
    }
}

SkPoint SkPathStroker2::unitNormal(const PathSegment& seg, float t) {
    if (seg.fVerb != SkPath::kLine_Verb) {
        SkDebugf("Unhandled verb for unit normal %d\n", seg.fVerb);
    }

    (void)t;  // Not needed for lines
    const SkPoint tangent = seg.fPoints[1] - seg.fPoints[0];
    const SkPoint normal = rotate90(tangent);
    return setLength(normal, 1);
}

float SkPathStroker2::squaredLineLength(const PathSegment& lineSeg) {
    SkASSERT(lineSeg.fVerb == SkPath::kLine_Verb);
    const SkPoint diff = lineSeg.fPoints[1] - lineSeg.fPoints[0];
    return diff.dot(diff);
}

}  // namespace

//////////////////////////////////////////////////////////////////////////////

class SimpleStroker : public Sample {
    bool fShowSkiaStroke, fShowHidden;
    float fWidth = 175;
    SkPaint fPtsPaint, fStrokePaint, fNewFillPaint, fHiddenPaint;
    static constexpr int kN = 3;

public:
    SkPoint fPts[kN];

    SimpleStroker() : fShowSkiaStroke(true), fShowHidden(false) {
        fPts[0] = {500, 200};
        fPts[1] = {300, 200};
        fPts[2] = {100, 100};

        fPtsPaint.setAntiAlias(true);
        fPtsPaint.setStrokeWidth(10);
        fPtsPaint.setStrokeCap(SkPaint::kRound_Cap);

        fStrokePaint.setAntiAlias(true);
        fStrokePaint.setStyle(SkPaint::kStroke_Style);
        fStrokePaint.setColor(0x80FF0000);

        fNewFillPaint.setAntiAlias(true);
        fNewFillPaint.setColor(0x8000FF00);

        fHiddenPaint.setAntiAlias(true);
        fHiddenPaint.setStyle(SkPaint::kStroke_Style);
        fHiddenPaint.setColor(0xFF0000FF);
    }

    void toggle(bool& value) { value = !value; }

protected:
    SkString name() override { return SkString("SimpleStroker"); }

    bool onChar(SkUnichar uni) override {
        switch (uni) {
            case '1':
                this->toggle(fShowSkiaStroke);
                return true;
            case '2':
                this->toggle(fShowHidden);
                return true;
            case '-':
                fWidth -= 5;
                return true;
            case '=':
                fWidth += 5;
                return true;
            default:
                break;
        }
        return false;
    }

    void makePath(SkPath* path) {
        path->moveTo(fPts[0]);
        for (int i = 1; i < kN; ++i) {
            path->lineTo(fPts[i]);
        }
    }

    void onDrawContent(SkCanvas* canvas) override {
        canvas->drawColor(0xFFEEEEEE);

        SkPath path;
        this->makePath(&path);

        fStrokePaint.setStrokeWidth(fWidth);

        // The correct result
        if (fShowSkiaStroke) {
            canvas->drawPath(path, fStrokePaint);
        }

        // Simple stroker result
        SkPathStroker2 stroker;
        SkPath fillPath = stroker.getFillPath(path, fStrokePaint);
        canvas->drawPath(fillPath, fNewFillPaint);

        if (fShowHidden) {
            canvas->drawPath(fillPath, fHiddenPaint);
        }

        canvas->drawPoints(SkCanvas::kPoints_PointMode, kN, fPts, fPtsPaint);
    }

    Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
        const SkScalar tol = 4;
        const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2);
        for (int i = 0; i < kN; ++i) {
            if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) {
                return new Click([this, i](Click* c) {
                    fPts[i] = c->fCurr;
                    return true;
                });
            }
        }
        return nullptr;
    }

private:
    typedef Sample INHERITED;
};

DEF_SAMPLE(return new SimpleStroker;)
<|endoftext|>


<commit_before>//===-- RegAllocSimple.cpp - A simple generic register allocator --- ------===//
//
// This file implements a simple register allocator. *Very* simple.
//
//===----------------------------------------------------------------------===//

#include "llvm/Function.h"
#include "llvm/iTerminators.h"
#include "llvm/Type.h"
#include "llvm/Constants.h"
#include "llvm/Pass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/Target/MachineInstrInfo.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/MachineRegInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/InstVisitor.h"
#include "Support/Statistic.h"
#include <map>

namespace {
  struct RegAllocSimple : public FunctionPass {
    TargetMachine &TM;
    MachineBasicBlock *CurrMBB;
    MachineFunction *MF;
    unsigned maxOffset;
    const MRegisterInfo *RegInfo;
    unsigned NumBytesAllocated, ByteAlignment;

    // Maps SSA Regs => offsets on the stack where these values are stored
    // FIXME: change name to VirtReg2OffsetMap
    std::map<unsigned, unsigned> RegMap;

    // Maps SSA Regs => physical regs
    std::map<unsigned, unsigned> SSA2PhysRegMap;

    // Maps physical register to their register classes
    std::map<unsigned, const TargetRegisterClass*> PhysReg2RegClassMap;

    // Made to combat the incorrect allocation of r2 = add r1, r1
    std::map<unsigned, unsigned> VirtReg2PhysRegMap;

    // Maps RegClass => which index we can take a register from. Since this is a
    // simple register allocator, when we need a register of a certain class, we
    // just take the next available one.
    std::map<unsigned, unsigned> RegsUsed;
    std::map<const TargetRegisterClass*, unsigned> RegClassIdx;

    RegAllocSimple(TargetMachine &tm) : TM(tm), CurrMBB(0), maxOffset(0),
                                        RegInfo(tm.getRegisterInfo()),
                                        ByteAlignment(4)
    {
      // build reverse mapping for physReg -> register class
      RegInfo->buildReg2RegClassMap(PhysReg2RegClassMap);

      RegsUsed[RegInfo->getFramePointer()] = 1;
      RegsUsed[RegInfo->getStackPointer()] = 1;

      cleanupAfterFunction();
    }

    bool isAvailableReg(unsigned Reg) {
      // assert(Reg < MRegisterInfo::FirstVirtualReg && "...");
      return RegsUsed.find(Reg) == RegsUsed.end();
    }

    ///
    unsigned allocateStackSpaceFor(unsigned VirtReg,
                                   const TargetRegisterClass *regClass);

    /// Given size (in bytes), returns a register that is currently unused
    /// Side effect: marks that register as being used until manually cleared
    unsigned getFreeReg(unsigned virtualReg);

    /// Returns all `borrowed' registers back to the free pool
    void clearAllRegs() {
        RegClassIdx.clear();
    }

    /// Invalidates any references, real or implicit, to physical registers
    ///
    void invalidatePhysRegs(const MachineInstr *MI) {
      unsigned Opcode = MI->getOpcode();
      const MachineInstrInfo &MII = TM.getInstrInfo();
      const MachineInstrDescriptor &Desc = MII.get(Opcode);
      const unsigned *regs = Desc.ImplicitUses;
      while (*regs)
        RegsUsed[*regs++] = 1;

      regs = Desc.ImplicitDefs;
      while (*regs)
        RegsUsed[*regs++] = 1;
    }

    void cleanupAfterFunction() {
      RegMap.clear();
      SSA2PhysRegMap.clear();
      NumBytesAllocated = ByteAlignment;
    }

    /// Moves value from memory into that register
    MachineBasicBlock::iterator
    moveUseToReg (MachineBasicBlock *MBB,
                  MachineBasicBlock::iterator I, unsigned VirtReg,
                  unsigned &PhysReg);

    /// Saves reg value on the stack (maps virtual register to stack value)
    MachineBasicBlock::iterator
    saveVirtRegToStack (MachineBasicBlock *MBB,
                        MachineBasicBlock::iterator I, unsigned VirtReg,
                        unsigned PhysReg);

    MachineBasicBlock::iterator
    savePhysRegToStack (MachineBasicBlock *MBB,
                        MachineBasicBlock::iterator I, unsigned PhysReg);

    /// runOnFunction - Top level implementation of instruction selection for
    /// the entire function.
    ///
    bool runOnMachineFunction(MachineFunction &Fn);

    bool runOnFunction(Function &Fn) {
      return runOnMachineFunction(MachineFunction::get(&Fn));
    }
  };

}

unsigned RegAllocSimple::allocateStackSpaceFor(unsigned VirtReg,
                                            const TargetRegisterClass *regClass)
{
  if (RegMap.find(VirtReg) == RegMap.end()) {
#if 0
    unsigned size = regClass->getDataSize();
    unsigned over = NumBytesAllocated - (NumBytesAllocated % ByteAlignment);
    if (size >= ByteAlignment - over) {
      // need to pad by (ByteAlignment - over)
      NumBytesAllocated += ByteAlignment - over;
    }
    RegMap[VirtReg] = NumBytesAllocated;
    NumBytesAllocated += size;
#endif
    // FIXME: forcing each arg to take 4 bytes on the stack
    RegMap[VirtReg] = NumBytesAllocated;
    NumBytesAllocated += ByteAlignment;
  }
  return RegMap[VirtReg];
}

unsigned RegAllocSimple::getFreeReg(unsigned virtualReg) {
  const TargetRegisterClass* regClass = MF->getRegClass(virtualReg);
  unsigned physReg;
  assert(regClass);
  if (RegClassIdx.find(regClass) != RegClassIdx.end()) {
    unsigned regIdx = RegClassIdx[regClass]++;
    assert(regIdx < regClass->getNumRegs() && "Not enough registers!");
    physReg = regClass->getRegister(regIdx);
  } else {
    physReg = regClass->getRegister(0);
    // assert(physReg < regClass->getNumRegs() && "No registers in class!");
    RegClassIdx[regClass] = 1;
  }

  if (isAvailableReg(physReg))
    return physReg;
  else {
    return getFreeReg(virtualReg);
  }
}

MachineBasicBlock::iterator
RegAllocSimple::moveUseToReg (MachineBasicBlock *MBB,
                              MachineBasicBlock::iterator I,
                              unsigned VirtReg, unsigned &PhysReg)
{
  const TargetRegisterClass* regClass = MF->getRegClass(VirtReg);
  assert(regClass);

  unsigned stackOffset = allocateStackSpaceFor(VirtReg, regClass);
  PhysReg = getFreeReg(VirtReg);

  // Add move instruction(s)
  return RegInfo->loadRegOffset2Reg(MBB, I, PhysReg,
                                    RegInfo->getFramePointer(),
                                    -stackOffset, regClass->getDataSize());
}

MachineBasicBlock::iterator
RegAllocSimple::saveVirtRegToStack (MachineBasicBlock *MBB,
                                    MachineBasicBlock::iterator I,
                                    unsigned VirtReg, unsigned PhysReg)
{
  const TargetRegisterClass* regClass = MF->getRegClass(VirtReg);
  assert(regClass);

  unsigned stackOffset = allocateStackSpaceFor(VirtReg, regClass);

  // Add move instruction(s)
  return RegInfo->storeReg2RegOffset(MBB, I, PhysReg,
                                     RegInfo->getFramePointer(),
                                     -stackOffset, regClass->getDataSize());
}

MachineBasicBlock::iterator
RegAllocSimple::savePhysRegToStack (MachineBasicBlock *MBB,
                                    MachineBasicBlock::iterator I,
                                    unsigned PhysReg)
{
  const TargetRegisterClass* regClass = MF->getRegClass(PhysReg);
  assert(regClass);

  unsigned offset = allocateStackSpaceFor(PhysReg, regClass);

  // Add move instruction(s)
  return RegInfo->storeReg2RegOffset(MBB, I, PhysReg,
                                     RegInfo->getFramePointer(),
                                     offset, regClass->getDataSize());
}

bool RegAllocSimple::runOnMachineFunction(MachineFunction &Fn) {
  cleanupAfterFunction();

  unsigned virtualReg, physReg;
  DEBUG(std::cerr << "Machine Function " << "\n");
  MF = &Fn;

  for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end();
       MBB != MBBe; ++MBB)
  {
    CurrMBB = &(*MBB);

    // Handle PHI instructions specially: add moves to each pred block
    while (MBB->front()->getOpcode() == 0) {
      MachineInstr *MI = MBB->front();
      // get rid of the phi
      MBB->erase(MBB->begin());

      // a preliminary pass that will invalidate any registers that
      // are used by the instruction (including implicit uses)
      invalidatePhysRegs(MI);

      DEBUG(std::cerr << "num invalid regs: " << RegsUsed.size() << "\n");

      DEBUG(std::cerr << "num ops: " << MI->getNumOperands() << "\n");
      MachineOperand &targetReg = MI->getOperand(0);

      // If it's a virtual register, allocate a physical one
      // otherwise, just use whatever register is there now
      // note: it MUST be a register -- we're assigning to it
      virtualReg = (unsigned) targetReg.getAllocatedRegNum();
      if (targetReg.isVirtualRegister()) {
        physReg = getFreeReg(virtualReg);
      } else {
        physReg = virtualReg;
      }

      // Find the register class of the target register: should be the
      // same as the values we're trying to store there
      const TargetRegisterClass* regClass = PhysReg2RegClassMap[physReg];
      assert(regClass && "Target register class not found!");
      unsigned dataSize = regClass->getDataSize();

      for (int i = MI->getNumOperands() - 1; i >= 2; i-=2) {
        MachineOperand &opVal = MI->getOperand(i-1);

        // Get the MachineBasicBlock equivalent of the BasicBlock that is the
        // source path the phi
        MachineBasicBlock *opBlock = MI->getOperand(i).getMachineBasicBlock();
        MachineBasicBlock::iterator opI = opBlock->end();
        MachineInstr *opMI = *(--opI);
        const MachineInstrInfo &MII = TM.getInstrInfo();
        // must backtrack over ALL the branches in the previous block, until no more
        while ((MII.isBranch(opMI->getOpcode()) || MII.isReturn(opMI->getOpcode()))
               && opI != opBlock->begin())
        {
          opMI = *(--opI);
        }
        // move back to the first branch instruction so new instructions
        // are inserted right in front of it and not in front of a non-branch
        ++opI;

        // Retrieve the constant value from this op, move it to target
        // register of the phi
        if (opVal.getType() == MachineOperand::MO_SignExtendedImmed ||
            opVal.getType() == MachineOperand::MO_UnextendedImmed)
        {
          opI = RegInfo->moveImm2Reg(opBlock, opI, physReg,
                                     (unsigned) opVal.getImmedValue(),
                                     dataSize);
          saveVirtRegToStack(opBlock, opI, virtualReg, physReg);
        } else {
          // Allocate a physical register and add a move in the BB
          unsigned opVirtualReg = (unsigned) opVal.getAllocatedRegNum();
          unsigned opPhysReg; // = getFreeReg(opVirtualReg);
          opI = moveUseToReg(opBlock, opI, opVirtualReg, physReg);
          //opI = RegInfo->moveReg2Reg(opBlock, opI, physReg, opPhysReg,
          //                           dataSize);
          // Save that register value to the stack of the TARGET REG
          saveVirtRegToStack(opBlock, opI, virtualReg, physReg);
        }

        // make regs available to other instructions
        clearAllRegs();
      }

      // really delete the instruction
      delete MI;
    }

    //loop over each basic block
    for (MachineBasicBlock::iterator I = MBB->begin(); I != MBB->end(); ++I)
    {
      MachineInstr *MI = *I;

      // a preliminary pass that will invalidate any registers that
      // are used by the instruction (including implicit uses)
      invalidatePhysRegs(MI);

      // Loop over uses, move from memory into registers
      for (int i = MI->getNumOperands() - 1; i >= 0; --i) {
        MachineOperand &op = MI->getOperand(i);

        if (op.getType() == MachineOperand::MO_SignExtendedImmed ||
            op.getType() == MachineOperand::MO_UnextendedImmed)
        {
          DEBUG(std::cerr << "const\n");
        } else if (op.isVirtualRegister()) {
          virtualReg = (unsigned) op.getAllocatedRegNum();
          DEBUG(std::cerr << "op: " << op << "\n");
          DEBUG(std::cerr << "\t inst[" << i << "]: ";
                MI->print(std::cerr, TM));

          // make sure the same virtual register maps to the same physical
          // register in any given instruction
          if (VirtReg2PhysRegMap.find(virtualReg) != VirtReg2PhysRegMap.end()) {
            physReg = VirtReg2PhysRegMap[virtualReg];
          } else {
            if (op.opIsDef()) {
              if (TM.getInstrInfo().isTwoAddrInstr(MI->getOpcode()) && i == 0) {
                // must be same register number as the first operand
                // This maps a = b + c into b += c, and saves b into a's spot
                physReg = (unsigned) MI->getOperand(1).getAllocatedRegNum();
              } else {
                physReg = getFreeReg(virtualReg);
              }
              MachineBasicBlock::iterator J = I;
              J = saveVirtRegToStack(CurrMBB, ++J, virtualReg, physReg);
              I = --J;
            } else {
              I = moveUseToReg(CurrMBB, I, virtualReg, physReg);
            }
            VirtReg2PhysRegMap[virtualReg] = physReg;
          }
          MI->SetMachineOperandReg(i, physReg);
          DEBUG(std::cerr << "virt: " << virtualReg <<
                ", phys: " << op.getAllocatedRegNum() << "\n");
        }
      }

      clearAllRegs();
      VirtReg2PhysRegMap.clear();
    }

  }

  // add prologue we should preserve callee-save registers...
  MachineFunction::iterator Fi = Fn.begin();
  MachineBasicBlock *MBB = Fi;
  MachineBasicBlock::iterator MBBi = MBB->begin();
  RegInfo->emitPrologue(MBB, MBBi, NumBytesAllocated);

  // add epilogue to restore the callee-save registers
  // loop over the basic block
  for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end();
       MBB != MBBe; ++MBB)
  {
    // check if last instruction is a RET
    MachineBasicBlock::iterator I = (*MBB).end();
    MachineInstr *MI = *(--I);
    const MachineInstrInfo &MII = TM.getInstrInfo();
    if (MII.isReturn(MI->getOpcode())) {
      // this block has a return instruction, add epilogue
      RegInfo->emitEpilogue(MBB, I, NumBytesAllocated);
    }
  }

  return false;  // We never modify the LLVM itself.
}

Pass *createSimpleX86RegisterAllocator(TargetMachine &TM) {
  return new RegAllocSimple(TM);
}
<commit_msg>Remove extraneous #includes, perform FIXME<commit_after>//===-- RegAllocSimple.cpp - A simple generic register allocator --- ------===//
//
// This file implements a simple register allocator. *Very* simple.
//
//===----------------------------------------------------------------------===//

#include "llvm/Function.h"
#include "llvm/iTerminators.h"
#include "llvm/Type.h"
#include "llvm/Constants.h"
#include "llvm/Pass.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/Target/MachineInstrInfo.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/InstVisitor.h"
#include "Support/Statistic.h"

namespace {
  struct RegAllocSimple : public FunctionPass {
    TargetMachine &TM;
    MachineBasicBlock *CurrMBB;
    MachineFunction *MF;
    unsigned maxOffset;
    const MRegisterInfo *RegInfo;
    unsigned NumBytesAllocated, ByteAlignment;

    // Maps SSA Regs => offsets on the stack where these values are stored
    std::map<unsigned, unsigned> VirtReg2OffsetMap;

    // Maps SSA Regs => physical regs
    std::map<unsigned, unsigned> SSA2PhysRegMap;

    // Maps physical register to their register classes
    std::map<unsigned, const TargetRegisterClass*> PhysReg2RegClassMap;

    // Made to combat the incorrect allocation of r2 = add r1, r1
    std::map<unsigned, unsigned> VirtReg2PhysRegMap;

    // Maps RegClass => which index we can take a register from. Since this is a
    // simple register allocator, when we need a register of a certain class, we
    // just take the next available one.
    std::map<unsigned, unsigned> RegsUsed;
    std::map<const TargetRegisterClass*, unsigned> RegClassIdx;

    RegAllocSimple(TargetMachine &tm) : TM(tm), CurrMBB(0), maxOffset(0),
                                        RegInfo(tm.getRegisterInfo()),
                                        ByteAlignment(4)
    {
      // build reverse mapping for physReg -> register class
      RegInfo->buildReg2RegClassMap(PhysReg2RegClassMap);

      RegsUsed[RegInfo->getFramePointer()] = 1;
      RegsUsed[RegInfo->getStackPointer()] = 1;

      cleanupAfterFunction();
    }

    bool isAvailableReg(unsigned Reg) {
      // assert(Reg < MRegisterInfo::FirstVirtualReg && "...");
      return RegsUsed.find(Reg) == RegsUsed.end();
    }

    ///
    unsigned allocateStackSpaceFor(unsigned VirtReg,
                                   const TargetRegisterClass *regClass);

    /// Given size (in bytes), returns a register that is currently unused
    /// Side effect: marks that register as being used until manually cleared
    unsigned getFreeReg(unsigned virtualReg);

    /// Returns all `borrowed' registers back to the free pool
    void clearAllRegs() {
        RegClassIdx.clear();
    }

    /// Invalidates any references, real or implicit, to physical registers
    ///
    void invalidatePhysRegs(const MachineInstr *MI) {
      unsigned Opcode = MI->getOpcode();
      const MachineInstrInfo &MII = TM.getInstrInfo();
      const MachineInstrDescriptor &Desc = MII.get(Opcode);
      const unsigned *regs = Desc.ImplicitUses;
      while (*regs)
        RegsUsed[*regs++] = 1;

      regs = Desc.ImplicitDefs;
      while (*regs)
        RegsUsed[*regs++] = 1;
    }

    void cleanupAfterFunction() {
      VirtReg2OffsetMap.clear();
      SSA2PhysRegMap.clear();
      NumBytesAllocated = ByteAlignment;
    }

    /// Moves value from memory into that register
    MachineBasicBlock::iterator
    moveUseToReg (MachineBasicBlock *MBB,
                  MachineBasicBlock::iterator I, unsigned VirtReg,
                  unsigned &PhysReg);

    /// Saves reg value on the stack (maps virtual register to stack value)
    MachineBasicBlock::iterator
    saveVirtRegToStack (MachineBasicBlock *MBB,
                        MachineBasicBlock::iterator I, unsigned VirtReg,
                        unsigned PhysReg);

    MachineBasicBlock::iterator
    savePhysRegToStack (MachineBasicBlock *MBB,
                        MachineBasicBlock::iterator I, unsigned PhysReg);

    /// runOnFunction - Top level implementation of instruction selection for
    /// the entire function.
    ///
    bool runOnMachineFunction(MachineFunction &Fn);

    bool runOnFunction(Function &Fn) {
      return runOnMachineFunction(MachineFunction::get(&Fn));
    }
  };

}

unsigned RegAllocSimple::allocateStackSpaceFor(unsigned VirtReg,
                                            const TargetRegisterClass *regClass)
{
  if (VirtReg2OffsetMap.find(VirtReg) == VirtReg2OffsetMap.end()) {
#if 0
    unsigned size = regClass->getDataSize();
    unsigned over = NumBytesAllocated - (NumBytesAllocated % ByteAlignment);
    if (size >= ByteAlignment - over) {
      // need to pad by (ByteAlignment - over)
      NumBytesAllocated += ByteAlignment - over;
    }
    VirtReg2OffsetMap[VirtReg] = NumBytesAllocated;
    NumBytesAllocated += size;
#endif
    // FIXME: forcing each arg to take 4 bytes on the stack
    VirtReg2OffsetMap[VirtReg] = NumBytesAllocated;
    NumBytesAllocated += ByteAlignment;
  }
  return VirtReg2OffsetMap[VirtReg];
}

unsigned RegAllocSimple::getFreeReg(unsigned virtualReg) {
  const TargetRegisterClass* regClass = MF->getRegClass(virtualReg);
  unsigned physReg;
  assert(regClass);
  if (RegClassIdx.find(regClass) != RegClassIdx.end()) {
    unsigned regIdx = RegClassIdx[regClass]++;
    assert(regIdx < regClass->getNumRegs() && "Not enough registers!");
    physReg = regClass->getRegister(regIdx);
  } else {
    physReg = regClass->getRegister(0);
    // assert(physReg < regClass->getNumRegs() && "No registers in class!");
    RegClassIdx[regClass] = 1;
  }

  if (isAvailableReg(physReg))
    return physReg;
  else {
    return getFreeReg(virtualReg);
  }
}

MachineBasicBlock::iterator
RegAllocSimple::moveUseToReg (MachineBasicBlock *MBB,
                              MachineBasicBlock::iterator I,
                              unsigned VirtReg, unsigned &PhysReg)
{
  const TargetRegisterClass* regClass = MF->getRegClass(VirtReg);
  assert(regClass);

  unsigned stackOffset = allocateStackSpaceFor(VirtReg, regClass);
  PhysReg = getFreeReg(VirtReg);

  // Add move instruction(s)
  return RegInfo->loadRegOffset2Reg(MBB, I, PhysReg,
                                    RegInfo->getFramePointer(),
                                    -stackOffset, regClass->getDataSize());
}

MachineBasicBlock::iterator
RegAllocSimple::saveVirtRegToStack (MachineBasicBlock *MBB,
                                    MachineBasicBlock::iterator I,
                                    unsigned VirtReg, unsigned PhysReg)
{
  const TargetRegisterClass* regClass = MF->getRegClass(VirtReg);
  assert(regClass);

  unsigned stackOffset = allocateStackSpaceFor(VirtReg, regClass);

  // Add move instruction(s)
  return RegInfo->storeReg2RegOffset(MBB, I, PhysReg,
                                     RegInfo->getFramePointer(),
                                     -stackOffset, regClass->getDataSize());
}

MachineBasicBlock::iterator
RegAllocSimple::savePhysRegToStack (MachineBasicBlock *MBB,
                                    MachineBasicBlock::iterator I,
                                    unsigned PhysReg)
{
  const TargetRegisterClass* regClass = MF->getRegClass(PhysReg);
  assert(regClass);

  unsigned offset = allocateStackSpaceFor(PhysReg, regClass);

  // Add move instruction(s)
  return RegInfo->storeReg2RegOffset(MBB, I, PhysReg,
                                     RegInfo->getFramePointer(),
                                     offset, regClass->getDataSize());
}

bool RegAllocSimple::runOnMachineFunction(MachineFunction &Fn) {
  cleanupAfterFunction();

  unsigned virtualReg, physReg;
  DEBUG(std::cerr << "Machine Function " << "\n");
  MF = &Fn;

  for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end();
       MBB != MBBe; ++MBB)
  {
    CurrMBB = &(*MBB);

    // Handle PHI instructions specially: add moves to each pred block
    while (MBB->front()->getOpcode() == 0) {
      MachineInstr *MI = MBB->front();
      // get rid of the phi
      MBB->erase(MBB->begin());

      // a preliminary pass that will invalidate any registers that
      // are used by the instruction (including implicit uses)
      invalidatePhysRegs(MI);

      DEBUG(std::cerr << "num invalid regs: " << RegsUsed.size() << "\n");

      DEBUG(std::cerr << "num ops: " << MI->getNumOperands() << "\n");
      MachineOperand &targetReg = MI->getOperand(0);

      // If it's a virtual register, allocate a physical one
      // otherwise, just use whatever register is there now
      // note: it MUST be a register -- we're assigning to it
      virtualReg = (unsigned) targetReg.getAllocatedRegNum();
      if (targetReg.isVirtualRegister()) {
        physReg = getFreeReg(virtualReg);
      } else {
        physReg = virtualReg;
      }

      // Find the register class of the target register: should be the
      // same as the values we're trying to store there
      const TargetRegisterClass* regClass = PhysReg2RegClassMap[physReg];
      assert(regClass && "Target register class not found!");
      unsigned dataSize = regClass->getDataSize();

      for (int i = MI->getNumOperands() - 1; i >= 2; i-=2) {
        MachineOperand &opVal = MI->getOperand(i-1);

        // Get the MachineBasicBlock equivalent of the BasicBlock that is the
        // source path the phi
        MachineBasicBlock *opBlock = MI->getOperand(i).getMachineBasicBlock();
        MachineBasicBlock::iterator opI = opBlock->end();
        MachineInstr *opMI = *(--opI);
        const MachineInstrInfo &MII = TM.getInstrInfo();
        // must backtrack over ALL the branches in the previous block, until no more
        while ((MII.isBranch(opMI->getOpcode()) || MII.isReturn(opMI->getOpcode()))
               && opI != opBlock->begin())
        {
          opMI = *(--opI);
        }
        // move back to the first branch instruction so new instructions
        // are inserted right in front of it and not in front of a non-branch
        ++opI;

        // Retrieve the constant value from this op, move it to target
        // register of the phi
        if (opVal.getType() == MachineOperand::MO_SignExtendedImmed ||
            opVal.getType() == MachineOperand::MO_UnextendedImmed)
        {
          opI = RegInfo->moveImm2Reg(opBlock, opI, physReg,
                                     (unsigned) opVal.getImmedValue(),
                                     dataSize);
          saveVirtRegToStack(opBlock, opI, virtualReg, physReg);
        } else {
          // Allocate a physical register and add a move in the BB
          unsigned opVirtualReg = (unsigned) opVal.getAllocatedRegNum();
          unsigned opPhysReg; // = getFreeReg(opVirtualReg);
          opI = moveUseToReg(opBlock, opI, opVirtualReg, physReg);
          //opI = RegInfo->moveReg2Reg(opBlock, opI, physReg, opPhysReg,
          //                           dataSize);
          // Save that register value to the stack of the TARGET REG
          saveVirtRegToStack(opBlock, opI, virtualReg, physReg);
        }

        // make regs available to other instructions
        clearAllRegs();
      }

      // really delete the instruction
      delete MI;
    }

    //loop over each basic block
    for (MachineBasicBlock::iterator I = MBB->begin(); I != MBB->end(); ++I)
    {
      MachineInstr *MI = *I;

      // a preliminary pass that will invalidate any registers that
      // are used by the instruction (including implicit uses)
      invalidatePhysRegs(MI);

      // Loop over uses, move from memory into registers
      for (int i = MI->getNumOperands() - 1; i >= 0; --i) {
        MachineOperand &op = MI->getOperand(i);

        if (op.getType() == MachineOperand::MO_SignExtendedImmed ||
            op.getType() == MachineOperand::MO_UnextendedImmed)
        {
          DEBUG(std::cerr << "const\n");
        } else if (op.isVirtualRegister()) {
          virtualReg = (unsigned) op.getAllocatedRegNum();
          DEBUG(std::cerr << "op: " << op << "\n");
          DEBUG(std::cerr << "\t inst[" << i << "]: ";
                MI->print(std::cerr, TM));

          // make sure the same virtual register maps to the same physical
          // register in any given instruction
          if (VirtReg2PhysRegMap.find(virtualReg) != VirtReg2PhysRegMap.end()) {
            physReg = VirtReg2PhysRegMap[virtualReg];
          } else {
            if (op.opIsDef()) {
              if (TM.getInstrInfo().isTwoAddrInstr(MI->getOpcode()) && i == 0) {
                // must be same register number as the first operand
                // This maps a = b + c into b += c, and saves b into a's spot
                physReg = (unsigned) MI->getOperand(1).getAllocatedRegNum();
              } else {
                physReg = getFreeReg(virtualReg);
              }
              MachineBasicBlock::iterator J = I;
              J = saveVirtRegToStack(CurrMBB, ++J, virtualReg, physReg);
              I = --J;
            } else {
              I = moveUseToReg(CurrMBB, I, virtualReg, physReg);
            }
            VirtReg2PhysRegMap[virtualReg] = physReg;
          }
          MI->SetMachineOperandReg(i, physReg);
          DEBUG(std::cerr << "virt: " << virtualReg <<
                ", phys: " << op.getAllocatedRegNum() << "\n");
        }
      }

      clearAllRegs();
      VirtReg2PhysRegMap.clear();
    }

  }

  // add prologue we should preserve callee-save registers...
  MachineFunction::iterator Fi = Fn.begin();
  MachineBasicBlock *MBB = Fi;
  MachineBasicBlock::iterator MBBi = MBB->begin();
  RegInfo->emitPrologue(MBB, MBBi, NumBytesAllocated);

  // add epilogue to restore the callee-save registers
  // loop over the basic block
  for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end();
       MBB != MBBe; ++MBB)
  {
    // check if last instruction is a RET
    MachineBasicBlock::iterator I = (*MBB).end();
    MachineInstr *MI = *(--I);
    const MachineInstrInfo &MII = TM.getInstrInfo();
    if (MII.isReturn(MI->getOpcode())) {
      // this block has a return instruction, add epilogue
      RegInfo->emitEpilogue(MBB, I, NumBytesAllocated);
    }
  }

  return false;  // We never modify the LLVM itself.
}

Pass *createSimpleX86RegisterAllocator(TargetMachine &TM) {
  return new RegAllocSimple(TM);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: frmbase.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: dr $ $Date: 2002-01-08 07:23:24 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

#ifdef PCH
#include "filt_pch.hxx"
#endif

#pragma hdrstop

#include "formel.hxx"

_ScRangeList::~_ScRangeList()
{
    ScRange*    p = ( ScRange* ) First();

    while( p )
    {
        delete p;
        p = ( ScRange* ) Next();
    }
}

_ScRangeListTabs::_ScRangeListTabs( void )
{
    ppTabLists = new _ScRangeList*[ MAXTAB + 1 ];

    for( UINT16 n = 0 ; n <= MAXTAB ; n++ )
        ppTabLists[ n ] = NULL;

    bHasRanges = FALSE;
    pAct = NULL;
    nAct = 0;
}

_ScRangeListTabs::~_ScRangeListTabs()
{
    if( bHasRanges )
    {
        for( UINT16 n = 0 ; n <= MAXTAB ; n++ )
        {
            if( ppTabLists[ n ] )
                delete ppTabLists[ n ];
        }
    }

    delete[] ppTabLists;
}

void _ScRangeListTabs::Append( SingleRefData a, const BOOL b )
{
    if( b )
    {
        if( a.nTab > MAXTAB )
            a.nTab = MAXTAB;

        if( a.nCol > MAXCOL )
            a.nCol = MAXCOL;

        if( a.nRow > MAXROW )
            a.nRow = MAXROW;
    }
    else
    {
        DBG_ASSERT( a.nTab <= MAXTAB, "-_ScRangeListTabs::Append(): Luegen haben kurze Abstuerze!" );
    }

    bHasRanges = TRUE;

    _ScRangeList*   p = ppTabLists[ a.nTab ];

    if( !p )
        p = ppTabLists[ a.nTab ] = new _ScRangeList;

    p->Append( a );
}

void _ScRangeListTabs::Append( ComplRefData a, const BOOL b )
{
    if( b )
    {
        // #96263# ignore 3D ranges
        if( a.Ref1.nTab != a.Ref2.nTab )
            return;

        INT16&  rTab = a.Ref1.nTab;
        if( rTab > MAXTAB )
            rTab = MAXTAB;
        else if( rTab < 0 )
            rTab = 0;

        INT16&  rCol1 = a.Ref1.nCol;
        if( rCol1 > MAXCOL )
            rCol1 = MAXCOL;
        else if( rCol1 < 0 )
            rCol1 = 0;

        INT16&  rRow1 = a.Ref1.nRow;
        if( rRow1 > MAXROW )
            rRow1 = MAXROW;
        else if( rRow1 < 0 )
            rRow1 = 0;

        INT16&  rCol2 = a.Ref2.nCol;
        if( rCol2 > MAXCOL )
            rCol2 = MAXCOL;
        else if( rCol2 < 0 )
            rCol2 = 0;

        INT16&  rRow2 = a.Ref2.nRow;
        if( rRow2 > MAXROW )
            rRow2 = MAXROW;
        else if( rRow2 < 0 )
            rRow2 = 0;
    }
    else
    {
        DBG_ASSERT( a.Ref1.nTab <= MAXTAB,
            "-_ScRangeListTabs::Append(): Luegen haben kurze Abstuerze!" );
        DBG_ASSERT( a.Ref1.nTab == a.Ref2.nTab,
            "+_ScRangeListTabs::Append(): 3D-Ranges werden in SC nicht unterstuetzt!" );
    }

    bHasRanges = TRUE;

    _ScRangeList*   p = ppTabLists[ a.Ref1.nTab ];

    if( !p )
        p = ppTabLists[ a.Ref1.nTab ] = new _ScRangeList;

    p->Append( a );
}

const ScRange* _ScRangeListTabs::First( const UINT16 n )
{
    DBG_ASSERT( n <= MAXTAB, "-_ScRangeListTabs::First(): Und tschuessssssss!" );

    if( ppTabLists[ n ] )
    {
        pAct = ppTabLists[ n ];
        nAct = n;
        return pAct->First();
    }
    else
    {
        pAct = NULL;
        nAct = 0;
        return NULL;
    }
}

const ScRange* _ScRangeListTabs::Next( void )
{
    if( pAct )
        return pAct->Next();
    else
        return NULL;
}

ConverterBase::ConverterBase( UINT16 nNewBuffer ) :
    aPool(),
    aStack(),
    aEingPos( 0, 0, 0 ),
    nBufferSize( nNewBuffer ),
    eStatus( ConvOK )
{
    DBG_ASSERT( nNewBuffer > 0, "ConverterBase::ConverterBase - nNewBuffer == 0!" );
    pBuffer = new sal_Char[ nNewBuffer ];
}

ConverterBase::~ConverterBase()
{
    delete[] pBuffer;
}

void ConverterBase::Reset()
{
    eStatus = ConvOK;
    aPool.Reset();
    aStack.Reset();
}

ExcelConverterBase::ExcelConverterBase( XclImpStream &rStr, UINT16 nNewBuffer ) :
    ConverterBase( nNewBuffer ),
    aIn( rStr )
{
}

ExcelConverterBase::~ExcelConverterBase()
{
}

void ExcelConverterBase::Reset( ScAddress aNewEingPos )
{
    ConverterBase::Reset();
    aEingPos = aNewEingPos;
}

void ExcelConverterBase::Reset()
{
    ConverterBase::Reset();
    aEingPos.Set( 0, 0, 0 );
}

LotusConverterBase::LotusConverterBase( SvStream &rStr, UINT16 nNewBuffer ) :
    ConverterBase( nNewBuffer ),
    aIn( rStr ),
    nBytesLeft( 0 )
{
}

LotusConverterBase::~LotusConverterBase()
{
}

void LotusConverterBase::Reset( INT32 nLen, ScAddress aNewEingPos )
{
    ConverterBase::Reset();
    nBytesLeft = nLen;
    aEingPos = aNewEingPos;
}

void LotusConverterBase::Reset( INT32 nLen )
{
    ConverterBase::Reset();
    nBytesLeft = nLen;
    aEingPos.Set( 0, 0, 0 );
}

void LotusConverterBase::Reset( ScAddress aNewEingPos )
{
    ConverterBase::Reset();
    nBytesLeft = 0;
    aEingPos = aNewEingPos;
}

<commit_msg>INTEGRATION: CWS rowlimit (1.3.320); FILE MERGED 2004/03/25 21:35:58 er 1.3.320.2: #i1967# use ValidCol,ValidRow,ValidTab 2004/03/19 20:55:16 er 1.3.320.1: #i1967# type correctness<commit_after>/*************************************************************************
 *
 *  $RCSfile: frmbase.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: obo $ $Date: 2004-06-04 10:44:14 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

#ifdef PCH
#include "filt_pch.hxx"
#endif

#pragma hdrstop

#include "formel.hxx"

_ScRangeList::~_ScRangeList()
{
    ScRange*    p = ( ScRange* ) First();

    while( p )
    {
        delete p;
        p = ( ScRange* ) Next();
    }
}

_ScRangeListTabs::_ScRangeListTabs( void )
{
    ppTabLists = new _ScRangeList*[ MAXTAB + 1 ];

    for( UINT16 n = 0 ; n <= MAXTAB ; n++ )
        ppTabLists[ n ] = NULL;

    bHasRanges = FALSE;
    pAct = NULL;
    nAct = 0;
}

_ScRangeListTabs::~_ScRangeListTabs()
{
    if( bHasRanges )
    {
        for( UINT16 n = 0 ; n <= MAXTAB ; n++ )
        {
            if( ppTabLists[ n ] )
                delete ppTabLists[ n ];
        }
    }

    delete[] ppTabLists;
}

void _ScRangeListTabs::Append( SingleRefData a, const BOOL b )
{
    if( b )
    {
        if( a.nTab > MAXTAB )
            a.nTab = MAXTAB;

        if( a.nCol > MAXCOL )
            a.nCol = MAXCOL;

        if( a.nRow > MAXROW )
            a.nRow = MAXROW;
    }
    else
    {
        DBG_ASSERT( ValidTab(a.nTab), "-_ScRangeListTabs::Append(): Luegen haben kurze Abstuerze!" );
    }

    bHasRanges = TRUE;

    _ScRangeList*   p = ppTabLists[ a.nTab ];

    if( !p )
        p = ppTabLists[ a.nTab ] = new _ScRangeList;

    p->Append( a );
}

void _ScRangeListTabs::Append( ComplRefData a, const BOOL b )
{
    if( b )
    {
        // #96263# ignore 3D ranges
        if( a.Ref1.nTab != a.Ref2.nTab )
            return;

        SCsTAB& rTab = a.Ref1.nTab;
        if( rTab > MAXTAB )
            rTab = MAXTAB;
        else if( rTab < 0 )
            rTab = 0;

        SCsCOL& rCol1 = a.Ref1.nCol;
        if( rCol1 > MAXCOL )
            rCol1 = MAXCOL;
        else if( rCol1 < 0 )
            rCol1 = 0;

        SCsROW& rRow1 = a.Ref1.nRow;
        if( rRow1 > MAXROW )
            rRow1 = MAXROW;
        else if( rRow1 < 0 )
            rRow1 = 0;

        SCsCOL& rCol2 = a.Ref2.nCol;
        if( rCol2 > MAXCOL )
            rCol2 = MAXCOL;
        else if( rCol2 < 0 )
            rCol2 = 0;

        SCsROW& rRow2 = a.Ref2.nRow;
        if( rRow2 > MAXROW )
            rRow2 = MAXROW;
        else if( rRow2 < 0 )
            rRow2 = 0;
    }
    else
    {
        DBG_ASSERT( ValidTab(a.Ref1.nTab),
            "-_ScRangeListTabs::Append(): Luegen haben kurze Abstuerze!" );
        DBG_ASSERT( a.Ref1.nTab == a.Ref2.nTab,
            "+_ScRangeListTabs::Append(): 3D-Ranges werden in SC nicht unterstuetzt!" );
    }

    bHasRanges = TRUE;

    _ScRangeList*   p = ppTabLists[ a.Ref1.nTab ];

    if( !p )
        p = ppTabLists[ a.Ref1.nTab ] = new _ScRangeList;

    p->Append( a );
}

const ScRange* _ScRangeListTabs::First( const UINT16 n )
{
    DBG_ASSERT( ValidTab(n), "-_ScRangeListTabs::First(): Und tschuessssssss!" );

    if( ppTabLists[ n ] )
    {
        pAct = ppTabLists[ n ];
        nAct = n;
        return pAct->First();
    }
    else
    {
        pAct = NULL;
        nAct = 0;
        return NULL;
    }
}

const ScRange* _ScRangeListTabs::Next( void )
{
    if( pAct )
        return pAct->Next();
    else
        return NULL;
}

ConverterBase::ConverterBase( UINT16 nNewBuffer ) :
    aPool(),
    aStack(),
    aEingPos( 0, 0, 0 ),
    nBufferSize( nNewBuffer ),
    eStatus( ConvOK )
{
    DBG_ASSERT( nNewBuffer > 0, "ConverterBase::ConverterBase - nNewBuffer == 0!" );
    pBuffer = new sal_Char[ nNewBuffer ];
}

ConverterBase::~ConverterBase()
{
    delete[] pBuffer;
}

void ConverterBase::Reset()
{
    eStatus = ConvOK;
    aPool.Reset();
    aStack.Reset();
}

ExcelConverterBase::ExcelConverterBase( XclImpStream &rStr, UINT16 nNewBuffer ) :
    ConverterBase( nNewBuffer ),
    aIn( rStr )
{
}

ExcelConverterBase::~ExcelConverterBase()
{
}

void ExcelConverterBase::Reset( ScAddress aNewEingPos )
{
    ConverterBase::Reset();
    aEingPos = aNewEingPos;
}

void ExcelConverterBase::Reset()
{
    ConverterBase::Reset();
    aEingPos.Set( 0, 0, 0 );
}

LotusConverterBase::LotusConverterBase( SvStream &rStr, UINT16 nNewBuffer ) :
    ConverterBase( nNewBuffer ),
    aIn( rStr ),
    nBytesLeft( 0 )
{
}

LotusConverterBase::~LotusConverterBase()
{
}

void LotusConverterBase::Reset( INT32 nLen, ScAddress aNewEingPos )
{
    ConverterBase::Reset();
    nBytesLeft = nLen;
    aEingPos = aNewEingPos;
}

void LotusConverterBase::Reset( INT32 nLen )
{
    ConverterBase::Reset();
    nBytesLeft = nLen;
    aEingPos.Set( 0, 0, 0 );
}

void LotusConverterBase::Reset( ScAddress aNewEingPos )
{
    ConverterBase::Reset();
    nBytesLeft = 0;
    aEingPos = aNewEingPos;
}

<|endoftext|>


<commit_before><commit_msg>coverity#706047 Unintended sign extension<commit_after><|endoftext|>


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

#include "swift/Driver/DependencyGraph.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/YAMLParser.h"

using namespace swift;

namespace {
  using DependencyMaskTy = DependencyGraphImpl::DependencyMaskTy;
  enum class DependencyKind : DependencyMaskTy {
    Name = 1 << 0,
    Type = 1 << 1
  };

  enum class DependencyDirection : bool {
    Depends,
    Provides
  };
} // end anonymous namespace

static bool
parseDependencyFile(llvm::MemoryBuffer &buffer, bool providesOnly,
                    llvm::function_ref<void(StringRef, DependencyKind,
                                            DependencyDirection)> callback) {
  using namespace llvm;

  // FIXME: Switch to a format other than YAML.
  llvm::SourceMgr SM;
  yaml::Stream stream(buffer.getMemBufferRef(), SM);
  auto I = stream.begin();
  if (I == stream.end() || !I->getRoot())
    return true;

  auto *topLevelMap = dyn_cast<yaml::MappingNode>(I->getRoot());
  if (!topLevelMap)
    return !isa<yaml::NullNode>(I->getRoot());

  SmallString<64> scratch;
  // FIXME: LLVM's YAML support does incremental parsing in such a way that
  // for-range loops break.
  for (auto i = topLevelMap->begin(), e = topLevelMap->end(); i != e; ++i) {
    auto *key = cast<yaml::ScalarNode>(i->getKey());

    using KindPair = std::pair<DependencyKind, DependencyDirection>;

    KindPair dirAndKind = llvm::StringSwitch<KindPair>(key->getValue(scratch))
      .Case("top-level", std::make_pair(DependencyKind::Name,
                                        DependencyDirection::Depends))
      .Case("member-access", std::make_pair(DependencyKind::Type,
                                            DependencyDirection::Depends))
      .Case("provides", std::make_pair(DependencyKind::Name,
                                       DependencyDirection::Provides))
      .Case("nominals", std::make_pair(DependencyKind::Type,
                                       DependencyDirection::Provides));

    if (providesOnly && dirAndKind.second != DependencyDirection::Provides)
      continue;

    auto *entries = cast<yaml::SequenceNode>(i->getValue());
    for (const yaml::Node &rawEntry : *entries) {
      auto *entry = cast<yaml::ScalarNode>(&rawEntry);
      callback(entry->getValue(scratch), dirAndKind.first, dirAndKind.second);
    }
  }

  return false;
}

bool DependencyGraphImpl::loadFromPath(const void *node, StringRef path) {
  auto buffer = llvm::MemoryBuffer::getFile(path);
  if (!buffer)
    return true;
  return loadFromBuffer(node, *buffer.get());
}

bool DependencyGraphImpl::loadFromString(const void *node, StringRef data) {
  auto buffer = llvm::MemoryBuffer::getMemBuffer(data);
  return loadFromBuffer(node, *buffer);
}

bool DependencyGraphImpl::loadFromBuffer(const void *node,
                                         llvm::MemoryBuffer &buffer) {
  auto &provides = Provides[node];
  provides.clear();
  return parseDependencyFile(buffer, /*providesOnly=*/isMarked(node),
                             [this, node, &provides](StringRef name,
                                                     DependencyKind kind,
                                                     DependencyDirection dir) {
    auto kindAsMask = static_cast<DependencyMaskTy>(kind);
    switch (dir) {
    case DependencyDirection::Depends: {
      auto &entries = Dependencies[name];
      auto iter = std::find_if(entries.begin(), entries.end(),
                               [node](const DependencyPairTy &entry) -> bool {
        return node == entry.second;
      });
      if (iter == entries.end())
        entries.emplace_back(kindAsMask, node);
      else
        iter->first |= kindAsMask;
      break;
    }

    case DependencyDirection::Provides: {
      auto iter = std::find_if(provides.begin(), provides.end(),
                               [name](const ProvidesPairTy &entry) -> bool {
        return name == entry.second;
      });
      if (iter == provides.end())
        provides.emplace_back(kindAsMask, name);
      else
        iter->first |= kindAsMask;
      break;
    }
    }
  });
}

void
DependencyGraphImpl::markTransitive(SmallVectorImpl<const void *> &newlyMarked,
                                    const void *node) {
  assert(Provides.count(node) && "node is not in the graph");
  SmallVector<const void *, 16> worklist;

  auto addDependentsToWorklist = [&](const void *next) {
    auto allProvided = Provides.find(next);
    if (allProvided == Provides.end())
      return;

    for (const auto &provided : allProvided->second) {
      auto allDependents = Dependencies.find(provided.second);
      if (allDependents == Dependencies.end())
        continue;

      for (const auto &dependent : allDependents->second) {
        if ((provided.first & dependent.first) == 0)
          continue;
        if (isMarked(dependent.second))
          continue;
        worklist.push_back(dependent.second);
      }
    }
  };

  // Always mark through the starting node, even if it's already marked.
  Marked.insert(node);
  addDependentsToWorklist(node);

  while (!worklist.empty()) {
    const void *next = worklist.pop_back_val();
    if (!Marked.insert(next))
      continue;
    newlyMarked.push_back(next);
    addDependentsToWorklist(next);
  }
}
<commit_msg>[Driver] Handle null lists in the YAML dependencies file.<commit_after>//===--- DependencyGraph.cpp - Track intra-module dependencies ------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/Driver/DependencyGraph.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/YAMLParser.h"

using namespace swift;

namespace {
  using DependencyMaskTy = DependencyGraphImpl::DependencyMaskTy;
  enum class DependencyKind : DependencyMaskTy {
    Name = 1 << 0,
    Type = 1 << 1
  };

  enum class DependencyDirection : bool {
    Depends,
    Provides
  };
} // end anonymous namespace

static bool
parseDependencyFile(llvm::MemoryBuffer &buffer, bool providesOnly,
                    llvm::function_ref<void(StringRef, DependencyKind,
                                            DependencyDirection)> callback) {
  using namespace llvm;

  // FIXME: Switch to a format other than YAML.
  llvm::SourceMgr SM;
  yaml::Stream stream(buffer.getMemBufferRef(), SM);
  auto I = stream.begin();
  if (I == stream.end() || !I->getRoot())
    return true;

  auto *topLevelMap = dyn_cast<yaml::MappingNode>(I->getRoot());
  if (!topLevelMap)
    return !isa<yaml::NullNode>(I->getRoot());

  SmallString<64> scratch;
  // FIXME: LLVM's YAML support does incremental parsing in such a way that
  // for-range loops break.
  for (auto i = topLevelMap->begin(), e = topLevelMap->end(); i != e; ++i) {
    if (isa<yaml::NullNode>(i->getValue()))
      continue;

    auto *key = cast<yaml::ScalarNode>(i->getKey());

    using KindPair = std::pair<DependencyKind, DependencyDirection>;

    KindPair dirAndKind = llvm::StringSwitch<KindPair>(key->getValue(scratch))
      .Case("top-level", std::make_pair(DependencyKind::Name,
                                        DependencyDirection::Depends))
      .Case("member-access", std::make_pair(DependencyKind::Type,
                                            DependencyDirection::Depends))
      .Case("provides", std::make_pair(DependencyKind::Name,
                                       DependencyDirection::Provides))
      .Case("nominals", std::make_pair(DependencyKind::Type,
                                       DependencyDirection::Provides));

    if (providesOnly && dirAndKind.second != DependencyDirection::Provides)
      continue;

    auto *entries = cast<yaml::SequenceNode>(i->getValue());
    for (const yaml::Node &rawEntry : *entries) {
      auto *entry = cast<yaml::ScalarNode>(&rawEntry);
      callback(entry->getValue(scratch), dirAndKind.first, dirAndKind.second);
    }
  }

  return false;
}

bool DependencyGraphImpl::loadFromPath(const void *node, StringRef path) {
  auto buffer = llvm::MemoryBuffer::getFile(path);
  if (!buffer)
    return true;
  return loadFromBuffer(node, *buffer.get());
}

bool DependencyGraphImpl::loadFromString(const void *node, StringRef data) {
  auto buffer = llvm::MemoryBuffer::getMemBuffer(data);
  return loadFromBuffer(node, *buffer);
}

bool DependencyGraphImpl::loadFromBuffer(const void *node,
                                         llvm::MemoryBuffer &buffer) {
  auto &provides = Provides[node];
  provides.clear();
  return parseDependencyFile(buffer, /*providesOnly=*/isMarked(node),
                             [this, node, &provides](StringRef name,
                                                     DependencyKind kind,
                                                     DependencyDirection dir) {
    auto kindAsMask = static_cast<DependencyMaskTy>(kind);
    switch (dir) {
    case DependencyDirection::Depends: {
      auto &entries = Dependencies[name];
      auto iter = std::find_if(entries.begin(), entries.end(),
                               [node](const DependencyPairTy &entry) -> bool {
        return node == entry.second;
      });
      if (iter == entries.end())
        entries.emplace_back(kindAsMask, node);
      else
        iter->first |= kindAsMask;
      break;
    }

    case DependencyDirection::Provides: {
      auto iter = std::find_if(provides.begin(), provides.end(),
                               [name](const ProvidesPairTy &entry) -> bool {
        return name == entry.second;
      });
      if (iter == provides.end())
        provides.emplace_back(kindAsMask, name);
      else
        iter->first |= kindAsMask;
      break;
    }
    }
  });
}

void
DependencyGraphImpl::markTransitive(SmallVectorImpl<const void *> &newlyMarked,
                                    const void *node) {
  assert(Provides.count(node) && "node is not in the graph");
  SmallVector<const void *, 16> worklist;

  auto addDependentsToWorklist = [&](const void *next) {
    auto allProvided = Provides.find(next);
    if (allProvided == Provides.end())
      return;

    for (const auto &provided : allProvided->second) {
      auto allDependents = Dependencies.find(provided.second);
      if (allDependents == Dependencies.end())
        continue;

      for (const auto &dependent : allDependents->second) {
        if ((provided.first & dependent.first) == 0)
          continue;
        if (isMarked(dependent.second))
          continue;
        worklist.push_back(dependent.second);
      }
    }
  };

  // Always mark through the starting node, even if it's already marked.
  Marked.insert(node);
  addDependentsToWorklist(node);

  while (!worklist.empty()) {
    const void *next = worklist.pop_back_val();
    if (!Marked.insert(next))
      continue;
    newlyMarked.push_back(next);
    addDependentsToWorklist(next);
  }
}
<|endoftext|>