<commit_before>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */
#if defined(_MSC_VER)
// turn off bogus `this used in base member initialization list'
#  pragma warning(disable: 4786)
#endif

#include "global.h"

const struct GlobalDBItem globalDBItems[] = {
  { "_agilityAdVel",		"2.25",				false, StateDatabase::Locked},
  { "_agilityTimeWindow",	"1.0",				false, StateDatabase::Locked},
  { "_agilityVelDelta",	        "0.3",				false, StateDatabase::Locked},
  { "_angleTolerance",		"0.01",				false, StateDatabase::Locked},
  { "_angularAd",		"1.5",				false, StateDatabase::Locked},
  { "_avenueSize",		"2.0*_boxBase",			false, StateDatabase::Locked},
  { "_baseSize",		"60.0",                         false, StateDatabase::Locked},
  { "_boxBase",			"30.0",				false, StateDatabase::Locked},
  { "_boxHeight",		"6.0*_muzzleHeight",		false, StateDatabase::Locked},
  { "_burrowAngularAd",		"0.55",				false, StateDatabase::Locked},
  { "_burrowDepth",		"-1.32",			false, StateDatabase::Locked},
  { "_burrowSpeedAd",		"0.80",				false, StateDatabase::Locked},
  { "_deadUnder",		"-1.0",				false, StateDatabase::Locked},
  { "_explodeTime",		"5.0",				false, StateDatabase::Locked},
  { "_fakeLag",			"0.5",				false, StateDatabase::Locked},
  { "_flagAltitude",		"11.0",				false, StateDatabase::Locked},
  { "_flagHeight",		"10.0",				false, StateDatabase::Locked},
  { "_flagPoleWidth",		"0.025",                        false, StateDatabase::Locked},
  { "_flagPoleSize",		"0.8",				false, StateDatabase::Locked},
  { "_flagRadius",		"2.5",				false, StateDatabase::Locked},
  { "_friction",		"0",				false, StateDatabase::Locked},
  { "_gMissileAng",		"0.628319",			false, StateDatabase::Locked},
  { "_gMissileAdLife",		"0.95",				false, StateDatabase::Locked},
  { "_gravity",			"-9.8",				false, StateDatabase::Locked},
  { "_identifyRange",		"50.0",				false, StateDatabase::Locked},
  { "_jumpVelocity",		"19.0",				false, StateDatabase::Locked},
  { "_laserAdLife",		"0.1",				false, StateDatabase::Locked},
  { "_laserAdRate",		"0.5",				false, StateDatabase::Locked},
  { "_laserAdVel",		"1000.0",			false, StateDatabase::Locked},
  { "_lockOnAngle",		"0.15",				false, StateDatabase::Locked},
  { "_lRAdRate",		"0.5",				false, StateDatabase::Locked},
  { "_maxBumpHeight",		"0.33",				false, StateDatabase::Locked},
  { "_maxFlagGrabs",		"4.0",				false, StateDatabase::Locked},
  { "_maxLOD",			"32767.0",			false, StateDatabase::Locked},
  { "_momentumAngAcc",		"1.0",				false, StateDatabase::Locked},
  { "_momentumLinAcc",		"1.0",				false, StateDatabase::Locked},
  { "_momentumFriction",	"0",				false, StateDatabase::Locked},
  { "_mGunAdLife",		"1.0 / _mGunAdRate",		false, StateDatabase::Locked},
  { "_mGunAdRate",		"10.0",				false, StateDatabase::Locked},
  { "_mGunAdVel",		"1.5",				false, StateDatabase::Locked},
  { "_muzzleFront",		"_tankRadius + 0.1",		false, StateDatabase::Locked},
  { "_muzzleHeight",		"1.57",				false, StateDatabase::Locked},
  { "_notRespondingTime",	"5.0",				false, StateDatabase::Locked},
  { "_obeseFactor",		"2.5",				false, StateDatabase::Locked},
  { "_pauseDropTime",		"15.0",				false, StateDatabase::Locked},
  { "_positionTolerance",	"0.01",				false, StateDatabase::Locked},
  { "_pyrBase",			"4.0*_tankHeight",		false, StateDatabase::Locked},
  { "_pyrHeight",		"5.0*_tankHeight",		false, StateDatabase::Locked},
  { "_rejoinTime",		"10.0",	                        false, StateDatabase::Locked},
  { "_reloadTime",		"_shotRange / _shotSpeed",	false, StateDatabase::Locked},
  { "_rFireAdLife",		"1.0 / _rFireAdRate",		false, StateDatabase::Locked},
  { "_rFireAdRate",		"2.0",				false, StateDatabase::Locked},
  { "_rFireAdVel",		"1.5",				false, StateDatabase::Locked},
  { "_shieldFlight",		"2.7",				false, StateDatabase::Locked},
  { "_shockAdLife",		"0.2",				false, StateDatabase::Locked},
  { "_shockInRadius",		"_tankLength",			false, StateDatabase::Locked},
  { "_shockOutRadius",		"60.0",				false, StateDatabase::Locked},
  { "_shotTailLength",		"4.0",				false, StateDatabase::Locked},
  { "_shotRadius",		"0.5",				false, StateDatabase::Locked},
  { "_shotRange",		"350.0",			false, StateDatabase::Locked},
  { "_shotSpeed",		"100.0",			false, StateDatabase::Locked},
  { "_shotsKeepVerticalVelocity",	"0",			false, StateDatabase::Locked},
  { "_srRadiusMult",		"2.0",				false, StateDatabase::Locked},
  { "_syncTime",		"0",				false, StateDatabase::Locked},
  { "_tankExplosionSize",	"3.5 * _tankLength", 		false, StateDatabase::Locked},
  { "_tankAngVel",		"0.785398", 			false, StateDatabase::Locked},
  { "_tankHeight",		"2.05",				false, StateDatabase::Locked},
  { "_tankLength",		"6.0",				false, StateDatabase::Locked},
  { "_tankRadius",		"0.72 * _tankLength",		false, StateDatabase::Locked},
  { "_tankSpeed",		"25.0",				false, StateDatabase::Locked},
  { "_tankWidth",		"2.8",				false, StateDatabase::Locked},
  { "_targetingAngle",		"0.3",				false, StateDatabase::Locked},
  { "_teleportBreadth",		"4.48",				false, StateDatabase::Locked},
  { "_teleportHeight",		"10.08",			false, StateDatabase::Locked},
  { "_teleportTime",		"1.0",				false, StateDatabase::Locked},
  { "_teleportWidth",		"1.12",				false, StateDatabase::Locked},
  { "_thiefAdLife",		"0.05",				false, StateDatabase::Locked},
  { "_thiefAdRate",		"12.0",				false, StateDatabase::Locked},
  { "_thiefAdShotVel",		"8.0",				false, StateDatabase::Locked},
  { "_thiefTinyFactor",		"0.5",				false, StateDatabase::Locked},
  { "_thiefVelAd",		"1.67",				false, StateDatabase::Locked},
  { "_thiefDropTime",		"_reloadTime * 0.5",		false, StateDatabase::Locked},
  { "_tinyFactor",		"0.4",				false, StateDatabase::Locked},
  { "_updateThrottleRate",	"30.0",				false, StateDatabase::Locked},
  { "_velocityAd",		"1.5",				false, StateDatabase::Locked},
  { "_wallHeight",		"3.0*_tankHeight",		false, StateDatabase::Locked},
  { "_wideAngleAng",		"1.745329", 			false, StateDatabase::Locked},
  { "_wingsGravity",		"_gravity",			false, StateDatabase::Locked},
  { "_wingsJumpCount",		"1",				false, StateDatabase::Locked},
  { "_wingsJumpVelocity",	"_jumpVelocity",		false, StateDatabase::Locked},
  { "_worldSize",		"800.0",			false, StateDatabase::Locked}
};
const unsigned int	numGlobalDBItems = countof(globalDBItems);

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>default deadUnder should be near -Inf so that it's disabled -- -32767 is close (-1 kills burrow)<commit_after>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */
#if defined(_MSC_VER)
// turn off bogus `this used in base member initialization list'
#  pragma warning(disable: 4786)
#endif

#include "global.h"

const struct GlobalDBItem globalDBItems[] = {
  { "_agilityAdVel",		"2.25",				false, StateDatabase::Locked},
  { "_agilityTimeWindow",	"1.0",				false, StateDatabase::Locked},
  { "_agilityVelDelta",	        "0.3",				false, StateDatabase::Locked},
  { "_angleTolerance",		"0.01",				false, StateDatabase::Locked},
  { "_angularAd",		"1.5",				false, StateDatabase::Locked},
  { "_avenueSize",		"2.0*_boxBase",			false, StateDatabase::Locked},
  { "_baseSize",		"60.0",                         false, StateDatabase::Locked},
  { "_boxBase",			"30.0",				false, StateDatabase::Locked},
  { "_boxHeight",		"6.0*_muzzleHeight",		false, StateDatabase::Locked},
  { "_burrowAngularAd",		"0.55",				false, StateDatabase::Locked},
  { "_burrowDepth",		"-1.32",			false, StateDatabase::Locked},
  { "_burrowSpeedAd",		"0.80",				false, StateDatabase::Locked},
  { "_deadUnder",		"-32767.0",			false, StateDatabase::Locked},
  { "_explodeTime",		"5.0",				false, StateDatabase::Locked},
  { "_fakeLag",			"0.5",				false, StateDatabase::Locked},
  { "_flagAltitude",		"11.0",				false, StateDatabase::Locked},
  { "_flagHeight",		"10.0",				false, StateDatabase::Locked},
  { "_flagPoleWidth",		"0.025",                        false, StateDatabase::Locked},
  { "_flagPoleSize",		"0.8",				false, StateDatabase::Locked},
  { "_flagRadius",		"2.5",				false, StateDatabase::Locked},
  { "_friction",		"0",				false, StateDatabase::Locked},
  { "_gMissileAng",		"0.628319",			false, StateDatabase::Locked},
  { "_gMissileAdLife",		"0.95",				false, StateDatabase::Locked},
  { "_gravity",			"-9.8",				false, StateDatabase::Locked},
  { "_identifyRange",		"50.0",				false, StateDatabase::Locked},
  { "_jumpVelocity",		"19.0",				false, StateDatabase::Locked},
  { "_laserAdLife",		"0.1",				false, StateDatabase::Locked},
  { "_laserAdRate",		"0.5",				false, StateDatabase::Locked},
  { "_laserAdVel",		"1000.0",			false, StateDatabase::Locked},
  { "_lockOnAngle",		"0.15",				false, StateDatabase::Locked},
  { "_lRAdRate",		"0.5",				false, StateDatabase::Locked},
  { "_maxBumpHeight",		"0.33",				false, StateDatabase::Locked},
  { "_maxFlagGrabs",		"4.0",				false, StateDatabase::Locked},
  { "_maxLOD",			"32767.0",			false, StateDatabase::Locked},
  { "_momentumAngAcc",		"1.0",				false, StateDatabase::Locked},
  { "_momentumLinAcc",		"1.0",				false, StateDatabase::Locked},
  { "_momentumFriction",	"0",				false, StateDatabase::Locked},
  { "_mGunAdLife",		"1.0 / _mGunAdRate",		false, StateDatabase::Locked},
  { "_mGunAdRate",		"10.0",				false, StateDatabase::Locked},
  { "_mGunAdVel",		"1.5",				false, StateDatabase::Locked},
  { "_muzzleFront",		"_tankRadius + 0.1",		false, StateDatabase::Locked},
  { "_muzzleHeight",		"1.57",				false, StateDatabase::Locked},
  { "_notRespondingTime",	"5.0",				false, StateDatabase::Locked},
  { "_obeseFactor",		"2.5",				false, StateDatabase::Locked},
  { "_pauseDropTime",		"15.0",				false, StateDatabase::Locked},
  { "_positionTolerance",	"0.01",				false, StateDatabase::Locked},
  { "_pyrBase",			"4.0*_tankHeight",		false, StateDatabase::Locked},
  { "_pyrHeight",		"5.0*_tankHeight",		false, StateDatabase::Locked},
  { "_rejoinTime",		"10.0",	                        false, StateDatabase::Locked},
  { "_reloadTime",		"_shotRange / _shotSpeed",	false, StateDatabase::Locked},
  { "_rFireAdLife",		"1.0 / _rFireAdRate",		false, StateDatabase::Locked},
  { "_rFireAdRate",		"2.0",				false, StateDatabase::Locked},
  { "_rFireAdVel",		"1.5",				false, StateDatabase::Locked},
  { "_shieldFlight",		"2.7",				false, StateDatabase::Locked},
  { "_shockAdLife",		"0.2",				false, StateDatabase::Locked},
  { "_shockInRadius",		"_tankLength",			false, StateDatabase::Locked},
  { "_shockOutRadius",		"60.0",				false, StateDatabase::Locked},
  { "_shotTailLength",		"4.0",				false, StateDatabase::Locked},
  { "_shotRadius",		"0.5",				false, StateDatabase::Locked},
  { "_shotRange",		"350.0",			false, StateDatabase::Locked},
  { "_shotSpeed",		"100.0",			false, StateDatabase::Locked},
  { "_shotsKeepVerticalVelocity",	"0",			false, StateDatabase::Locked},
  { "_srRadiusMult",		"2.0",				false, StateDatabase::Locked},
  { "_syncTime",		"0",				false, StateDatabase::Locked},
  { "_tankExplosionSize",	"3.5 * _tankLength", 		false, StateDatabase::Locked},
  { "_tankAngVel",		"0.785398", 			false, StateDatabase::Locked},
  { "_tankHeight",		"2.05",				false, StateDatabase::Locked},
  { "_tankLength",		"6.0",				false, StateDatabase::Locked},
  { "_tankRadius",		"0.72 * _tankLength",		false, StateDatabase::Locked},
  { "_tankSpeed",		"25.0",				false, StateDatabase::Locked},
  { "_tankWidth",		"2.8",				false, StateDatabase::Locked},
  { "_targetingAngle",		"0.3",				false, StateDatabase::Locked},
  { "_teleportBreadth",		"4.48",				false, StateDatabase::Locked},
  { "_teleportHeight",		"10.08",			false, StateDatabase::Locked},
  { "_teleportTime",		"1.0",				false, StateDatabase::Locked},
  { "_teleportWidth",		"1.12",				false, StateDatabase::Locked},
  { "_thiefAdLife",		"0.05",				false, StateDatabase::Locked},
  { "_thiefAdRate",		"12.0",				false, StateDatabase::Locked},
  { "_thiefAdShotVel",		"8.0",				false, StateDatabase::Locked},
  { "_thiefTinyFactor",		"0.5",				false, StateDatabase::Locked},
  { "_thiefVelAd",		"1.67",				false, StateDatabase::Locked},
  { "_thiefDropTime",		"_reloadTime * 0.5",		false, StateDatabase::Locked},
  { "_tinyFactor",		"0.4",				false, StateDatabase::Locked},
  { "_updateThrottleRate",	"30.0",				false, StateDatabase::Locked},
  { "_velocityAd",		"1.5",				false, StateDatabase::Locked},
  { "_wallHeight",		"3.0*_tankHeight",		false, StateDatabase::Locked},
  { "_wideAngleAng",		"1.745329", 			false, StateDatabase::Locked},
  { "_wingsGravity",		"_gravity",			false, StateDatabase::Locked},
  { "_wingsJumpCount",		"1",				false, StateDatabase::Locked},
  { "_wingsJumpVelocity",	"_jumpVelocity",		false, StateDatabase::Locked},
  { "_worldSize",		"800.0",			false, StateDatabase::Locked}
};
const unsigned int	numGlobalDBItems = countof(globalDBItems);

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>#include "utils/mempool.hpp"

#include <new>
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <cstring>

#define MOVE_BYTES(base, offset) \
    reinterpret_cast<decltype(base)>(reinterpret_cast<uint8_t*>(base) + offset)

#define CONTAINER_OF(containerType, memberName, memberAddress) \
    reinterpret_cast<containerType*>(MOVE_BYTES(memberAddress, -offsetof(containerType, memberName)))

namespace impl = Compiler::Utils;

using namespace Compiler::Utils;

static constexpr auto BLOCK_SIZE = 1 << 12; // 4KB
static constexpr auto SIZES = 8; // difference size of memory, 8, 16, 24, 32, 40, 48, 56, 64
static constexpr auto MAX_SIZE = 8 * SIZES;

struct ListBlock {
    ListBlock *next;
};

/**
 * StandardLayout and layout-compatible with ListBlock,
 * and both have a next field which are semantically equal.
 * so DoubleLinkedBlock* can be safely casted to ListBlock*,
 * so we do not need a freeList(DoubleLinkedBlock*) version
 */
struct DoubleLinkedBlock {
    DoubleLinkedBlock *next;
    DoubleLinkedBlock *prev;
    uint8_t data[0];
};

struct PoolBlock {
    /**< first node of free list */
    ListBlock *freeList;
    /**< points to first node of chunk list */
    ListBlock *chunk;
};

template <class T>
static inline T* managedMalloc(std::size_t additional = 0) noexcept(false) {
    auto ret = malloc(additional + sizeof(T));
    if(!ret)
        throw std::bad_alloc{};
    return static_cast<T*>(ret);
}

static inline void* managedRealloc(void *src, std::size_t newsize) noexcept(false) {
    auto ret = realloc(src, newsize);
    if(!ret)
        throw std::bad_alloc{};
    return ret;
}

static inline void managedFree(void *mem) noexcept {
    free(mem);
}

/**
 * See if lowest 3 bit of pointer address is not 0
 * @param ptr pointer address
 */
static inline bool lowest3bitSet(void *ptr) noexcept {
    return (reinterpret_cast<uintptr_t>(ptr) & 7);
}

/**
 * Make address 8-byte aligned
 * @param ptr pointer address
 * @return aligned address
 */
static inline void* align8Pointer(void *ptr) noexcept {
    if(lowest3bitSet(ptr)) {
        auto &&uintptr = reinterpret_cast<uintptr_t&>(ptr);
        uintptr &= ~7U;
        uintptr += 8;
    }
    return ptr;
}

/**
 * Calculate size of memory block
 * @param size requested size
 * @return actual size of memory block
 */
static inline unsigned sizeOf(unsigned size) noexcept {
    assert(size != 0);
    return size < MAX_SIZE ? (size + 7) & ~7U : size;
}

/**
 * Calculate index of MemBlock in whole MemPool
 * @param size requested size
 * @return index to chunks array
 */
static inline unsigned indexOf(unsigned size) noexcept {
    assert(size != 0);
    return size < MAX_SIZE ? ((size + 7) >> 3) - 1 : SIZES;
}

static inline PoolBlock* chunkAt(void *base, unsigned index) noexcept {
    return static_cast<PoolBlock*>(base) + index;
}

/**
 * Allocate a memory block used as chunk, then attach to a PoolBlock
 * @param owner owner of this chunk
 * @param blockSize size of small block
 * @return first available memory block of this new chunk
 */
static ListBlock* addChunk(PoolBlock *owner, unsigned blockSize) {
    auto count = BLOCK_SIZE / blockSize;
    auto chunk = managedMalloc<ListBlock>(BLOCK_SIZE);

    auto mem = chunk + 1;
    while(count--) {
        auto next = MOVE_BYTES(mem, blockSize);
        mem->next = next;
        mem = next;
    }

    chunk->next = owner->chunk;
    owner->chunk = chunk;

    mem->next = owner->freeList;
    owner->freeList = chunk + 1;

    return chunk + 1;
}

/**
 * Allocate an arbitary size of memory, then attach it to PoolBlock
 * @param owner owner of this memory
 * @param blockSize size of this memory
 * @return available memory of this memory block
 */
static void* arbitarySizedBlock(PoolBlock *owner, unsigned blockSize) {
    auto block = managedMalloc<DoubleLinkedBlock>(blockSize);

    auto first = reinterpret_cast<DoubleLinkedBlock*>(owner->chunk);
    if(first)
        first->prev = block;
    block->next = first;
    block->prev = nullptr;

    owner->chunk = reinterpret_cast<ListBlock*>(block);
    return block->data;
}

MemPool impl::pool{};

class MemPool::AlignedTag {};

MemPool::AlignedTag MemPool::aligned{};

MemPool::MemPool() {
    auto chunks = managedMalloc<PoolBlock>(SIZES * sizeof(PoolBlock));
    for(auto i=0; i<SIZES+1; ++i) {
        chunks[i].chunk = nullptr;
        chunks[i].freeList = nullptr;
    }
}

MemPool::~MemPool() noexcept {
    clear();
    managedFree(m_chunks);
}

void* MemPool::allocate(unsigned size) {
    auto index = indexOf(size);
    auto chunk = chunkAt(m_chunks, index);

    if(index == SIZES)
        return arbitarySizedBlock(chunk, size);

    auto block = chunk->freeList;
    if(!block)
        block = addChunk(chunk, sizeOf(size));

    chunk->freeList = block->next;
    return block;
}

void* MemPool::align8Allocate(unsigned size) {
    auto index = indexOf(size);
    assert(index < SIZES);

    auto chunk = chunkAt(m_chunks, index);
    ListBlock *first = chunk->freeList, *prev = nullptr;
    while(first) {
        if(lowest3bitSet(first)) {
            if(!prev)
                chunk->freeList = first->next;
            else
                prev->next = first->next;
            return first;
        }
        prev = first;
        first = first->next;
    }

    return align8Pointer(allocate(size + 8));
}

void* MemPool::reallocate(void *current, unsigned oldSize, unsigned newSize) {
    if(oldSize >= newSize || sizeOf(oldSize) == sizeOf(newSize))
        return current;
    if(indexOf(oldSize) == SIZES)
        return managedRealloc(current, newSize);

    auto ret = memcpy(allocate(newSize), current, oldSize);
    deallocate(current, oldSize);
    return ret;
}

void MemPool::deallocate(void *mem, unsigned size) noexcept {
    if(!mem)
        return;
    auto index = indexOf(size);
    auto chunk = chunkAt(m_chunks, index);

    if(index == SIZES) {
        auto block = CONTAINER_OF(DoubleLinkedBlock, data, mem);
        auto prev = block->prev;
        auto next = block->next;
        if(prev)
            prev->next = next;
        if(next)
            next->prev = prev;
        managedFree(block);
        return;
    }

    auto block = static_cast<ListBlock*>(mem);
    block->next = chunk->freeList;
    chunk->freeList = block;
}

void MemPool::clear() noexcept {
    auto chunks = static_cast<PoolBlock*>(m_chunks);
    for(auto i=0; i<SIZES; ++i, ++chunks) {
        auto head = chunks->chunk;
        while(head) {
            auto save = head->next;
            managedFree(head);
            head = save;
        }
        chunks->chunk = nullptr;
        chunks->freeList = nullptr;
    }
}

void* operator new(std::size_t size, MemPool &pool) {
    return pool.allocate(size);
}

void* operator new(std::size_t size, MemPool &pool, const MemPool::AlignedTag &) {
    return pool.align8Allocate(size);
}

void operator delete(void* mem, std::size_t size, Compiler::Utils::MemPool& pool) noexcept {
    pool.deallocate(mem, size);
}
<commit_msg>fix mempool<commit_after>#include "utils/mempool.hpp"

#include <new>
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <cstring>

#define MOVE_BYTES(base, offset) \
    reinterpret_cast<decltype(base)>(reinterpret_cast<uint8_t*>(base) + offset)

#define CONTAINER_OF(containerType, memberName, memberAddress) \
    reinterpret_cast<containerType*>(MOVE_BYTES(memberAddress, -offsetof(containerType, memberName)))

namespace impl = Compiler::Utils;

using namespace Compiler::Utils;

static constexpr auto BLOCK_SIZE = 1 << 12; // 4KB
static constexpr auto SIZES = 8; // difference size of memory, 8, 16, 24, 32, 40, 48, 56, 64
static constexpr auto MAX_SIZE = 8 * SIZES;

struct ListBlock {
    ListBlock *next;
};

/**
 * StandardLayout and layout-compatible with ListBlock,
 * and both have a next field that are semantically equal.
 * So DualLinkedBlock* can be safely casted to ListBlock*,
 * and can share a same deallcation function.
 */
struct DualLinkedBlock {
    DualLinkedBlock *next;
    DualLinkedBlock *prev;
    uint8_t          data[0];

    /**
     * Fix pointer linkage after reallocation.
     */
    inline void fixLinkage() noexcept {
        if(prev)
            prev->next = this;
        if(next)
            next->prev = this;
    }

    /**
     * Remove this block from a doubly-linked list
     */
    inline void removeThis() noexcept {
        if(prev)
            prev->next = next;
        if(next)
            next->prev = prev;
    }
};

struct PoolBlock {
    /**< first node of free list */
    ListBlock *freeList;
    /**< points to first node of chunk list */
    ListBlock *chunk;
};

template <class T>
static inline T* managedMalloc(std::size_t additional = 0) noexcept(false) {
    auto ret = malloc(additional + sizeof(T));
    if(!ret)
        throw std::bad_alloc{};
    return static_cast<T*>(ret);
}

template <class T>
static inline T* managedRealloc(T *src, std::size_t newsize) noexcept(false) {
    auto ret = realloc(src, newsize + sizeof(T));
    if(!ret)
        throw std::bad_alloc{};
    return static_cast<T*>(ret);
}

static inline void managedFree(void *mem) noexcept {
    free(mem);
}

/**
 * See if lowest 3 bit of pointer address is not 0
 * @param ptr pointer address
 */
static inline bool lowest3bitSet(void *ptr) noexcept {
    return (reinterpret_cast<uintptr_t>(ptr) & 7);
}

/**
 * Make address 8-byte aligned
 * @param ptr pointer address
 * @return aligned address
 */
static inline void* align8Pointer(void *ptr) noexcept {
    if(lowest3bitSet(ptr)) {
        auto &&uintptr = reinterpret_cast<uintptr_t&>(ptr);
        uintptr &= ~7U;
        uintptr += 8;
    }
    return ptr;
}

/**
 * Calculate size of memory block
 * @param size requested size
 * @return actual size of memory block
 */
static inline unsigned sizeOf(unsigned size) noexcept {
    assert(size != 0);
    return size < MAX_SIZE ? (size + 7) & ~7U : size;
}

/**
 * Calculate index of MemBlock in whole MemPool
 * @param size requested size
 * @return index to chunks array
 */
static inline unsigned indexOf(unsigned size) noexcept {
    assert(size != 0);
    return size < MAX_SIZE ? ((size + 7) >> 3) - 1 : SIZES;
}

static inline PoolBlock* chunkAt(void *base, unsigned index) noexcept {
    return static_cast<PoolBlock*>(base) + index;
}

/**
 * Allocate a memory block used as chunk, then attach to a PoolBlock
 * @param owner owner of this chunk
 * @param blockSize size of small block
 * @return first available memory block of this new chunk
 */
static ListBlock* addChunk(PoolBlock *owner, unsigned blockSize) {
    auto count = BLOCK_SIZE / blockSize;
    auto chunk = managedMalloc<ListBlock>(BLOCK_SIZE);

    auto mem = chunk + 1;
    while(count--) {
        auto next = MOVE_BYTES(mem, blockSize);
        mem->next = next;
        mem = next;
    }

    chunk->next = owner->chunk;
    owner->chunk = chunk;

    mem->next = owner->freeList;
    owner->freeList = chunk + 1;

    return chunk + 1;
}

/**
 * Allocate an arbitary size of memory, then attach it to PoolBlock
 * @param owner owner of this memory
 * @param blockSize size of this memory
 * @return available memory of this memory block
 */
static void* arbitarySizedBlock(PoolBlock *owner, unsigned blockSize) {
    auto block = managedMalloc<DualLinkedBlock>(blockSize);

    auto first = reinterpret_cast<DualLinkedBlock *>(owner->chunk);
    if(first)
        first->prev = block;
    block->next = first;
    block->prev = nullptr;

    owner->chunk = reinterpret_cast<ListBlock*>(block);
    return block->data;
}

MemPool impl::pool{};

class MemPool::AlignedTag {};

MemPool::AlignedTag MemPool::aligned{};

MemPool::MemPool() {
    auto chunks = managedMalloc<PoolBlock>(SIZES * sizeof(PoolBlock));
    for(auto i=0; i<SIZES+1; ++i) {
        chunks[i].chunk = nullptr;
        chunks[i].freeList = nullptr;
    }
}

MemPool::~MemPool() noexcept {
    clear();
    managedFree(m_chunks);
}

void* MemPool::allocate(unsigned size) {
    auto index = indexOf(size);
    auto chunk = chunkAt(m_chunks, index);

    if(index == SIZES)
        return arbitarySizedBlock(chunk, size);

    auto block = chunk->freeList;
    if(!block)
        block = addChunk(chunk, sizeOf(size));

    chunk->freeList = block->next;
    return block;
}

void* MemPool::align8Allocate(unsigned size) {
    auto index = indexOf(size);
    assert(index < SIZES);

    auto chunk = chunkAt(m_chunks, index);
    ListBlock *first = chunk->freeList, *prev = nullptr;
    while(first) {
        if(!lowest3bitSet(first)) {
            if(!prev)
                chunk->freeList = first->next;
            else
                prev->next = first->next;
            return first;
        }
        prev = first;
        first = first->next;
    }

    return align8Pointer(allocate(size + 8));
}

void* MemPool::reallocate(void *current, unsigned oldSize, unsigned newSize) {
    if(oldSize >= newSize || sizeOf(oldSize) == sizeOf(newSize))
        return current;
    if(indexOf(oldSize) == SIZES) {
        auto block = CONTAINER_OF(DualLinkedBlock, data, current);
        auto newblock = managedRealloc(block, newSize);
        newblock->fixLinkage();
        return newblock->data;
    }
    auto ret = memcpy(allocate(newSize), current, oldSize);
    deallocate(current, oldSize);
    return ret;
}

void MemPool::deallocate(void *mem, unsigned size) noexcept {
    if(!mem)
        return;
    auto index = indexOf(size);
    auto chunk = chunkAt(m_chunks, index);

    if(index == SIZES) {
        auto block = CONTAINER_OF(DualLinkedBlock, data, mem);
        block->removeThis();
        managedFree(block);
        return;
    }

    auto block = static_cast<ListBlock*>(mem);
    block->next = chunk->freeList;
    chunk->freeList = block;
}

void MemPool::clear() noexcept {
    auto chunks = static_cast<PoolBlock*>(m_chunks);
    for(auto i=0; i<SIZES; ++i, ++chunks) {
        auto head = chunks->chunk;
        while(head) {
            auto save = head->next;
            managedFree(head);
            head = save;
        }
        chunks->chunk = nullptr;
        chunks->freeList = nullptr;
    }
}

void* operator new(std::size_t size, MemPool &pool) {
    return pool.allocate(size);
}

void* operator new(std::size_t size, MemPool &pool, const MemPool::AlignedTag &) {
    return pool.align8Allocate(size);
}

void operator delete(void* mem, std::size_t size, Compiler::Utils::MemPool& pool) noexcept {
    pool.deallocate(mem, size);
}
<|endoftext|>


<commit_before><commit_msg>Stuff stolen from the Internet.<commit_after><|endoftext|>


<commit_before>/**
 * studentCollection_class.cpp
 *
 * Author: Patrick Rummage <patrickbrummage@gmail.com>
 *
 * Objective:
 *
 */
#include <iostream>
using std::cin;
using std::cout;

struct studentRecord {
    int studentID;
    int grade;
    char* name;
};

class studentCollection {
    private:
        struct studentNode {
            studentRecord studentData;
            studentNode* next;
        };

    public:
        studentCollection();
        ~studentCollection();
        void addRecord(studentRecord newStudent);
        studentRecord recordWithNumber(int idNum);
        double averageRecord();
        studentCollection recordsWithinRange(int low, int high);
        void removeRecord(int idNum);
        studentNode* copiedList(const studentNode* original);
        studentCollection& operator=(const studentCollection& rhs);

    private:
        studentNode* _listHead;
        void deleteList(studentNode* &listPtr);
};

studentCollection::studentCollection() {
    _listHead = NULL;
}

void studentCollection::addRecord(studentRecord newStudent) {
    studentNode* newNode = new studentNode;
    newNode->studentData = newStudent;
    newNode->next = _listHead; // Previous first item
    _listHead = newNode;
}

studentRecord studentCollection::recordWithNumber(int idNum) {
    studentNode* loopPtr = _listHead;
    while (loopPtr != NULL && loopPtr->studentData.studentID != idNum) {
        loopPtr = loopPtr->next;
    }
    if (loopPtr == NULL) {
        studentRecord dummyRecord{-1,-1,"VOID"};
        return dummyRecord;
    } else {
        return loopPtr->studentData;
    }
}

double studentCollection::averageRecord() {
    if (_listHead == NULL) { // Handle empty list
        return 0;
    }
    int count = 0;
    int sum = 0;
    studentNode* listPtr = _listHead;
    while (listPtr != NULL) {
       sum += listPtr->studentData.grade;
       count++;
       listPtr = listPtr->next;
    }
    double average = sum / count;
    return average;
}

void studentCollection::removeRecord(int idNum) {
    studentNode* loopPtr = _listHead;
    studentNode* previous = NULL;
    while (loopPtr != NULL && loopPtr->studentData.studentID != idNum) {
        previous = loopPtr;
        loopPtr = loopPtr->next;
    }
    if (loopPtr == NULL) { // Not found
        return;
    }
    if (previous == NULL) { // Removing first node
        _listHead = _listHead->next;
    } else { // Join nodes before and after one to be deleted
        previous->next = loopPtr->next;
    }
    delete loopPtr;
}

void studentCollection::deleteList(studentNode* &listPtr) {
    while (listPtr != NULL) {
        studentNode* temp = listPtr;
        listPtr = listPtr->next;
        delete temp;
    }
}

studentCollection studentCollection::recordsWithinRange(int low, int high) {
    studentCollection newCollection;
    studentNode* listPtr = _listHead;
    int studentGrade;
    while (listPtr != NULL) {
        studentGrade = listPtr->studentData.grade;
        if (studentGrade >= low && studentGrade <= high) {
           newCollection.addRecord(listPtr->studentData);
        }
        listPtr = listPtr->next;
    }
    return newCollection;
}

studentCollection::studentNode*
studentCollection::copiedList(const studentNode* original) {
    if (original == NULL) {
        return NULL;
    }
    studentNode* newList = new studentNode;
    newList->studentData = original->studentData;
    studentNode* oldLoopPtr = original->next;
    studentNode* newLoopPtr = newList;
    while(oldLoopPtr != NULL) {
        newLoopPtr->next = new studentNode;
        newLoopPtr = newLoopPtr->next;
        newLoopPtr->studentData = oldLoopPtr->studentData;
        oldLoopPtr = oldLoopPtr->next;
    }
    newLoopPtr->next = NULL;
    return newList;
}

studentCollection::~studentCollection() {
    deleteList(_listHead);
}

studentCollection& studentCollection::operator=(const studentCollection& rhs) {
    if (this != &rhs) {
        deleteList(_listHead);
        _listHead = copiedList(rhs._listHead);
    }
    return *this;
}

int main (int argc, char* argv[]) {
    studentCollection collection1;
    collection1.addRecord(studentRecord{0,100,"Peace"});
    collection1.addRecord(studentRecord{1,50,"Scrimbles"});

    studentCollection collection2 = collection1;
    collection2.addRecord(studentRecord{2,25,"Grizzabella"});

    double average = collection1.averageRecord();
    double average2 = collection2.averageRecord();
    cout << average << '\n';
    cout << average2 << '\n';

    return 0;
}
<commit_msg>added print method<commit_after>/**
 * studentCollection_class.cpp
 *
 * Author: Patrick Rummage <patrickbrummage@gmail.com>
 *
 * Objective:
 *
 */
#include <iostream>
using std::cin;
using std::cout;

struct studentRecord {
    int studentID;
    int grade;
    char* name;
};

class studentCollection {
    private:
        struct studentNode {
            studentRecord studentData;
            studentNode* next;
        };

    public:
        studentCollection();
        ~studentCollection();
        void printList() const;
        void addRecord(studentRecord newStudent);
        studentRecord recordWithNumber(int idNum);
        double averageRecord();
        studentCollection recordsWithinRange(int low, int high);
        void removeRecord(int idNum);
        studentNode* copiedList(const studentNode* original);
        studentCollection& operator=(const studentCollection& rhs);

    private:
        studentNode* _listHead;
        void deleteList(studentNode* &listPtr);
};

studentCollection::studentCollection() {
    _listHead = NULL;
}

void studentCollection::printList() const {
    studentNode* listPtr = _listHead;
    while (listPtr != NULL) {
        cout << listPtr->studentData.studentID << ", " << listPtr->studentData.grade <<
            ", " << listPtr->studentData.name << '\n';
        listPtr = listPtr->next;
    }
}

void studentCollection::addRecord(studentRecord newStudent) {
    studentNode* newNode = new studentNode;
    newNode->studentData = newStudent;
    newNode->next = _listHead; // Previous first item
    _listHead = newNode;
}

studentRecord studentCollection::recordWithNumber(int idNum) {
    studentNode* loopPtr = _listHead;
    while (loopPtr != NULL && loopPtr->studentData.studentID != idNum) {
        loopPtr = loopPtr->next;
    }
    if (loopPtr == NULL) {
        studentRecord dummyRecord{-1,-1,"VOID"};
        return dummyRecord;
    } else {
        return loopPtr->studentData;
    }
}

double studentCollection::averageRecord() {
    if (_listHead == NULL) { // Handle empty list
        return 0;
    }
    int count = 0;
    int sum = 0;
    studentNode* listPtr = _listHead;
    while (listPtr != NULL) {
       sum += listPtr->studentData.grade;
       count++;
       listPtr = listPtr->next;
    }
    double average = sum / count;
    return average;
}

void studentCollection::removeRecord(int idNum) {
    studentNode* loopPtr = _listHead;
    studentNode* previous = NULL;
    while (loopPtr != NULL && loopPtr->studentData.studentID != idNum) {
        previous = loopPtr;
        loopPtr = loopPtr->next;
    }
    if (loopPtr == NULL) { // Not found
        return;
    }
    if (previous == NULL) { // Removing first node
        _listHead = _listHead->next;
    } else { // Join nodes before and after one to be deleted
        previous->next = loopPtr->next;
    }
    delete loopPtr;
}

void studentCollection::deleteList(studentNode* &listPtr) {
    while (listPtr != NULL) {
        studentNode* temp = listPtr;
        listPtr = listPtr->next;
        delete temp;
    }
}

studentCollection studentCollection::recordsWithinRange(int low, int high) {
    studentCollection newCollection;
    studentNode* listPtr = _listHead;
    int studentGrade;
    while (listPtr != NULL) {
        studentGrade = listPtr->studentData.grade;
        if (studentGrade >= low && studentGrade <= high) {
           newCollection.addRecord(listPtr->studentData);
        }
        listPtr = listPtr->next;
    }
    return newCollection;
}

studentCollection::studentNode*
studentCollection::copiedList(const studentNode* original) {
    if (original == NULL) {
        return NULL;
    }
    studentNode* newList = new studentNode;
    newList->studentData = original->studentData;
    studentNode* oldLoopPtr = original->next;
    studentNode* newLoopPtr = newList;
    while(oldLoopPtr != NULL) {
        newLoopPtr->next = new studentNode;
        newLoopPtr = newLoopPtr->next;
        newLoopPtr->studentData = oldLoopPtr->studentData;
        oldLoopPtr = oldLoopPtr->next;
    }
    newLoopPtr->next = NULL;
    return newList;
}

studentCollection::~studentCollection() {
    deleteList(_listHead);
}

studentCollection& studentCollection::operator=(const studentCollection& rhs) {
    if (this != &rhs) {
        deleteList(_listHead);
        _listHead = copiedList(rhs._listHead);
    }
    return *this;
}

//-----------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& ost, const studentCollection& sc) {
    sc.printList();

    return ost;
}

int main (int argc, char* argv[]) {
    studentCollection collection1;
    collection1.addRecord(studentRecord{0,100,"Peace"});
    collection1.addRecord(studentRecord{1,50,"Scrimbles"});

    studentCollection collection2 = collection1;
    collection2.addRecord(studentRecord{2,25,"Grizzabella"});

    double average = collection1.averageRecord();
    double average2 = collection2.averageRecord();
    cout << average << '\n';
    cout << average2 << '\n';

    cout << collection2 << '\n';

    return 0;
}
<|endoftext|>


<commit_before>// -*- mode: c++; c-basic-offset:4 -*-

// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.

// Copyright (c) 2002,2003 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// 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
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.

#include <cppunit/TextTestRunner.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/extensions/HelperMacros.h>

#ifndef TM_IN_SYS_TIME
#include <time.h>
#else
#include <sys/time.h>
#endif

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>   // for stat

#include <string>
#include <sstream>

#include "Ancillary.h"
#include "DDS.h"
#include "debug.h"

#include "run_tests_cppunit.h"
#include "run_tests_cppunit.h"
#include "test_config.h"

using namespace CppUnit;
using namespace std;
using namespace libdap;

class ancT: public TestFixture {
private:

protected:

public:
    ancT() = default;
    ~ancT() = default;

    CPPUNIT_TEST_SUITE (ancT);

    CPPUNIT_TEST (find_ancillary_file_test);
    CPPUNIT_TEST (find_group_ancillary_file_test);
    CPPUNIT_TEST (read_ancillary_das_file_test);

    CPPUNIT_TEST_SUITE_END();

    void find_ancillary_file_test()
    {
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testsuite/test.1", "das", "", "")
                == (string) TEST_SRC_DIR + "/das-testsuite/test.1.das");
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testsuite/special.test.hdf", "das", "", "")
                == (string) TEST_SRC_DIR + "/das-testsuite/special.test.das");
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testsuite/test.2", "das", "", "")
                == (string) TEST_SRC_DIR + "/das-testsuite/das");
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testsuite/test.1.gz", "das", "", "")
                == (string) TEST_SRC_DIR + "/das-testsuite/test.1.das");
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testsuite/test.3.Z", "das", "", "")
                == (string) TEST_SRC_DIR + "/das-testsuite/test.3.Z.das");
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testste/test_1", "das", (string) TEST_SRC_DIR + "/das-testsuite/", "")
            == (string) TEST_SRC_DIR + "/das-testsuite/test_1.das");
        Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testsuite/te1", "das", (string) TEST_SRC_DIR + "/das-testite/", "");
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testsuite/te1", "das", (string) TEST_SRC_DIR + "/das-testite/", "")
            == (string) TEST_SRC_DIR + "/das-testsuite/das");
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testste/test1", "das", (string) TEST_SRC_DIR + "/das-testsuite/", "")
            == (string) TEST_SRC_DIR + "/das-testsuite/das");
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testste/test1", "das", (string) TEST_SRC_DIR + "/das-testsuite/", "test.1")
            == (string) TEST_SRC_DIR + "/das-testsuite/test.1.das");
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testste/test1", "ds", (string) TEST_SRC_DIR + "/das-testsuite/", "")
            == "");
    }

    void find_group_ancillary_file_test()
    {
        CPPUNIT_ASSERT(
            Ancillary::find_group_ancillary_file((string) TEST_SRC_DIR + "/cgi-util-tests/02group.hdf", ".htm")
                == (string) TEST_SRC_DIR + "/cgi-util-tests/group.htm");
        CPPUNIT_ASSERT(
            Ancillary::find_group_ancillary_file((string) TEST_SRC_DIR + "/cgi-util-tests/group01.hdf", ".htm")
                == (string) TEST_SRC_DIR + "/cgi-util-tests/group.htm");
        CPPUNIT_ASSERT(
            Ancillary::find_group_ancillary_file((string) TEST_SRC_DIR + "/cgi-util-tests/group.hdf", ".htm") == "");
    }

    void read_ancillary_das_file_test()
    {
        DAS das;
        string dir = "";
        string file = "";
        Ancillary::read_ancillary_das(das, (string) TEST_SRC_DIR + "/das-testsuite/test.1.das", dir, file);
        CPPUNIT_ASSERT(das.get_size() == 1);
    }

};

CPPUNIT_TEST_SUITE_REGISTRATION (ancT);

int main(int argc, char *argv[])
{
    return run_tests<ancT>(argc, argv) ? 0: 1;
}
<commit_msg>Removed extra header (#189)<commit_after>// -*- mode: c++; c-basic-offset:4 -*-

// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.

// Copyright (c) 2002,2003 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// 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
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.

#include <cppunit/TextTestRunner.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/extensions/HelperMacros.h>

#ifndef TM_IN_SYS_TIME
#include <time.h>
#else
#include <sys/time.h>
#endif

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>   // for stat

#include <string>
#include <sstream>

#include "Ancillary.h"
#include "DDS.h"
#include "debug.h"

#include "run_tests_cppunit.h"
#include "test_config.h"

using namespace CppUnit;
using namespace std;
using namespace libdap;

class ancT: public TestFixture {
private:

protected:

public:
    ancT() = default;
    ~ancT() = default;

    CPPUNIT_TEST_SUITE (ancT);

    CPPUNIT_TEST (find_ancillary_file_test);
    CPPUNIT_TEST (find_group_ancillary_file_test);
    CPPUNIT_TEST (read_ancillary_das_file_test);

    CPPUNIT_TEST_SUITE_END();

    void find_ancillary_file_test()
    {
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testsuite/test.1", "das", "", "")
                == (string) TEST_SRC_DIR + "/das-testsuite/test.1.das");
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testsuite/special.test.hdf", "das", "", "")
                == (string) TEST_SRC_DIR + "/das-testsuite/special.test.das");
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testsuite/test.2", "das", "", "")
                == (string) TEST_SRC_DIR + "/das-testsuite/das");
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testsuite/test.1.gz", "das", "", "")
                == (string) TEST_SRC_DIR + "/das-testsuite/test.1.das");
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testsuite/test.3.Z", "das", "", "")
                == (string) TEST_SRC_DIR + "/das-testsuite/test.3.Z.das");
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testste/test_1", "das", (string) TEST_SRC_DIR + "/das-testsuite/", "")
            == (string) TEST_SRC_DIR + "/das-testsuite/test_1.das");
        Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testsuite/te1", "das", (string) TEST_SRC_DIR + "/das-testite/", "");
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testsuite/te1", "das", (string) TEST_SRC_DIR + "/das-testite/", "")
            == (string) TEST_SRC_DIR + "/das-testsuite/das");
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testste/test1", "das", (string) TEST_SRC_DIR + "/das-testsuite/", "")
            == (string) TEST_SRC_DIR + "/das-testsuite/das");
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testste/test1", "das", (string) TEST_SRC_DIR + "/das-testsuite/", "test.1")
            == (string) TEST_SRC_DIR + "/das-testsuite/test.1.das");
        CPPUNIT_ASSERT(
            Ancillary::find_ancillary_file((string) TEST_SRC_DIR + "/das-testste/test1", "ds", (string) TEST_SRC_DIR + "/das-testsuite/", "")
            == "");
    }

    void find_group_ancillary_file_test()
    {
        CPPUNIT_ASSERT(
            Ancillary::find_group_ancillary_file((string) TEST_SRC_DIR + "/cgi-util-tests/02group.hdf", ".htm")
                == (string) TEST_SRC_DIR + "/cgi-util-tests/group.htm");
        CPPUNIT_ASSERT(
            Ancillary::find_group_ancillary_file((string) TEST_SRC_DIR + "/cgi-util-tests/group01.hdf", ".htm")
                == (string) TEST_SRC_DIR + "/cgi-util-tests/group.htm");
        CPPUNIT_ASSERT(
            Ancillary::find_group_ancillary_file((string) TEST_SRC_DIR + "/cgi-util-tests/group.hdf", ".htm") == "");
    }

    void read_ancillary_das_file_test()
    {
        DAS das;
        string dir = "";
        string file = "";
        Ancillary::read_ancillary_das(das, (string) TEST_SRC_DIR + "/das-testsuite/test.1.das", dir, file);
        CPPUNIT_ASSERT(das.get_size() == 1);
    }

};

CPPUNIT_TEST_SUITE_REGISTRATION (ancT);

int main(int argc, char *argv[])
{
    return run_tests<ancT>(argc, argv) ? 0: 1;
}
<|endoftext|>


<commit_before>/*
 * This file is distributed under the terms in the attached LICENSE file.
 * If you do not find this file, copies can be found by writing to:
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300,
 * Berkeley, CA, 94704.  Attention:  Intel License Inquiry.
 * Or
 * UC Berkeley EECS Computer Science Division, 387 Soda Hall #1776,
 * Berkeley, CA,  94707. Attention: P2 Group.
 */

#include "boost/test/unit_test.hpp"
using boost::unit_test_framework::test_suite;

#include "testPel.h"
#include "testTable2.h"
#include "testMarshal.h"
#include "testBasicElementPlumbing.h"
#include "testFdbufs.h"
#include "testValues.h"
#include "testCsv.h"
#include "testTables.h"
#include "testIDs.h"

#include "testLists.C"

test_suite* init_unit_test_suite(int, char**)
{
  test_suite *top = BOOST_TEST_SUITE("P2 Unit Test Suite");

  top->add(new testPel_testSuite());
  top->add(new testTable2_testSuite());
  top->add(new testMarshal_testSuite());
  top->add(new testBasicElementPlumbing_testSuite());
  top->add(new testFdbufs_testSuite());
  top->add(new testValues_testSuite());
  top->add(new testCsv_testSuite());

  top->add(new testTables_testSuite());
  top->add(new testIDs_testSuite());
  top->add(new testLists_testSuite());
  return top;
}
<commit_msg>Fixed p2Test to only include .h's<commit_after>/*
 * This file is distributed under the terms in the attached LICENSE file.
 * If you do not find this file, copies can be found by writing to:
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300,
 * Berkeley, CA, 94704.  Attention:  Intel License Inquiry.
 * Or
 * UC Berkeley EECS Computer Science Division, 387 Soda Hall #1776,
 * Berkeley, CA,  94707. Attention: P2 Group.
 */

#include "boost/test/unit_test.hpp"
using boost::unit_test_framework::test_suite;

#include "testPel.h"
#include "testTable2.h"
#include "testMarshal.h"
#include "testBasicElementPlumbing.h"
#include "testFdbufs.h"
#include "testValues.h"
#include "testCsv.h"
#include "testTables.h"
#include "testIDs.h"
#include "testLists.h"

test_suite* init_unit_test_suite(int, char**)
{
  test_suite *top = BOOST_TEST_SUITE("P2 Unit Test Suite");

  top->add(new testPel_testSuite());
  top->add(new testTable2_testSuite());
  top->add(new testMarshal_testSuite());
  top->add(new testBasicElementPlumbing_testSuite());
  top->add(new testFdbufs_testSuite());
  top->add(new testValues_testSuite());
  top->add(new testCsv_testSuite());
  top->add(new testTables_testSuite());
  top->add(new testIDs_testSuite());
  top->add(new testLists_testSuite());
  return top;
}
<|endoftext|>


<commit_before>#ifndef EQ_SOLVER_HPP
#define EQ_SOLVER_HPP

#include "expr.hpp"
#include "util.hpp"

#if defined(__DEPRECATED)
#define EQ_DEPRECATED
#undef __DEPRECATED // Hack to silence gcc
#endif

// or-tools
#include <constraint_solver/constraint_solver.h>

// Restore
#if defined(EQ_DEPRECATED)
#undef EQ_DEPRECATED
#define __DEPRECATED
#endif

namespace eq {
namespace op= operations_research;

class Solver {
public:

	void addVar(int& ref)
	{
		intVars.emplace_back(&ref, solver.MakeIntVar(minInt, maxInt));
	}

	template <typename T>
	void addRelation(Expr<T> rel)
	{
		makeRel(*this, rel);
	}

	void apply()
	{
		std::vector<op::IntVar*> ints;
		for (auto&& m : intVars) {
			ints.push_back(m.model);
		}
		auto db= solver.MakePhase(ints, op::Solver::CHOOSE_FIRST_UNBOUND, op::Solver::ASSIGN_MIN_VALUE);
		solver.NewSearch(db);

		if (solver.NextSolution()) {
			for (auto&& var : intVars) {
				assert(var.actual && var.model);
				*var.actual= var.model->Value();
			}
		} else {
			std::cout << "Solving error, failure count: " << solver.failures() << std::endl;
		}

		solver.EndSearch();
	}

private:
	template <typename T>
	struct VarInfo {
		VarInfo()= default;
		VarInfo(T* actual, op::IntVar* model)
			: actual(actual)
			, model(model)
		{ }
		VarInfo(const VarInfo&)= default;
		VarInfo(VarInfo&& other) : VarInfo(other) {}

		VarInfo& operator=(const VarInfo&)= default;
		VarInfo& operator=(VarInfo&& other){
			// std::vector insists using move assign even when its deleted... (gcc 4.8.1)
			return operator=(other);
		}

		T* actual= nullptr;
		op::IntVar* model= nullptr;
	};

	template <typename T>
	struct MakeRel {
		static_assert(!sizeof(T), "Solving for particular expr not implemented");
	};

	/// @todo Simplify expression trees so that unsupported operations vanish
	/// @todo Check if IntExpr::Var() calls could be omitted
	/// Creates solver constraints matching to expression
	template <typename E>
	static auto makeRel(Solver& self, E&& t)
	-> Return<decltype(&MakeRel<RemoveRef<E>>::eval)>
	{
		return MakeRel<RemoveRef<E>>::eval(self, t);
	}

	// Expressions to constraints -conversions

	template <typename T>
	struct MakeRel<Expr<T>> {
		static auto eval(Solver& self, Expr<T> e)
		-> decltype(makeRel(self, e.get()))
		{
			return makeRel(self, e.get());
		}
	};

	template <typename T>
	struct MakeRel<Var<T>> {
		static op::IntVar* eval(Solver& self, Var<T>& v)
		{
			return self.getVarInfo(v.get()).model;
		}
	};

	template <typename T>
	struct MakeRel<Constant<T>> {
		static op::IntVar* eval(Solver& self, Constant<T> v)
		{
			/// @todo Not sure if leaks
			return self.solver.MakeIntConst(v.get());
		}
	};

	template <typename T1, typename T2>
	struct MakeRel<BiOp<T1, T2, Add>> {
		static op::IntVar* eval(Solver& self, BiOp<T1, T2, Add> e)
		{
			return self.solver.MakeSum(	makeRel(self, e.lhs),
										makeRel(self, e.rhs))->Var();
		}
	};

	template <typename T1, typename T2>
	struct MakeRel<BiOp<T1, T2, Sub>> {
		static op::IntVar* eval(Solver& self, BiOp<T1, T2, Sub> e)
		{
			return self.solver.MakeDifference(	makeRel(self, e.lhs),
												makeRel(self, e.rhs))->Var();
		}
	};

	template <typename T1, typename T2>
	struct MakeRel<BiOp<T1, T2, Mul>> {
		static op::IntVar* eval(Solver& self, BiOp<T1, T2, Mul> e)
		{
			return self.solver.MakeProd(makeRel(self, e.lhs),
										makeRel(self, e.rhs))->Var();
		}
	};

	template <typename T1, typename T2>
	struct MakeRel<BiOp<T1, T2, Div>> {
		static op::IntVar* eval(Solver& self, BiOp<T1, T2, Div> e)
		{
			return self.solver.MakeDiv(	makeRel(self, e.lhs),
										makeRel(self, e.rhs))->Var();
		}
	};

	template <typename T>
	struct MakeRel<UOp<T, Pos>> {
		static op::IntVar* eval(Solver& self, UOp<T, Pos> op)
		{
			return makeRel(self, op.e);
		}
	};

	template <typename T>
	struct MakeRel<UOp<T, Neg>> {
		static op::IntVar* eval(Solver& self, UOp<T, Neg> op)
		{
			return self.solver.MakeOpposite(makeRel(self, op.e))->Var();
		}
	};

	template <typename T1, typename T2>
	struct MakeRel<BiOp<T1, T2, Eq>> {
		static void eval(Solver& self, BiOp<T1, T2, Eq> e)
		{
			auto constraint= self.solver.MakeEquality(	makeRel(self, e.lhs),
														makeRel(self, e.rhs));
			self.solver.AddConstraint(constraint);
		}
	};

	template <typename T1, typename T2>
	struct MakeRel<BiOp<T1, T2, Neq>> {
		static void eval(Solver& self, BiOp<T1, T2, Neq> e)
		{
			auto constraint= self.solver.MakeNonEquality(	makeRel(self, e.lhs),
															makeRel(self, e.rhs));
			self.solver.AddConstraint(constraint);
		}
	};

	template <typename T1, typename T2>
	struct MakeRel<BiOp<T1, T2, Gr>> {
		static void eval(Solver& self, BiOp<T1, T2, Gr> e)
		{
			auto constraint= self.solver.MakeGreater(	makeRel(self, e.lhs),
														makeRel(self, e.rhs));
			self.solver.AddConstraint(constraint);
		}
	};

	template <typename T1, typename T2>
	struct MakeRel<BiOp<T1, T2, Ls>> {
		static void eval(Solver& self, BiOp<T1, T2, Ls> e)
		{
			auto constraint= self.solver.MakeLess(	makeRel(self, e.lhs),
													makeRel(self, e.rhs));
			self.solver.AddConstraint(constraint);
		}
	};

	template <typename T1, typename T2>
	struct MakeRel<BiOp<T1, T2, Geq>> {
		static void eval(Solver& self, BiOp<T1, T2, Geq> e)
		{
			auto constraint= self.solver.MakeGreaterOrEqual(makeRel(self, e.lhs),
															makeRel(self, e.rhs));
			self.solver.AddConstraint(constraint);
		}
	};

	template <typename T1, typename T2>
	struct MakeRel<BiOp<T1, T2, Leq>> {
		static void eval(Solver& self, BiOp<T1, T2, Leq> e)
		{
			auto constraint= self.solver.MakeLessOrEqual(	makeRel(self, e.lhs),
															makeRel(self, e.rhs));
			self.solver.AddConstraint(constraint);
		}
	};

	template <typename T1, typename T2>
	struct MakeRel<BiOp<T1, T2, And>> {
		static void eval(Solver& self, BiOp<T1, T2, And> e)
		{
			static_assert(isRelation<T1>() && isRelation<T2>(),
					"Invalid exprs for && operator");
			MakeRel<T1>::eval(self, e.lhs);
			MakeRel<T2>::eval(self, e.rhs);
		}
	};

	template <typename T1, typename T2>
	struct MakeRel<BiOp<T1, T2, Or>> {
		static void eval(Solver& self, BiOp<T1, T2, Or> e)
		{
			static_assert(!sizeof(T1), "@todo ||");
		}
	};

	template <typename T>
	struct MakeRel<UOp<T, Not>> {
		static op::IntVar* eval(Solver& self, UOp<T, Not> e)
		{
			static_assert(!sizeof(T), "@todo Negation");
		}
	};

	VarInfo<int>& getVarInfo(const int& ref)
	{
		for (auto&& m : intVars) {
			if (m.actual == &ref)
				return m;
		}

		assert(0 && "var not found");
		throw "var not found";
	}

	// Completely arbitrary
	static constexpr int minInt= -9999;
	static constexpr int maxInt= 9999;

	op::Solver solver{"solver"};
	DynArray<VarInfo<int>> intVars;
};

} // eq

#endif // EQ_SOLVER_HPP
<commit_msg>Moved MakeRel struct outside Solver<commit_after>#ifndef EQ_SOLVER_HPP
#define EQ_SOLVER_HPP

#include "expr.hpp"
#include "util.hpp"

#include <stdexcept>

#if defined(__DEPRECATED)
#define EQ_DEPRECATED
#undef __DEPRECATED // Hack to silence gcc
#endif

// or-tools
#include <constraint_solver/constraint_solver.h>

// Restore
#if defined(EQ_DEPRECATED)
#undef EQ_DEPRECATED
#define __DEPRECATED
#endif

namespace eq {
namespace op= operations_research;
class Solver;

namespace detail {

template <typename T>
struct MakeRel {
	static_assert(!sizeof(T), "Solving for particular expr not implemented");
};

/// @todo Simplify expression trees so that unsupported operations vanish
/// @todo Check if IntExpr::Var() calls could be omitted
/// Creates solver constraints matching to expression
template <typename E>
static auto makeRel(Solver& self, E&& t)
-> Return<decltype(&MakeRel<RemoveRef<E>>::eval)>
{
	return detail::MakeRel<RemoveRef<E>>::eval(self, t);
}

} // detail

class Solver {
public:

	void addVar(int& ref)
	{
		intVars.emplace_back(&ref, solver.MakeIntVar(minInt, maxInt));
	}

	template <typename T>
	void addRelation(Expr<T> rel)
	{
		detail::makeRel(*this, rel);
	}

	/// Solve and apply results
	void apply()
	{
		std::vector<op::IntVar*> ints;
		for (auto&& m : intVars) {
			ints.push_back(m.model);
		}
		auto db= solver.MakePhase(ints, op::Solver::CHOOSE_FIRST_UNBOUND, op::Solver::ASSIGN_MIN_VALUE);
		solver.NewSearch(db);

		if (solver.NextSolution()) {
			for (auto&& var : intVars) {
				assert(var.actual && var.model);
				*var.actual= var.model->Value();
			}
		} else {
			std::cout << "Solving error, failure count: " << solver.failures() << std::endl;
		}

		solver.EndSearch();
	}

private:
	template <typename T>
	friend class detail::MakeRel;

	template <typename T>
	struct VarInfo {
		VarInfo()= default;
		VarInfo(T* actual, op::IntVar* model)
			: actual(actual)
			, model(model)
		{ }
		VarInfo(const VarInfo&)= default;
		VarInfo(VarInfo&& other) : VarInfo(other) {}

		VarInfo& operator=(const VarInfo&)= default;
		VarInfo& operator=(VarInfo&& other){
			// std::vector insists using move assign even when its deleted... (gcc 4.8.1)
			return operator=(other);
		}

		T* actual= nullptr;
		op::IntVar* model= nullptr;
	};

	VarInfo<int>& getVarInfo(const int& ref)
	{
		for (auto&& m : intVars) {
			if (m.actual == &ref)
				return m;
		}

		throw std::runtime_error{"var not found"};
	}

	// Completely arbitrary
	/// @todo Remove limits
	static constexpr int minInt= -9999;
	static constexpr int maxInt= 9999;

	op::Solver solver{"solver"};
	DynArray<VarInfo<int>> intVars;
};

namespace detail {

// Expressions to constraints -conversions

template <typename T>
struct MakeRel<Expr<T>> {
	static auto eval(Solver& self, Expr<T> e)
	-> decltype(makeRel(self, e.get()))
	{
		return makeRel(self, e.get());
	}
};

template <typename T>
struct MakeRel<Var<T>> {
	static op::IntVar* eval(Solver& self, Var<T>& v)
	{
		return self.getVarInfo(v.get()).model;
	}
};

template <typename T>
struct MakeRel<Constant<T>> {
	static op::IntVar* eval(Solver& self, Constant<T> v)
	{
		/// @todo Not sure if leaks
		return self.solver.MakeIntConst(v.get());
	}
};

template <typename T1, typename T2>
struct MakeRel<BiOp<T1, T2, Add>> {
	static op::IntVar* eval(Solver& self, BiOp<T1, T2, Add> e)
	{
		return self.solver.MakeSum(	makeRel(self, e.lhs),
									makeRel(self, e.rhs))->Var();
	}
};

template <typename T1, typename T2>
struct MakeRel<BiOp<T1, T2, Sub>> {
	static op::IntVar* eval(Solver& self, BiOp<T1, T2, Sub> e)
	{
		return self.solver.MakeDifference(	makeRel(self, e.lhs),
											makeRel(self, e.rhs))->Var();
	}
};

template <typename T1, typename T2>
struct MakeRel<BiOp<T1, T2, Mul>> {
	static op::IntVar* eval(Solver& self, BiOp<T1, T2, Mul> e)
	{
		return self.solver.MakeProd(makeRel(self, e.lhs),
									makeRel(self, e.rhs))->Var();
	}
};

template <typename T1, typename T2>
struct MakeRel<BiOp<T1, T2, Div>> {
	static op::IntVar* eval(Solver& self, BiOp<T1, T2, Div> e)
	{
		return self.solver.MakeDiv(	makeRel(self, e.lhs),
									makeRel(self, e.rhs))->Var();
	}
};

template <typename T>
struct MakeRel<UOp<T, Pos>> {
	static op::IntVar* eval(Solver& self, UOp<T, Pos> op)
	{
		return makeRel(self, op.e);
	}
};

template <typename T>
struct MakeRel<UOp<T, Neg>> {
	static op::IntVar* eval(Solver& self, UOp<T, Neg> op)
	{
		return self.solver.MakeOpposite(makeRel(self, op.e))->Var();
	}
};

template <typename T1, typename T2>
struct MakeRel<BiOp<T1, T2, Eq>> {
	static void eval(Solver& self, BiOp<T1, T2, Eq> e)
	{
		auto constraint= self.solver.MakeEquality(	makeRel(self, e.lhs),
													makeRel(self, e.rhs));
		self.solver.AddConstraint(constraint);
	}
};

template <typename T1, typename T2>
struct MakeRel<BiOp<T1, T2, Neq>> {
	static void eval(Solver& self, BiOp<T1, T2, Neq> e)
	{
		auto constraint= self.solver.MakeNonEquality(	makeRel(self, e.lhs),
														makeRel(self, e.rhs));
		self.solver.AddConstraint(constraint);
	}
};

template <typename T1, typename T2>
struct MakeRel<BiOp<T1, T2, Gr>> {
	static void eval(Solver& self, BiOp<T1, T2, Gr> e)
	{
		auto constraint= self.solver.MakeGreater(	makeRel(self, e.lhs),
													makeRel(self, e.rhs));
		self.solver.AddConstraint(constraint);
	}
};

template <typename T1, typename T2>
struct MakeRel<BiOp<T1, T2, Ls>> {
	static void eval(Solver& self, BiOp<T1, T2, Ls> e)
	{
		auto constraint= self.solver.MakeLess(	makeRel(self, e.lhs),
												makeRel(self, e.rhs));
		self.solver.AddConstraint(constraint);
	}
};

template <typename T1, typename T2>
struct MakeRel<BiOp<T1, T2, Geq>> {
	static void eval(Solver& self, BiOp<T1, T2, Geq> e)
	{
		auto constraint= self.solver.MakeGreaterOrEqual(makeRel(self, e.lhs),
														makeRel(self, e.rhs));
		self.solver.AddConstraint(constraint);
	}
};

template <typename T1, typename T2>
struct MakeRel<BiOp<T1, T2, Leq>> {
	static void eval(Solver& self, BiOp<T1, T2, Leq> e)
	{
		auto constraint= self.solver.MakeLessOrEqual(	makeRel(self, e.lhs),
														makeRel(self, e.rhs));
		self.solver.AddConstraint(constraint);
	}
};

template <typename T1, typename T2>
struct MakeRel<BiOp<T1, T2, And>> {
	static void eval(Solver& self, BiOp<T1, T2, And> e)
	{
		static_assert(isRelation<T1>() && isRelation<T2>(),
				"Invalid exprs for && operator");
		MakeRel<T1>::eval(self, e.lhs);
		MakeRel<T2>::eval(self, e.rhs);
	}
};

template <typename T1, typename T2>
struct MakeRel<BiOp<T1, T2, Or>> {
	static void eval(Solver& self, BiOp<T1, T2, Or> e)
	{
		static_assert(!sizeof(T1), "@todo ||");
	}
};

template <typename T>
struct MakeRel<UOp<T, Not>> {
	static op::IntVar* eval(Solver& self, UOp<T, Not> e)
	{
		static_assert(!sizeof(T), "@todo Negation");
	}
};

} // detail
} // eq

#endif // EQ_SOLVER_HPP
<|endoftext|>


<commit_before>//===-- NEONMoveFix.cpp - Convert vfp reg-reg moves into neon ---*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "neon-mov-fix"
#include "ARM.h"
#include "ARMMachineFunctionInfo.h"
#include "ARMInstrInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

STATISTIC(NumVMovs, "Number of reg-reg moves converted");

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

    virtual bool runOnMachineFunction(MachineFunction &Fn);

    virtual const char *getPassName() const {
      return "NEON reg-reg move conversion";
    }

  private:
    const TargetRegisterInfo *TRI;
    const ARMBaseInstrInfo *TII;

    typedef DenseMap<unsigned, const MachineInstr*> RegMap;

    bool InsertMoves(MachineBasicBlock &MBB);
  };
  char NEONMoveFixPass::ID = 0;
}

bool NEONMoveFixPass::InsertMoves(MachineBasicBlock &MBB) {
  RegMap Defs;
  bool Modified = false;

  // Walk over MBB tracking the def points of the registers.
  MachineBasicBlock::iterator MII = MBB.begin(), E = MBB.end();
  MachineBasicBlock::iterator NextMII;
  for (; MII != E; MII = NextMII) {
    NextMII = llvm::next(MII);
    MachineInstr *MI = &*MII;

    if (MI->getOpcode() == ARM::VMOVD &&
        !TII->isPredicated(MI)) {
      unsigned SrcReg = MI->getOperand(1).getReg();
      // If we do not find an instruction defining the reg, this means the
      // register should be live-in for this BB. It's always to better to use
      // NEON reg-reg moves.
      unsigned Domain = ARMII::DomainNEON;
      RegMap::iterator DefMI = Defs.find(SrcReg);
      if (DefMI != Defs.end()) {
        Domain = DefMI->second->getDesc().TSFlags & ARMII::DomainMask;
        // Instructions in general domain are subreg accesses.
        // Map them to NEON reg-reg moves.
        if (Domain == ARMII::DomainGeneral)
          Domain = ARMII::DomainNEON;
      }

      if (Domain & ARMII::DomainNEON) {
        // Convert VMOVD to VMOVDneon
        unsigned DestReg = MI->getOperand(0).getReg();

        DEBUG({errs() << "vmov convert: "; MI->dump();});

        // It's safe to ignore imp-defs / imp-uses here, since:
        //  - We're running late, no intelligent condegen passes should be run
        //    afterwards
        //  - The imp-defs / imp-uses are superregs only, we don't care about
        //    them.
        AddDefaultPred(BuildMI(MBB, *MI, MI->getDebugLoc(),
                             TII->get(ARM::VMOVDneon), DestReg).addReg(SrcReg));
        MBB.erase(MI);
        MachineBasicBlock::iterator I = prior(NextMII);
        MI = &*I;

        DEBUG({errs() << "        into: "; MI->dump();});

        Modified = true;
        ++NumVMovs;
      } else {
        assert((Domain & ARMII::DomainVFP) && "Invalid domain!");
        // Do nothing.
      }
    }

    // Update def information.
    for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
      const MachineOperand& MO = MI->getOperand(i);
      if (!MO.isReg() || !MO.isDef())
        continue;
      unsigned MOReg = MO.getReg();

      Defs[MOReg] = MI;
      // Catch subregs as well.
      for (const unsigned *R = TRI->getSubRegisters(MOReg); *R; ++R)
        Defs[*R] = MI;
    }
  }

  return Modified;
}

bool NEONMoveFixPass::runOnMachineFunction(MachineFunction &Fn) {
  ARMFunctionInfo *AFI = Fn.getInfo<ARMFunctionInfo>();
  const TargetMachine &TM = Fn.getTarget();

  if (AFI->isThumb1OnlyFunction())
    return false;

  TRI = TM.getRegisterInfo();
  TII = static_cast<const ARMBaseInstrInfo*>(TM.getInstrInfo());

  bool Modified = false;
  for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
       ++MFI) {
    MachineBasicBlock &MBB = *MFI;
    Modified |= InsertMoves(MBB);
  }

  return Modified;
}

/// createNEONMoveFixPass - Returns an instance of the NEON reg-reg moves fix
/// pass.
FunctionPass *llvm::createNEONMoveFixPass() {
  return new NEONMoveFixPass();
}
<commit_msg>Track defs for all aliases in NEONMoveFix.<commit_after>//===-- NEONMoveFix.cpp - Convert vfp reg-reg moves into neon ---*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "neon-mov-fix"
#include "ARM.h"
#include "ARMMachineFunctionInfo.h"
#include "ARMInstrInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

STATISTIC(NumVMovs, "Number of reg-reg moves converted");

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

    virtual bool runOnMachineFunction(MachineFunction &Fn);

    virtual const char *getPassName() const {
      return "NEON reg-reg move conversion";
    }

  private:
    const TargetRegisterInfo *TRI;
    const ARMBaseInstrInfo *TII;

    typedef DenseMap<unsigned, const MachineInstr*> RegMap;

    bool InsertMoves(MachineBasicBlock &MBB);
  };
  char NEONMoveFixPass::ID = 0;
}

bool NEONMoveFixPass::InsertMoves(MachineBasicBlock &MBB) {
  RegMap Defs;
  bool Modified = false;

  // Walk over MBB tracking the def points of the registers.
  MachineBasicBlock::iterator MII = MBB.begin(), E = MBB.end();
  MachineBasicBlock::iterator NextMII;
  for (; MII != E; MII = NextMII) {
    NextMII = llvm::next(MII);
    MachineInstr *MI = &*MII;

    if (MI->getOpcode() == ARM::VMOVD &&
        !TII->isPredicated(MI)) {
      unsigned SrcReg = MI->getOperand(1).getReg();
      // If we do not find an instruction defining the reg, this means the
      // register should be live-in for this BB. It's always to better to use
      // NEON reg-reg moves.
      unsigned Domain = ARMII::DomainNEON;
      RegMap::iterator DefMI = Defs.find(SrcReg);
      if (DefMI != Defs.end()) {
        Domain = DefMI->second->getDesc().TSFlags & ARMII::DomainMask;
        // Instructions in general domain are subreg accesses.
        // Map them to NEON reg-reg moves.
        if (Domain == ARMII::DomainGeneral)
          Domain = ARMII::DomainNEON;
      }

      if (Domain & ARMII::DomainNEON) {
        // Convert VMOVD to VMOVDneon
        unsigned DestReg = MI->getOperand(0).getReg();

        DEBUG({errs() << "vmov convert: "; MI->dump();});

        // It's safe to ignore imp-defs / imp-uses here, since:
        //  - We're running late, no intelligent condegen passes should be run
        //    afterwards
        //  - The imp-defs / imp-uses are superregs only, we don't care about
        //    them.
        AddDefaultPred(BuildMI(MBB, *MI, MI->getDebugLoc(),
                             TII->get(ARM::VMOVDneon), DestReg).addReg(SrcReg));
        MBB.erase(MI);
        MachineBasicBlock::iterator I = prior(NextMII);
        MI = &*I;

        DEBUG({errs() << "        into: "; MI->dump();});

        Modified = true;
        ++NumVMovs;
      } else {
        assert((Domain & ARMII::DomainVFP) && "Invalid domain!");
        // Do nothing.
      }
    }

    // Update def information.
    for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
      const MachineOperand& MO = MI->getOperand(i);
      if (!MO.isReg() || !MO.isDef())
        continue;
      unsigned MOReg = MO.getReg();

      Defs[MOReg] = MI;
      // Catch aliases as well.
      for (const unsigned *R = TRI->getAliasSet(MOReg); *R; ++R)
        Defs[*R] = MI;
    }
  }

  return Modified;
}

bool NEONMoveFixPass::runOnMachineFunction(MachineFunction &Fn) {
  ARMFunctionInfo *AFI = Fn.getInfo<ARMFunctionInfo>();
  const TargetMachine &TM = Fn.getTarget();

  if (AFI->isThumb1OnlyFunction())
    return false;

  TRI = TM.getRegisterInfo();
  TII = static_cast<const ARMBaseInstrInfo*>(TM.getInstrInfo());

  bool Modified = false;
  for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
       ++MFI) {
    MachineBasicBlock &MBB = *MFI;
    Modified |= InsertMoves(MBB);
  }

  return Modified;
}

/// createNEONMoveFixPass - Returns an instance of the NEON reg-reg moves fix
/// pass.
FunctionPass *llvm::createNEONMoveFixPass() {
  return new NEONMoveFixPass();
}
<|endoftext|>


<commit_before>//===- Inliner.cpp - Code common to all inliners --------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the mechanics required to implement inlining without
// missing any calls and updating the call graph.  The decisions of which calls
// are profitable to inline are implemented elsewhere.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "inline"
#include "llvm/Module.h"
#include "llvm/Instructions.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Transforms/IPO/InlinerPass.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/Statistic.h"
#include <set>
using namespace llvm;

STATISTIC(NumInlined, "Number of functions inlined");
STATISTIC(NumDeleted, "Number of functions deleted because all callers found");

static cl::opt<int>
InlineLimit("inline-threshold", cl::Hidden, cl::init(200),
        cl::desc("Control the amount of inlining to perform (default = 200)"));

Inliner::Inliner(void *ID)
  : CallGraphSCCPass(ID), InlineThreshold(InlineLimit) {}

Inliner::Inliner(void *ID, int Threshold)
  : CallGraphSCCPass(ID), InlineThreshold(Threshold) {}

/// getAnalysisUsage - For this class, we declare that we require and preserve
/// the call graph.  If the derived class implements this method, it should
/// always explicitly call the implementation here.
void Inliner::getAnalysisUsage(AnalysisUsage &Info) const {
  Info.addRequired<TargetData>();
  CallGraphSCCPass::getAnalysisUsage(Info);
}

// InlineCallIfPossible - If it is possible to inline the specified call site,
// do so and update the CallGraph for this operation.
bool Inliner::InlineCallIfPossible(CallSite CS, CallGraph &CG,
                                 const SmallPtrSet<Function*, 8> &SCCFunctions,
                                 const TargetData &TD) {
  Function *Callee = CS.getCalledFunction();
  Function *Caller = CS.getCaller();

  if (!InlineFunction(CS, &CG, &TD)) return false;

  // If the inlined function had a higher stack protection level than the
  // calling function, then bump up the caller's stack protection level.
  if (Callee->hasFnAttr(Attribute::StackProtectReq))
    Caller->addFnAttr(Attribute::StackProtectReq);
  else if (Callee->hasFnAttr(Attribute::StackProtect) &&
           !Caller->hasFnAttr(Attribute::StackProtectReq))
    Caller->addFnAttr(Attribute::StackProtect);

  // If we inlined the last possible call site to the function, delete the
  // function body now.
  if (Callee->use_empty() && (Callee->hasLocalLinkage() ||
                              Callee->hasAvailableExternallyLinkage()) &&
      !SCCFunctions.count(Callee)) {
    DOUT << "    -> Deleting dead function: " << Callee->getName() << "\n";
    CallGraphNode *CalleeNode = CG[Callee];

    // Remove any call graph edges from the callee to its callees.
    CalleeNode->removeAllCalledFunctions();

    resetCachedCostInfo(CalleeNode->getFunction());

    // Removing the node for callee from the call graph and delete it.
    delete CG.removeFunctionFromModule(CalleeNode);
    ++NumDeleted;
  }
  return true;
}

/// shouldInline - Return true if the inliner should attempt to inline
/// at the given CallSite.
bool Inliner::shouldInline(CallSite CS) {
  InlineCost IC = getInlineCost(CS);
  float FudgeFactor = getInlineFudgeFactor(CS);

  if (IC.isAlways()) {
    DOUT << "    Inlining: cost=always"
         << ", Call: " << *CS.getInstruction();
    return true;
  }

  if (IC.isNever()) {
    DOUT << "    NOT Inlining: cost=never"
         << ", Call: " << *CS.getInstruction();
    return false;
  }

  int Cost = IC.getValue();
  int CurrentThreshold = InlineThreshold;
  Function *Fn = CS.getCaller();
  if (Fn && !Fn->isDeclaration()
      && Fn->hasFnAttr(Attribute::OptimizeForSize)
      && InlineThreshold != 50) {
    CurrentThreshold = 50;
  }

  if (Cost >= (int)(CurrentThreshold * FudgeFactor)) {
    DOUT << "    NOT Inlining: cost=" << Cost
         << ", Call: " << *CS.getInstruction();
    return false;
  } else {
    DOUT << "    Inlining: cost=" << Cost
         << ", Call: " << *CS.getInstruction();
    return true;
  }
}

bool Inliner::runOnSCC(const std::vector<CallGraphNode*> &SCC) {
  CallGraph &CG = getAnalysis<CallGraph>();
  TargetData &TD = getAnalysis<TargetData>();

  SmallPtrSet<Function*, 8> SCCFunctions;
  DOUT << "Inliner visiting SCC:";
  for (unsigned i = 0, e = SCC.size(); i != e; ++i) {
    Function *F = SCC[i]->getFunction();
    if (F) SCCFunctions.insert(F);
    DOUT << " " << (F ? F->getName() : "INDIRECTNODE");
  }

  // Scan through and identify all call sites ahead of time so that we only
  // inline call sites in the original functions, not call sites that result
  // from inlining other functions.
  std::vector<CallSite> CallSites;

  for (unsigned i = 0, e = SCC.size(); i != e; ++i)
    if (Function *F = SCC[i]->getFunction())
      for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
        for (BasicBlock::iterator I = BB->begin(); I != BB->end(); ++I) {
          CallSite CS = CallSite::get(I);
          if (CS.getInstruction() && !isa<DbgInfoIntrinsic>(I) &&
                                     (!CS.getCalledFunction() ||
                                      !CS.getCalledFunction()->isDeclaration()))
            CallSites.push_back(CS);
        }

  DOUT << ": " << CallSites.size() << " call sites.\n";

  // Now that we have all of the call sites, move the ones to functions in the
  // current SCC to the end of the list.
  unsigned FirstCallInSCC = CallSites.size();
  for (unsigned i = 0; i < FirstCallInSCC; ++i)
    if (Function *F = CallSites[i].getCalledFunction())
      if (SCCFunctions.count(F))
        std::swap(CallSites[i--], CallSites[--FirstCallInSCC]);

  // Now that we have all of the call sites, loop over them and inline them if
  // it looks profitable to do so.
  bool Changed = false;
  bool LocalChange;
  do {
    LocalChange = false;
    // Iterate over the outer loop because inlining functions can cause indirect
    // calls to become direct calls.
    for (unsigned CSi = 0; CSi != CallSites.size(); ++CSi)
      if (Function *Callee = CallSites[CSi].getCalledFunction()) {
        // Calls to external functions are never inlinable.
        if (Callee->isDeclaration()) {
          if (SCC.size() == 1) {
            std::swap(CallSites[CSi], CallSites.back());
            CallSites.pop_back();
          } else {
            // Keep the 'in SCC / not in SCC' boundary correct.
            CallSites.erase(CallSites.begin()+CSi);
          }
          --CSi;
          continue;
        }

        // If the policy determines that we should inline this function,
        // try to do so.
        CallSite CS = CallSites[CSi];
        if (shouldInline(CS)) {
          Function *Caller = CS.getCaller();
          // Attempt to inline the function...
          if (InlineCallIfPossible(CS, CG, SCCFunctions, TD)) {
            // Remove any cached cost info for this caller, as inlining the
            // callee has increased the size of the caller (which may be the
            // same as the callee).
            resetCachedCostInfo(Caller);

            // Remove this call site from the list.  If possible, use
            // swap/pop_back for efficiency, but do not use it if doing so would
            // move a call site to a function in this SCC before the
            // 'FirstCallInSCC' barrier.
            if (SCC.size() == 1) {
              std::swap(CallSites[CSi], CallSites.back());
              CallSites.pop_back();
            } else {
              CallSites.erase(CallSites.begin()+CSi);
            }
            --CSi;

            ++NumInlined;
            Changed = true;
            LocalChange = true;
          }
        }
      }
  } while (LocalChange);

  return Changed;
}

// doFinalization - Remove now-dead linkonce functions at the end of
// processing to avoid breaking the SCC traversal.
bool Inliner::doFinalization(CallGraph &CG) {
  return removeDeadFunctions(CG);
}

  /// removeDeadFunctions - Remove dead functions that are not included in
  /// DNR (Do Not Remove) list.
bool Inliner::removeDeadFunctions(CallGraph &CG,
                                 SmallPtrSet<const Function *, 16> *DNR) {
  std::set<CallGraphNode*> FunctionsToRemove;

  // Scan for all of the functions, looking for ones that should now be removed
  // from the program.  Insert the dead ones in the FunctionsToRemove set.
  for (CallGraph::iterator I = CG.begin(), E = CG.end(); I != E; ++I) {
    CallGraphNode *CGN = I->second;
    if (Function *F = CGN ? CGN->getFunction() : 0) {
      // If the only remaining users of the function are dead constants, remove
      // them.
      F->removeDeadConstantUsers();

      if (DNR && DNR->count(F))
        continue;

      if ((F->hasLinkOnceLinkage() || F->hasLocalLinkage()) &&
          F->use_empty()) {

        // Remove any call graph edges from the function to its callees.
        CGN->removeAllCalledFunctions();

        // Remove any edges from the external node to the function's call graph
        // node.  These edges might have been made irrelegant due to
        // optimization of the program.
        CG.getExternalCallingNode()->removeAnyCallEdgeTo(CGN);

        // Removing the node for callee from the call graph and delete it.
        FunctionsToRemove.insert(CGN);
      }
    }
  }

  // Now that we know which functions to delete, do so.  We didn't want to do
  // this inline, because that would invalidate our CallGraph::iterator
  // objects. :(
  bool Changed = false;
  for (std::set<CallGraphNode*>::iterator I = FunctionsToRemove.begin(),
         E = FunctionsToRemove.end(); I != E; ++I) {
    resetCachedCostInfo((*I)->getFunction());
    delete CG.removeFunctionFromModule(*I);
    ++NumDeleted;
    Changed = true;
  }

  return Changed;
}
<commit_msg>Add line breaks to make the debug output a bit more readable.<commit_after>//===- Inliner.cpp - Code common to all inliners --------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the mechanics required to implement inlining without
// missing any calls and updating the call graph.  The decisions of which calls
// are profitable to inline are implemented elsewhere.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "inline"
#include "llvm/Module.h"
#include "llvm/Instructions.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Transforms/IPO/InlinerPass.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/Statistic.h"
#include <set>
using namespace llvm;

STATISTIC(NumInlined, "Number of functions inlined");
STATISTIC(NumDeleted, "Number of functions deleted because all callers found");

static cl::opt<int>
InlineLimit("inline-threshold", cl::Hidden, cl::init(200),
        cl::desc("Control the amount of inlining to perform (default = 200)"));

Inliner::Inliner(void *ID)
  : CallGraphSCCPass(ID), InlineThreshold(InlineLimit) {}

Inliner::Inliner(void *ID, int Threshold)
  : CallGraphSCCPass(ID), InlineThreshold(Threshold) {}

/// getAnalysisUsage - For this class, we declare that we require and preserve
/// the call graph.  If the derived class implements this method, it should
/// always explicitly call the implementation here.
void Inliner::getAnalysisUsage(AnalysisUsage &Info) const {
  Info.addRequired<TargetData>();
  CallGraphSCCPass::getAnalysisUsage(Info);
}

// InlineCallIfPossible - If it is possible to inline the specified call site,
// do so and update the CallGraph for this operation.
bool Inliner::InlineCallIfPossible(CallSite CS, CallGraph &CG,
                                 const SmallPtrSet<Function*, 8> &SCCFunctions,
                                 const TargetData &TD) {
  Function *Callee = CS.getCalledFunction();
  Function *Caller = CS.getCaller();

  if (!InlineFunction(CS, &CG, &TD)) return false;

  // If the inlined function had a higher stack protection level than the
  // calling function, then bump up the caller's stack protection level.
  if (Callee->hasFnAttr(Attribute::StackProtectReq))
    Caller->addFnAttr(Attribute::StackProtectReq);
  else if (Callee->hasFnAttr(Attribute::StackProtect) &&
           !Caller->hasFnAttr(Attribute::StackProtectReq))
    Caller->addFnAttr(Attribute::StackProtect);

  // If we inlined the last possible call site to the function, delete the
  // function body now.
  if (Callee->use_empty() && (Callee->hasLocalLinkage() ||
                              Callee->hasAvailableExternallyLinkage()) &&
      !SCCFunctions.count(Callee)) {
    DOUT << "    -> Deleting dead function: " << Callee->getName() << "\n";
    CallGraphNode *CalleeNode = CG[Callee];

    // Remove any call graph edges from the callee to its callees.
    CalleeNode->removeAllCalledFunctions();

    resetCachedCostInfo(CalleeNode->getFunction());

    // Removing the node for callee from the call graph and delete it.
    delete CG.removeFunctionFromModule(CalleeNode);
    ++NumDeleted;
  }
  return true;
}

/// shouldInline - Return true if the inliner should attempt to inline
/// at the given CallSite.
bool Inliner::shouldInline(CallSite CS) {
  InlineCost IC = getInlineCost(CS);
  float FudgeFactor = getInlineFudgeFactor(CS);

  if (IC.isAlways()) {
    DOUT << "    Inlining: cost=always"
         << ", Call: " << *CS.getInstruction() << "\n";
    return true;
  }

  if (IC.isNever()) {
    DOUT << "    NOT Inlining: cost=never"
         << ", Call: " << *CS.getInstruction() << "\n";
    return false;
  }

  int Cost = IC.getValue();
  int CurrentThreshold = InlineThreshold;
  Function *Fn = CS.getCaller();
  if (Fn && !Fn->isDeclaration()
      && Fn->hasFnAttr(Attribute::OptimizeForSize)
      && InlineThreshold != 50) {
    CurrentThreshold = 50;
  }

  if (Cost >= (int)(CurrentThreshold * FudgeFactor)) {
    DOUT << "    NOT Inlining: cost=" << Cost
         << ", Call: " << *CS.getInstruction() << "\n";
    return false;
  } else {
    DOUT << "    Inlining: cost=" << Cost
         << ", Call: " << *CS.getInstruction() << "\n";
    return true;
  }
}

bool Inliner::runOnSCC(const std::vector<CallGraphNode*> &SCC) {
  CallGraph &CG = getAnalysis<CallGraph>();
  TargetData &TD = getAnalysis<TargetData>();

  SmallPtrSet<Function*, 8> SCCFunctions;
  DOUT << "Inliner visiting SCC:";
  for (unsigned i = 0, e = SCC.size(); i != e; ++i) {
    Function *F = SCC[i]->getFunction();
    if (F) SCCFunctions.insert(F);
    DOUT << " " << (F ? F->getName() : "INDIRECTNODE");
  }

  // Scan through and identify all call sites ahead of time so that we only
  // inline call sites in the original functions, not call sites that result
  // from inlining other functions.
  std::vector<CallSite> CallSites;

  for (unsigned i = 0, e = SCC.size(); i != e; ++i)
    if (Function *F = SCC[i]->getFunction())
      for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
        for (BasicBlock::iterator I = BB->begin(); I != BB->end(); ++I) {
          CallSite CS = CallSite::get(I);
          if (CS.getInstruction() && !isa<DbgInfoIntrinsic>(I) &&
                                     (!CS.getCalledFunction() ||
                                      !CS.getCalledFunction()->isDeclaration()))
            CallSites.push_back(CS);
        }

  DOUT << ": " << CallSites.size() << " call sites.\n";

  // Now that we have all of the call sites, move the ones to functions in the
  // current SCC to the end of the list.
  unsigned FirstCallInSCC = CallSites.size();
  for (unsigned i = 0; i < FirstCallInSCC; ++i)
    if (Function *F = CallSites[i].getCalledFunction())
      if (SCCFunctions.count(F))
        std::swap(CallSites[i--], CallSites[--FirstCallInSCC]);

  // Now that we have all of the call sites, loop over them and inline them if
  // it looks profitable to do so.
  bool Changed = false;
  bool LocalChange;
  do {
    LocalChange = false;
    // Iterate over the outer loop because inlining functions can cause indirect
    // calls to become direct calls.
    for (unsigned CSi = 0; CSi != CallSites.size(); ++CSi)
      if (Function *Callee = CallSites[CSi].getCalledFunction()) {
        // Calls to external functions are never inlinable.
        if (Callee->isDeclaration()) {
          if (SCC.size() == 1) {
            std::swap(CallSites[CSi], CallSites.back());
            CallSites.pop_back();
          } else {
            // Keep the 'in SCC / not in SCC' boundary correct.
            CallSites.erase(CallSites.begin()+CSi);
          }
          --CSi;
          continue;
        }

        // If the policy determines that we should inline this function,
        // try to do so.
        CallSite CS = CallSites[CSi];
        if (shouldInline(CS)) {
          Function *Caller = CS.getCaller();
          // Attempt to inline the function...
          if (InlineCallIfPossible(CS, CG, SCCFunctions, TD)) {
            // Remove any cached cost info for this caller, as inlining the
            // callee has increased the size of the caller (which may be the
            // same as the callee).
            resetCachedCostInfo(Caller);

            // Remove this call site from the list.  If possible, use
            // swap/pop_back for efficiency, but do not use it if doing so would
            // move a call site to a function in this SCC before the
            // 'FirstCallInSCC' barrier.
            if (SCC.size() == 1) {
              std::swap(CallSites[CSi], CallSites.back());
              CallSites.pop_back();
            } else {
              CallSites.erase(CallSites.begin()+CSi);
            }
            --CSi;

            ++NumInlined;
            Changed = true;
            LocalChange = true;
          }
        }
      }
  } while (LocalChange);

  return Changed;
}

// doFinalization - Remove now-dead linkonce functions at the end of
// processing to avoid breaking the SCC traversal.
bool Inliner::doFinalization(CallGraph &CG) {
  return removeDeadFunctions(CG);
}

  /// removeDeadFunctions - Remove dead functions that are not included in
  /// DNR (Do Not Remove) list.
bool Inliner::removeDeadFunctions(CallGraph &CG,
                                 SmallPtrSet<const Function *, 16> *DNR) {
  std::set<CallGraphNode*> FunctionsToRemove;

  // Scan for all of the functions, looking for ones that should now be removed
  // from the program.  Insert the dead ones in the FunctionsToRemove set.
  for (CallGraph::iterator I = CG.begin(), E = CG.end(); I != E; ++I) {
    CallGraphNode *CGN = I->second;
    if (Function *F = CGN ? CGN->getFunction() : 0) {
      // If the only remaining users of the function are dead constants, remove
      // them.
      F->removeDeadConstantUsers();

      if (DNR && DNR->count(F))
        continue;

      if ((F->hasLinkOnceLinkage() || F->hasLocalLinkage()) &&
          F->use_empty()) {

        // Remove any call graph edges from the function to its callees.
        CGN->removeAllCalledFunctions();

        // Remove any edges from the external node to the function's call graph
        // node.  These edges might have been made irrelegant due to
        // optimization of the program.
        CG.getExternalCallingNode()->removeAnyCallEdgeTo(CGN);

        // Removing the node for callee from the call graph and delete it.
        FunctionsToRemove.insert(CGN);
      }
    }
  }

  // Now that we know which functions to delete, do so.  We didn't want to do
  // this inline, because that would invalidate our CallGraph::iterator
  // objects. :(
  bool Changed = false;
  for (std::set<CallGraphNode*>::iterator I = FunctionsToRemove.begin(),
         E = FunctionsToRemove.end(); I != E; ++I) {
    resetCachedCostInfo((*I)->getFunction());
    delete CG.removeFunctionFromModule(*I);
    ++NumDeleted;
    Changed = true;
  }

  return Changed;
}
<|endoftext|>