/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * vim: set ts=8 sts=4 et sw=4 tw=99:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "jit/x86-shared/Architecture-x86-shared.h"
#if !defined(JS_CODEGEN_X86) && !defined(JS_CODEGEN_X64)
# error "Wrong architecture. Only x86 and x64 should build this file!"
#endif

#include "jit/RegisterSets.h"

const char*
js::jit::FloatRegister::name() const {
    static const char* const names[] = {

#ifdef JS_CODEGEN_X64
#define FLOAT_REGS_(TYPE) \
        "%xmm0" TYPE, "%xmm1" TYPE, "%xmm2" TYPE, "%xmm3" TYPE, \
        "%xmm4" TYPE, "%xmm5" TYPE, "%xmm6" TYPE, "%xmm7" TYPE, \
        "%xmm8" TYPE, "%xmm9" TYPE, "%xmm10" TYPE, "%xmm11" TYPE, \
        "%xmm12" TYPE, "%xmm13" TYPE, "%xmm14" TYPE, "%xmm15" TYPE
#else
#define FLOAT_REGS_(TYPE) \
        "%xmm0" TYPE, "%xmm1" TYPE, "%xmm2" TYPE, "%xmm3" TYPE, \
        "%xmm4" TYPE, "%xmm5" TYPE, "%xmm6" TYPE, "%xmm7" TYPE
#endif

        // These should be enumerated in the same order as in
        // FloatRegisters::ContentType.
        FLOAT_REGS_(".s"),
        FLOAT_REGS_(".d"),
        FLOAT_REGS_(".i4"),
        FLOAT_REGS_(".s4")
#undef FLOAT_REGS_

    };
    MOZ_ASSERT(size_t(code()) < mozilla::ArrayLength(names));
    return names[size_t(code())];
}

js::jit::FloatRegisterSet
js::jit::FloatRegister::ReduceSetForPush(const FloatRegisterSet& s)
{
    SetType bits = s.bits();

    // Ignore all SIMD register, if not supported.
    if (!JitSupportsSimd())
        bits &= Codes::AllPhysMask * Codes::SpreadScalar;

    // Exclude registers which are already pushed with a larger type. High bits
    // are associated with larger register types. Thus we keep the set of
    // registers which are not included in larger type.
    bits &= ~(bits >> (1 * Codes::TotalPhys));
    bits &= ~(bits >> (2 * Codes::TotalPhys));
    bits &= ~(bits >> (3 * Codes::TotalPhys));

    return FloatRegisterSet(bits);
}

uint32_t
js::jit::FloatRegister::GetPushSizeInBytes(const FloatRegisterSet& s)
{
    SetType all = s.bits();
    SetType set128b =
        (all >> (uint32_t(Codes::Simd128) * Codes::TotalPhys)) & Codes::AllPhysMask;
    SetType doubleSet =
        (all >> (uint32_t(Codes::Double) * Codes::TotalPhys)) & Codes::AllPhysMask;
    SetType singleSet =
        (all >> (uint32_t(Codes::Single) * Codes::TotalPhys)) & Codes::AllPhysMask;

    // PushRegsInMask pushes the largest register first, and thus avoids pushing
    // aliased registers. So we have to filter out the physical registers which
    // are already pushed as part of larger registers.
    SetType set64b = doubleSet & ~set128b;
    SetType set32b = singleSet & ~set64b  & ~set128b;

    static_assert(Codes::AllPhysMask <= 0xffff, "We can safely use CountPopulation32");
    uint32_t count32b = mozilla::CountPopulation32(set32b);

#if defined(JS_CODEGEN_X64)
    // If we have an odd number of 32 bits values, then we increase the size to
    // keep the stack aligned on 8 bytes. Note: Keep in sync with
    // PushRegsInMask, and PopRegsInMaskIgnore.
    count32b += count32b & 1;
#endif

    return mozilla::CountPopulation32(set128b) * (4 * sizeof(int32_t))
        + mozilla::CountPopulation32(set64b) * sizeof(double)
        + count32b * sizeof(float);
}
uint32_t
js::jit::FloatRegister::getRegisterDumpOffsetInBytes()
{
    return uint32_t(encoding()) * sizeof(FloatRegisters::RegisterContent);
}