vfp.hh revision 7398
17375Sgblack@eecs.umich.edu/*
27375Sgblack@eecs.umich.edu * Copyright (c) 2010 ARM Limited
37375Sgblack@eecs.umich.edu * All rights reserved
47375Sgblack@eecs.umich.edu *
57375Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall
67375Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual
77375Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating
87375Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software
97375Sgblack@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
107375Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
117375Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
127375Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form.
137375Sgblack@eecs.umich.edu *
147375Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
157375Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
167375Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
177375Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
187375Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
197375Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
207375Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
217375Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
227375Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
237375Sgblack@eecs.umich.edu * this software without specific prior written permission.
247375Sgblack@eecs.umich.edu *
257375Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
267375Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
277375Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
287375Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
297375Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
307375Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
317375Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
327375Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
337375Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
347375Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
357375Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
367375Sgblack@eecs.umich.edu *
377375Sgblack@eecs.umich.edu * Authors: Gabe Black
387375Sgblack@eecs.umich.edu */
397375Sgblack@eecs.umich.edu
407375Sgblack@eecs.umich.edu#ifndef __ARCH_ARM_INSTS_VFP_HH__
417375Sgblack@eecs.umich.edu#define __ARCH_ARM_INSTS_VFP_HH__
427375Sgblack@eecs.umich.edu
437375Sgblack@eecs.umich.edu#include "arch/arm/insts/misc.hh"
447378Sgblack@eecs.umich.edu#include "arch/arm/miscregs.hh"
457378Sgblack@eecs.umich.edu#include <fenv.h>
467382Sgblack@eecs.umich.edu#include <cmath>
477375Sgblack@eecs.umich.edu
487384Sgblack@eecs.umich.edunamespace ArmISA
497384Sgblack@eecs.umich.edu{
507384Sgblack@eecs.umich.edu
517375Sgblack@eecs.umich.eduenum VfpMicroMode {
527375Sgblack@eecs.umich.edu    VfpNotAMicroop,
537375Sgblack@eecs.umich.edu    VfpMicroop,
547375Sgblack@eecs.umich.edu    VfpFirstMicroop,
557375Sgblack@eecs.umich.edu    VfpLastMicroop
567375Sgblack@eecs.umich.edu};
577375Sgblack@eecs.umich.edu
587375Sgblack@eecs.umich.edutemplate<class T>
597375Sgblack@eecs.umich.edustatic inline void
607375Sgblack@eecs.umich.edusetVfpMicroFlags(VfpMicroMode mode, T &flags)
617375Sgblack@eecs.umich.edu{
627375Sgblack@eecs.umich.edu    switch (mode) {
637375Sgblack@eecs.umich.edu      case VfpMicroop:
647375Sgblack@eecs.umich.edu        flags[StaticInst::IsMicroop] = true;
657375Sgblack@eecs.umich.edu        break;
667375Sgblack@eecs.umich.edu      case VfpFirstMicroop:
677375Sgblack@eecs.umich.edu        flags[StaticInst::IsMicroop] =
687375Sgblack@eecs.umich.edu            flags[StaticInst::IsFirstMicroop] = true;
697375Sgblack@eecs.umich.edu        break;
707375Sgblack@eecs.umich.edu      case VfpLastMicroop:
717375Sgblack@eecs.umich.edu        flags[StaticInst::IsMicroop] =
727375Sgblack@eecs.umich.edu            flags[StaticInst::IsLastMicroop] = true;
737375Sgblack@eecs.umich.edu        break;
747375Sgblack@eecs.umich.edu      case VfpNotAMicroop:
757375Sgblack@eecs.umich.edu        break;
767375Sgblack@eecs.umich.edu    }
777376Sgblack@eecs.umich.edu    if (mode == VfpMicroop || mode == VfpFirstMicroop) {
787376Sgblack@eecs.umich.edu        flags[StaticInst::IsDelayedCommit] = true;
797376Sgblack@eecs.umich.edu    }
807375Sgblack@eecs.umich.edu}
817375Sgblack@eecs.umich.edu
827378Sgblack@eecs.umich.eduenum FeExceptionBit
837378Sgblack@eecs.umich.edu{
847378Sgblack@eecs.umich.edu    FeDivByZero = FE_DIVBYZERO,
857378Sgblack@eecs.umich.edu    FeInexact = FE_INEXACT,
867378Sgblack@eecs.umich.edu    FeInvalid = FE_INVALID,
877378Sgblack@eecs.umich.edu    FeOverflow = FE_OVERFLOW,
887378Sgblack@eecs.umich.edu    FeUnderflow = FE_UNDERFLOW,
897378Sgblack@eecs.umich.edu    FeAllExceptions = FE_ALL_EXCEPT
907378Sgblack@eecs.umich.edu};
917378Sgblack@eecs.umich.edu
927378Sgblack@eecs.umich.eduenum FeRoundingMode
937378Sgblack@eecs.umich.edu{
947378Sgblack@eecs.umich.edu    FeRoundDown = FE_DOWNWARD,
957378Sgblack@eecs.umich.edu    FeRoundNearest = FE_TONEAREST,
967378Sgblack@eecs.umich.edu    FeRoundZero = FE_TOWARDZERO,
977378Sgblack@eecs.umich.edu    FeRoundUpward = FE_UPWARD
987378Sgblack@eecs.umich.edu};
997378Sgblack@eecs.umich.edu
1007378Sgblack@eecs.umich.eduenum VfpRoundingMode
1017378Sgblack@eecs.umich.edu{
1027378Sgblack@eecs.umich.edu    VfpRoundNearest = 0,
1037378Sgblack@eecs.umich.edu    VfpRoundUpward = 1,
1047378Sgblack@eecs.umich.edu    VfpRoundDown = 2,
1057378Sgblack@eecs.umich.edu    VfpRoundZero = 3
1067378Sgblack@eecs.umich.edu};
1077378Sgblack@eecs.umich.edu
1087382Sgblack@eecs.umich.edutemplate <class fpType>
1097396Sgblack@eecs.umich.edustatic inline bool
1107396Sgblack@eecs.umich.eduflushToZero(fpType &op)
1117396Sgblack@eecs.umich.edu{
1127396Sgblack@eecs.umich.edu    fpType junk = 0.0;
1137396Sgblack@eecs.umich.edu    if (std::fpclassify(op) == FP_SUBNORMAL) {
1147396Sgblack@eecs.umich.edu        uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1);
1157396Sgblack@eecs.umich.edu        op = bitsToFp(fpToBits(op) & bitMask, junk);
1167396Sgblack@eecs.umich.edu        return true;
1177396Sgblack@eecs.umich.edu    }
1187396Sgblack@eecs.umich.edu    return false;
1197396Sgblack@eecs.umich.edu}
1207396Sgblack@eecs.umich.edu
1217396Sgblack@eecs.umich.edutemplate <class fpType>
1227396Sgblack@eecs.umich.edustatic inline bool
1237396Sgblack@eecs.umich.eduflushToZero(fpType &op1, fpType &op2)
1247396Sgblack@eecs.umich.edu{
1257396Sgblack@eecs.umich.edu    bool flush1 = flushToZero(op1);
1267396Sgblack@eecs.umich.edu    bool flush2 = flushToZero(op2);
1277396Sgblack@eecs.umich.edu    return flush1 || flush2;
1287396Sgblack@eecs.umich.edu}
1297396Sgblack@eecs.umich.edu
1307397Sgblack@eecs.umich.edutemplate <class fpType>
1317397Sgblack@eecs.umich.edustatic inline void
1327397Sgblack@eecs.umich.eduvfpFlushToZero(FPSCR &fpscr, fpType &op)
1337397Sgblack@eecs.umich.edu{
1347397Sgblack@eecs.umich.edu    if (fpscr.fz == 1 && flushToZero(op)) {
1357397Sgblack@eecs.umich.edu        fpscr.idc = 1;
1367397Sgblack@eecs.umich.edu    }
1377397Sgblack@eecs.umich.edu}
1387397Sgblack@eecs.umich.edu
1397397Sgblack@eecs.umich.edutemplate <class fpType>
1407397Sgblack@eecs.umich.edustatic inline void
1417397Sgblack@eecs.umich.eduvfpFlushToZero(FPSCR &fpscr, fpType &op1, fpType &op2)
1427397Sgblack@eecs.umich.edu{
1437397Sgblack@eecs.umich.edu    vfpFlushToZero(fpscr, op1);
1447397Sgblack@eecs.umich.edu    vfpFlushToZero(fpscr, op2);
1457397Sgblack@eecs.umich.edu}
1467397Sgblack@eecs.umich.edu
1477384Sgblack@eecs.umich.edustatic inline uint32_t
1487384Sgblack@eecs.umich.edufpToBits(float fp)
1497384Sgblack@eecs.umich.edu{
1507384Sgblack@eecs.umich.edu    union
1517384Sgblack@eecs.umich.edu    {
1527384Sgblack@eecs.umich.edu        float fp;
1537384Sgblack@eecs.umich.edu        uint32_t bits;
1547384Sgblack@eecs.umich.edu    } val;
1557384Sgblack@eecs.umich.edu    val.fp = fp;
1567384Sgblack@eecs.umich.edu    return val.bits;
1577384Sgblack@eecs.umich.edu}
1587384Sgblack@eecs.umich.edu
1597384Sgblack@eecs.umich.edustatic inline uint64_t
1607384Sgblack@eecs.umich.edufpToBits(double fp)
1617384Sgblack@eecs.umich.edu{
1627384Sgblack@eecs.umich.edu    union
1637384Sgblack@eecs.umich.edu    {
1647384Sgblack@eecs.umich.edu        double fp;
1657384Sgblack@eecs.umich.edu        uint64_t bits;
1667384Sgblack@eecs.umich.edu    } val;
1677384Sgblack@eecs.umich.edu    val.fp = fp;
1687384Sgblack@eecs.umich.edu    return val.bits;
1697384Sgblack@eecs.umich.edu}
1707384Sgblack@eecs.umich.edu
1717384Sgblack@eecs.umich.edustatic inline float
1727384Sgblack@eecs.umich.edubitsToFp(uint64_t bits, float junk)
1737384Sgblack@eecs.umich.edu{
1747384Sgblack@eecs.umich.edu    union
1757384Sgblack@eecs.umich.edu    {
1767384Sgblack@eecs.umich.edu        float fp;
1777384Sgblack@eecs.umich.edu        uint32_t bits;
1787384Sgblack@eecs.umich.edu    } val;
1797384Sgblack@eecs.umich.edu    val.bits = bits;
1807384Sgblack@eecs.umich.edu    return val.fp;
1817384Sgblack@eecs.umich.edu}
1827384Sgblack@eecs.umich.edu
1837384Sgblack@eecs.umich.edustatic inline double
1847384Sgblack@eecs.umich.edubitsToFp(uint64_t bits, double junk)
1857384Sgblack@eecs.umich.edu{
1867384Sgblack@eecs.umich.edu    union
1877384Sgblack@eecs.umich.edu    {
1887384Sgblack@eecs.umich.edu        double fp;
1897384Sgblack@eecs.umich.edu        uint64_t bits;
1907384Sgblack@eecs.umich.edu    } val;
1917384Sgblack@eecs.umich.edu    val.bits = bits;
1927384Sgblack@eecs.umich.edu    return val.fp;
1937384Sgblack@eecs.umich.edu}
1947384Sgblack@eecs.umich.edu
1957396Sgblack@eecs.umich.edutypedef int VfpSavedState;
1967396Sgblack@eecs.umich.edu
1977396Sgblack@eecs.umich.edustatic inline VfpSavedState
1987396Sgblack@eecs.umich.eduprepFpState(uint32_t rMode)
1997396Sgblack@eecs.umich.edu{
2007396Sgblack@eecs.umich.edu    int roundingMode = fegetround();
2017396Sgblack@eecs.umich.edu    feclearexcept(FeAllExceptions);
2027396Sgblack@eecs.umich.edu    switch (rMode) {
2037396Sgblack@eecs.umich.edu      case VfpRoundNearest:
2047396Sgblack@eecs.umich.edu        fesetround(FeRoundNearest);
2057396Sgblack@eecs.umich.edu        break;
2067396Sgblack@eecs.umich.edu      case VfpRoundUpward:
2077396Sgblack@eecs.umich.edu        fesetround(FeRoundUpward);
2087396Sgblack@eecs.umich.edu        break;
2097396Sgblack@eecs.umich.edu      case VfpRoundDown:
2107396Sgblack@eecs.umich.edu        fesetround(FeRoundDown);
2117396Sgblack@eecs.umich.edu        break;
2127396Sgblack@eecs.umich.edu      case VfpRoundZero:
2137396Sgblack@eecs.umich.edu        fesetround(FeRoundZero);
2147396Sgblack@eecs.umich.edu        break;
2157396Sgblack@eecs.umich.edu    }
2167396Sgblack@eecs.umich.edu    return roundingMode;
2177396Sgblack@eecs.umich.edu}
2187396Sgblack@eecs.umich.edu
2197396Sgblack@eecs.umich.edustatic inline void
2207396Sgblack@eecs.umich.edufinishVfp(FPSCR &fpscr, VfpSavedState state)
2217396Sgblack@eecs.umich.edu{
2227396Sgblack@eecs.umich.edu    int exceptions = fetestexcept(FeAllExceptions);
2237396Sgblack@eecs.umich.edu    bool underflow = false;
2247396Sgblack@eecs.umich.edu    if (exceptions & FeInvalid) {
2257396Sgblack@eecs.umich.edu        fpscr.ioc = 1;
2267396Sgblack@eecs.umich.edu    }
2277396Sgblack@eecs.umich.edu    if (exceptions & FeDivByZero) {
2287396Sgblack@eecs.umich.edu        fpscr.dzc = 1;
2297396Sgblack@eecs.umich.edu    }
2307396Sgblack@eecs.umich.edu    if (exceptions & FeOverflow) {
2317396Sgblack@eecs.umich.edu        fpscr.ofc = 1;
2327396Sgblack@eecs.umich.edu    }
2337396Sgblack@eecs.umich.edu    if (exceptions & FeUnderflow) {
2347396Sgblack@eecs.umich.edu        underflow = true;
2357396Sgblack@eecs.umich.edu        fpscr.ufc = 1;
2367396Sgblack@eecs.umich.edu    }
2377396Sgblack@eecs.umich.edu    if ((exceptions & FeInexact) && !(underflow && fpscr.fz)) {
2387396Sgblack@eecs.umich.edu        fpscr.ixc = 1;
2397396Sgblack@eecs.umich.edu    }
2407396Sgblack@eecs.umich.edu    fesetround(state);
2417396Sgblack@eecs.umich.edu}
2427396Sgblack@eecs.umich.edu
2437384Sgblack@eecs.umich.edutemplate <class fpType>
2447384Sgblack@eecs.umich.edustatic inline fpType
2457386Sgblack@eecs.umich.edufixDest(FPSCR fpscr, fpType val, fpType op1)
2467386Sgblack@eecs.umich.edu{
2477386Sgblack@eecs.umich.edu    int fpClass = std::fpclassify(val);
2487386Sgblack@eecs.umich.edu    fpType junk = 0.0;
2497386Sgblack@eecs.umich.edu    if (fpClass == FP_NAN) {
2507386Sgblack@eecs.umich.edu        const bool single = (sizeof(val) == sizeof(float));
2517386Sgblack@eecs.umich.edu        const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000);
2527386Sgblack@eecs.umich.edu        const bool nan = std::isnan(op1);
2537386Sgblack@eecs.umich.edu        if (!nan || (fpscr.dn == 1)) {
2547386Sgblack@eecs.umich.edu            val = bitsToFp(qnan, junk);
2557386Sgblack@eecs.umich.edu        } else if (nan) {
2567386Sgblack@eecs.umich.edu            val = bitsToFp(fpToBits(op1) | qnan, junk);
2577386Sgblack@eecs.umich.edu        }
2587386Sgblack@eecs.umich.edu    } else if (fpClass == FP_SUBNORMAL && fpscr.fz == 1) {
2597386Sgblack@eecs.umich.edu        // Turn val into a zero with the correct sign;
2607386Sgblack@eecs.umich.edu        uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1);
2617386Sgblack@eecs.umich.edu        val = bitsToFp(fpToBits(val) & bitMask, junk);
2627396Sgblack@eecs.umich.edu        feclearexcept(FeInexact);
2637386Sgblack@eecs.umich.edu        feraiseexcept(FeUnderflow);
2647386Sgblack@eecs.umich.edu    }
2657386Sgblack@eecs.umich.edu    return val;
2667386Sgblack@eecs.umich.edu}
2677386Sgblack@eecs.umich.edu
2687386Sgblack@eecs.umich.edutemplate <class fpType>
2697386Sgblack@eecs.umich.edustatic inline fpType
2707385Sgblack@eecs.umich.edufixDest(FPSCR fpscr, fpType val, fpType op1, fpType op2)
2717384Sgblack@eecs.umich.edu{
2727385Sgblack@eecs.umich.edu    int fpClass = std::fpclassify(val);
2737385Sgblack@eecs.umich.edu    fpType junk = 0.0;
2747385Sgblack@eecs.umich.edu    if (fpClass == FP_NAN) {
2757384Sgblack@eecs.umich.edu        const bool single = (sizeof(val) == sizeof(float));
2767384Sgblack@eecs.umich.edu        const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000);
2777384Sgblack@eecs.umich.edu        const bool nan1 = std::isnan(op1);
2787384Sgblack@eecs.umich.edu        const bool nan2 = std::isnan(op2);
2797384Sgblack@eecs.umich.edu        const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan);
2807384Sgblack@eecs.umich.edu        const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan);
2817384Sgblack@eecs.umich.edu        if ((!nan1 && !nan2) || (fpscr.dn == 1)) {
2827384Sgblack@eecs.umich.edu            val = bitsToFp(qnan, junk);
2837384Sgblack@eecs.umich.edu        } else if (signal1) {
2847384Sgblack@eecs.umich.edu            val = bitsToFp(fpToBits(op1) | qnan, junk);
2857384Sgblack@eecs.umich.edu        } else if (signal2) {
2867384Sgblack@eecs.umich.edu            val = bitsToFp(fpToBits(op2) | qnan, junk);
2877384Sgblack@eecs.umich.edu        } else if (nan1) {
2887384Sgblack@eecs.umich.edu            val = op1;
2897384Sgblack@eecs.umich.edu        } else if (nan2) {
2907384Sgblack@eecs.umich.edu            val = op2;
2917384Sgblack@eecs.umich.edu        }
2927385Sgblack@eecs.umich.edu    } else if (fpClass == FP_SUBNORMAL && fpscr.fz == 1) {
2937385Sgblack@eecs.umich.edu        // Turn val into a zero with the correct sign;
2947385Sgblack@eecs.umich.edu        uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1);
2957385Sgblack@eecs.umich.edu        val = bitsToFp(fpToBits(val) & bitMask, junk);
2967396Sgblack@eecs.umich.edu        feclearexcept(FeInexact);
2977385Sgblack@eecs.umich.edu        feraiseexcept(FeUnderflow);
2987384Sgblack@eecs.umich.edu    }
2997384Sgblack@eecs.umich.edu    return val;
3007384Sgblack@eecs.umich.edu}
3017384Sgblack@eecs.umich.edu
3027386Sgblack@eecs.umich.edutemplate <class fpType>
3037386Sgblack@eecs.umich.edustatic inline fpType
3047386Sgblack@eecs.umich.edufixDivDest(FPSCR fpscr, fpType val, fpType op1, fpType op2)
3057386Sgblack@eecs.umich.edu{
3067386Sgblack@eecs.umich.edu    fpType mid = fixDest(fpscr, val, op1, op2);
3077386Sgblack@eecs.umich.edu    const bool single = (sizeof(fpType) == sizeof(float));
3087386Sgblack@eecs.umich.edu    const fpType junk = 0.0;
3097386Sgblack@eecs.umich.edu    if ((single && (val == bitsToFp(0x00800000, junk) ||
3107386Sgblack@eecs.umich.edu                    val == bitsToFp(0x80800000, junk))) ||
3117386Sgblack@eecs.umich.edu        (!single && (val == bitsToFp(ULL(0x0010000000000000), junk) ||
3127386Sgblack@eecs.umich.edu                     val == bitsToFp(ULL(0x8010000000000000), junk)))
3137386Sgblack@eecs.umich.edu        ) {
3147386Sgblack@eecs.umich.edu        __asm__ __volatile__("" : "=m" (op1) : "m" (op1));
3157386Sgblack@eecs.umich.edu        fesetround(FeRoundZero);
3167386Sgblack@eecs.umich.edu        fpType temp = 0.0;
3177386Sgblack@eecs.umich.edu        __asm__ __volatile__("" : "=m" (temp) : "m" (temp));
3187386Sgblack@eecs.umich.edu        temp = op1 / op2;
3197396Sgblack@eecs.umich.edu        if (flushToZero(temp)) {
3207386Sgblack@eecs.umich.edu            feraiseexcept(FeUnderflow);
3217396Sgblack@eecs.umich.edu            if (fpscr.fz) {
3227396Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
3237396Sgblack@eecs.umich.edu                mid = temp;
3247396Sgblack@eecs.umich.edu            }
3257386Sgblack@eecs.umich.edu        }
3267386Sgblack@eecs.umich.edu        __asm__ __volatile__("" :: "m" (temp));
3277386Sgblack@eecs.umich.edu    }
3287386Sgblack@eecs.umich.edu    return mid;
3297386Sgblack@eecs.umich.edu}
3307386Sgblack@eecs.umich.edu
3317386Sgblack@eecs.umich.edustatic inline float
3327386Sgblack@eecs.umich.edufixFpDFpSDest(FPSCR fpscr, double val)
3337386Sgblack@eecs.umich.edu{
3347386Sgblack@eecs.umich.edu    const float junk = 0.0;
3357386Sgblack@eecs.umich.edu    float op1 = 0.0;
3367386Sgblack@eecs.umich.edu    if (std::isnan(val)) {
3377386Sgblack@eecs.umich.edu        uint64_t valBits = fpToBits(val);
3387386Sgblack@eecs.umich.edu        uint32_t op1Bits = bits(valBits, 50, 29) |
3397386Sgblack@eecs.umich.edu                           (mask(9) << 22) |
3407386Sgblack@eecs.umich.edu                           (bits(valBits, 63) << 31);
3417386Sgblack@eecs.umich.edu        op1 = bitsToFp(op1Bits, junk);
3427386Sgblack@eecs.umich.edu    }
3437386Sgblack@eecs.umich.edu    float mid = fixDest(fpscr, (float)val, op1);
3447396Sgblack@eecs.umich.edu    if (fpscr.fz && fetestexcept(FeUnderflow | FeInexact) ==
3457396Sgblack@eecs.umich.edu                    (FeUnderflow | FeInexact)) {
3467396Sgblack@eecs.umich.edu        feclearexcept(FeInexact);
3477396Sgblack@eecs.umich.edu    }
3487386Sgblack@eecs.umich.edu    if (mid == bitsToFp(0x00800000, junk) ||
3497386Sgblack@eecs.umich.edu        mid == bitsToFp(0x80800000, junk)) {
3507386Sgblack@eecs.umich.edu        __asm__ __volatile__("" : "=m" (val) : "m" (val));
3517386Sgblack@eecs.umich.edu        fesetround(FeRoundZero);
3527386Sgblack@eecs.umich.edu        float temp = 0.0;
3537386Sgblack@eecs.umich.edu        __asm__ __volatile__("" : "=m" (temp) : "m" (temp));
3547386Sgblack@eecs.umich.edu        temp = val;
3557396Sgblack@eecs.umich.edu        if (flushToZero(temp)) {
3567386Sgblack@eecs.umich.edu            feraiseexcept(FeUnderflow);
3577396Sgblack@eecs.umich.edu            if (fpscr.fz) {
3587396Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
3597396Sgblack@eecs.umich.edu                mid = temp;
3607396Sgblack@eecs.umich.edu            }
3617386Sgblack@eecs.umich.edu        }
3627386Sgblack@eecs.umich.edu        __asm__ __volatile__("" :: "m" (temp));
3637386Sgblack@eecs.umich.edu    }
3647386Sgblack@eecs.umich.edu    return mid;
3657386Sgblack@eecs.umich.edu}
3667386Sgblack@eecs.umich.edu
3677396Sgblack@eecs.umich.edustatic inline double
3687396Sgblack@eecs.umich.edufixFpSFpDDest(FPSCR fpscr, float val)
3697396Sgblack@eecs.umich.edu{
3707396Sgblack@eecs.umich.edu    const double junk = 0.0;
3717396Sgblack@eecs.umich.edu    double op1 = 0.0;
3727396Sgblack@eecs.umich.edu    if (std::isnan(val)) {
3737396Sgblack@eecs.umich.edu        uint32_t valBits = fpToBits(val);
3747396Sgblack@eecs.umich.edu        uint64_t op1Bits = ((uint64_t)bits(valBits, 21, 0) << 29) |
3757396Sgblack@eecs.umich.edu                           (mask(12) << 51) |
3767396Sgblack@eecs.umich.edu                           ((uint64_t)bits(valBits, 31) << 63);
3777396Sgblack@eecs.umich.edu        op1 = bitsToFp(op1Bits, junk);
3787396Sgblack@eecs.umich.edu    }
3797396Sgblack@eecs.umich.edu    double mid = fixDest(fpscr, (double)val, op1);
3807396Sgblack@eecs.umich.edu    if (mid == bitsToFp(ULL(0x0010000000000000), junk) ||
3817396Sgblack@eecs.umich.edu        mid == bitsToFp(ULL(0x8010000000000000), junk)) {
3827396Sgblack@eecs.umich.edu        __asm__ __volatile__("" : "=m" (val) : "m" (val));
3837396Sgblack@eecs.umich.edu        fesetround(FeRoundZero);
3847396Sgblack@eecs.umich.edu        double temp = 0.0;
3857396Sgblack@eecs.umich.edu        __asm__ __volatile__("" : "=m" (temp) : "m" (temp));
3867396Sgblack@eecs.umich.edu        temp = val;
3877396Sgblack@eecs.umich.edu        if (flushToZero(temp)) {
3887396Sgblack@eecs.umich.edu            feraiseexcept(FeUnderflow);
3897396Sgblack@eecs.umich.edu            if (fpscr.fz) {
3907396Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
3917396Sgblack@eecs.umich.edu                mid = temp;
3927396Sgblack@eecs.umich.edu            }
3937396Sgblack@eecs.umich.edu        }
3947396Sgblack@eecs.umich.edu        __asm__ __volatile__("" :: "m" (temp));
3957396Sgblack@eecs.umich.edu    }
3967396Sgblack@eecs.umich.edu    return mid;
3977396Sgblack@eecs.umich.edu}
3987396Sgblack@eecs.umich.edu
3997398Sgblack@eecs.umich.edustatic inline float
4007398Sgblack@eecs.umich.eduvcvtFpSFpH(FPSCR &fpscr, float op, float dest, bool top)
4017398Sgblack@eecs.umich.edu{
4027398Sgblack@eecs.umich.edu    float junk = 0.0;
4037398Sgblack@eecs.umich.edu    uint32_t destBits = fpToBits(dest);
4047398Sgblack@eecs.umich.edu    uint32_t opBits = fpToBits(op);
4057398Sgblack@eecs.umich.edu    // Extract the operand.
4067398Sgblack@eecs.umich.edu    bool neg = bits(opBits, 31);
4077398Sgblack@eecs.umich.edu    uint32_t exponent = bits(opBits, 30, 23);
4087398Sgblack@eecs.umich.edu    uint32_t oldMantissa = bits(opBits, 22, 0);
4097398Sgblack@eecs.umich.edu    uint32_t mantissa = oldMantissa >> (23 - 10);
4107398Sgblack@eecs.umich.edu    // Do the conversion.
4117398Sgblack@eecs.umich.edu    uint32_t extra = oldMantissa & mask(23 - 10);
4127398Sgblack@eecs.umich.edu    if (exponent == 0xff) {
4137398Sgblack@eecs.umich.edu        if (oldMantissa != 0) {
4147398Sgblack@eecs.umich.edu            // Nans.
4157398Sgblack@eecs.umich.edu            if (bits(mantissa, 9) == 0) {
4167398Sgblack@eecs.umich.edu                // Signalling nan.
4177398Sgblack@eecs.umich.edu                fpscr.ioc = 1;
4187398Sgblack@eecs.umich.edu            }
4197398Sgblack@eecs.umich.edu            if (fpscr.ahp) {
4207398Sgblack@eecs.umich.edu                mantissa = 0;
4217398Sgblack@eecs.umich.edu                exponent = 0;
4227398Sgblack@eecs.umich.edu                fpscr.ioc = 1;
4237398Sgblack@eecs.umich.edu            } else if (fpscr.dn) {
4247398Sgblack@eecs.umich.edu                mantissa = (1 << 9);
4257398Sgblack@eecs.umich.edu                exponent = 0x1f;
4267398Sgblack@eecs.umich.edu                neg = false;
4277398Sgblack@eecs.umich.edu            } else {
4287398Sgblack@eecs.umich.edu                exponent = 0x1f;
4297398Sgblack@eecs.umich.edu                mantissa |= (1 << 9);
4307398Sgblack@eecs.umich.edu            }
4317398Sgblack@eecs.umich.edu        } else {
4327398Sgblack@eecs.umich.edu            // Infinities.
4337398Sgblack@eecs.umich.edu            exponent = 0x1F;
4347398Sgblack@eecs.umich.edu            if (fpscr.ahp) {
4357398Sgblack@eecs.umich.edu                fpscr.ioc = 1;
4367398Sgblack@eecs.umich.edu                mantissa = 0x3ff;
4377398Sgblack@eecs.umich.edu            } else {
4387398Sgblack@eecs.umich.edu                mantissa = 0;
4397398Sgblack@eecs.umich.edu            }
4407398Sgblack@eecs.umich.edu        }
4417398Sgblack@eecs.umich.edu    } else if (exponent == 0 && oldMantissa == 0) {
4427398Sgblack@eecs.umich.edu        // Zero, don't need to do anything.
4437398Sgblack@eecs.umich.edu    } else {
4447398Sgblack@eecs.umich.edu        // Normalized or denormalized numbers.
4457398Sgblack@eecs.umich.edu
4467398Sgblack@eecs.umich.edu        bool inexact = (extra != 0);
4477398Sgblack@eecs.umich.edu
4487398Sgblack@eecs.umich.edu        if (exponent == 0) {
4497398Sgblack@eecs.umich.edu            // Denormalized.
4507398Sgblack@eecs.umich.edu
4517398Sgblack@eecs.umich.edu            // If flush to zero is on, this shouldn't happen.
4527398Sgblack@eecs.umich.edu            assert(fpscr.fz == 0);
4537398Sgblack@eecs.umich.edu
4547398Sgblack@eecs.umich.edu            // Check for underflow
4557398Sgblack@eecs.umich.edu            if (inexact || fpscr.ufe)
4567398Sgblack@eecs.umich.edu                fpscr.ufc = 1;
4577398Sgblack@eecs.umich.edu
4587398Sgblack@eecs.umich.edu            // Handle rounding.
4597398Sgblack@eecs.umich.edu            unsigned mode = fpscr.rMode;
4607398Sgblack@eecs.umich.edu            if ((mode == VfpRoundUpward && !neg && extra) ||
4617398Sgblack@eecs.umich.edu                (mode == VfpRoundDown && neg && extra) ||
4627398Sgblack@eecs.umich.edu                (mode == VfpRoundNearest &&
4637398Sgblack@eecs.umich.edu                 (extra > (1 << 9) ||
4647398Sgblack@eecs.umich.edu                  (extra == (1 << 9) && bits(mantissa, 0))))) {
4657398Sgblack@eecs.umich.edu                mantissa++;
4667398Sgblack@eecs.umich.edu            }
4677398Sgblack@eecs.umich.edu
4687398Sgblack@eecs.umich.edu            // See if the number became normalized after rounding.
4697398Sgblack@eecs.umich.edu            if (mantissa == (1 << 10)) {
4707398Sgblack@eecs.umich.edu                mantissa = 0;
4717398Sgblack@eecs.umich.edu                exponent = 1;
4727398Sgblack@eecs.umich.edu            }
4737398Sgblack@eecs.umich.edu        } else {
4747398Sgblack@eecs.umich.edu            // Normalized.
4757398Sgblack@eecs.umich.edu
4767398Sgblack@eecs.umich.edu            // We need to track the dropped bits differently since
4777398Sgblack@eecs.umich.edu            // more can be dropped by denormalizing.
4787398Sgblack@eecs.umich.edu            bool topOne = bits(extra, 12);
4797398Sgblack@eecs.umich.edu            bool restZeros = bits(extra, 11, 0) == 0;
4807398Sgblack@eecs.umich.edu
4817398Sgblack@eecs.umich.edu            if (exponent <= (127 - 15)) {
4827398Sgblack@eecs.umich.edu                // The result is too small. Denormalize.
4837398Sgblack@eecs.umich.edu                mantissa |= (1 << 10);
4847398Sgblack@eecs.umich.edu                while (mantissa && exponent <= (127 - 15)) {
4857398Sgblack@eecs.umich.edu                    restZeros = restZeros && !topOne;
4867398Sgblack@eecs.umich.edu                    topOne = bits(mantissa, 0);
4877398Sgblack@eecs.umich.edu                    mantissa = mantissa >> 1;
4887398Sgblack@eecs.umich.edu                    exponent++;
4897398Sgblack@eecs.umich.edu                }
4907398Sgblack@eecs.umich.edu                if (topOne || !restZeros)
4917398Sgblack@eecs.umich.edu                    inexact = true;
4927398Sgblack@eecs.umich.edu                exponent = 0;
4937398Sgblack@eecs.umich.edu            } else {
4947398Sgblack@eecs.umich.edu                // Change bias.
4957398Sgblack@eecs.umich.edu                exponent -= (127 - 15);
4967398Sgblack@eecs.umich.edu            }
4977398Sgblack@eecs.umich.edu
4987398Sgblack@eecs.umich.edu            if (exponent == 0 && (inexact || fpscr.ufe)) {
4997398Sgblack@eecs.umich.edu                // Underflow
5007398Sgblack@eecs.umich.edu                fpscr.ufc = 1;
5017398Sgblack@eecs.umich.edu            }
5027398Sgblack@eecs.umich.edu
5037398Sgblack@eecs.umich.edu            // Handle rounding.
5047398Sgblack@eecs.umich.edu            unsigned mode = fpscr.rMode;
5057398Sgblack@eecs.umich.edu            bool nonZero = topOne || !restZeros;
5067398Sgblack@eecs.umich.edu            if ((mode == VfpRoundUpward && !neg && nonZero) ||
5077398Sgblack@eecs.umich.edu                (mode == VfpRoundDown && neg && nonZero) ||
5087398Sgblack@eecs.umich.edu                (mode == VfpRoundNearest && topOne &&
5097398Sgblack@eecs.umich.edu                 (!restZeros || bits(mantissa, 0)))) {
5107398Sgblack@eecs.umich.edu                mantissa++;
5117398Sgblack@eecs.umich.edu            }
5127398Sgblack@eecs.umich.edu
5137398Sgblack@eecs.umich.edu            // See if we rounded up and need to bump the exponent.
5147398Sgblack@eecs.umich.edu            if (mantissa == (1 << 10)) {
5157398Sgblack@eecs.umich.edu                mantissa = 0;
5167398Sgblack@eecs.umich.edu                exponent++;
5177398Sgblack@eecs.umich.edu            }
5187398Sgblack@eecs.umich.edu
5197398Sgblack@eecs.umich.edu            // Deal with overflow
5207398Sgblack@eecs.umich.edu            if (fpscr.ahp) {
5217398Sgblack@eecs.umich.edu                if (exponent >= 0x20) {
5227398Sgblack@eecs.umich.edu                    exponent = 0x1f;
5237398Sgblack@eecs.umich.edu                    mantissa = 0x3ff;
5247398Sgblack@eecs.umich.edu                    fpscr.ioc = 1;
5257398Sgblack@eecs.umich.edu                    // Supress inexact exception.
5267398Sgblack@eecs.umich.edu                    inexact = false;
5277398Sgblack@eecs.umich.edu                }
5287398Sgblack@eecs.umich.edu            } else {
5297398Sgblack@eecs.umich.edu                if (exponent >= 0x1f) {
5307398Sgblack@eecs.umich.edu                    if ((mode == VfpRoundNearest) ||
5317398Sgblack@eecs.umich.edu                        (mode == VfpRoundUpward && !neg) ||
5327398Sgblack@eecs.umich.edu                        (mode == VfpRoundDown && neg)) {
5337398Sgblack@eecs.umich.edu                        // Overflow to infinity.
5347398Sgblack@eecs.umich.edu                        exponent = 0x1f;
5357398Sgblack@eecs.umich.edu                        mantissa = 0;
5367398Sgblack@eecs.umich.edu                    } else {
5377398Sgblack@eecs.umich.edu                        // Overflow to max normal.
5387398Sgblack@eecs.umich.edu                        exponent = 0x1e;
5397398Sgblack@eecs.umich.edu                        mantissa = 0x3ff;
5407398Sgblack@eecs.umich.edu                    }
5417398Sgblack@eecs.umich.edu                    fpscr.ofc = 1;
5427398Sgblack@eecs.umich.edu                    inexact = true;
5437398Sgblack@eecs.umich.edu                }
5447398Sgblack@eecs.umich.edu            }
5457398Sgblack@eecs.umich.edu        }
5467398Sgblack@eecs.umich.edu
5477398Sgblack@eecs.umich.edu        if (inexact) {
5487398Sgblack@eecs.umich.edu            fpscr.ixc = 1;
5497398Sgblack@eecs.umich.edu        }
5507398Sgblack@eecs.umich.edu    }
5517398Sgblack@eecs.umich.edu    // Reassemble and install the result.
5527398Sgblack@eecs.umich.edu    uint32_t result = bits(mantissa, 9, 0);
5537398Sgblack@eecs.umich.edu    replaceBits(result, 14, 10, exponent);
5547398Sgblack@eecs.umich.edu    if (neg)
5557398Sgblack@eecs.umich.edu        result |= (1 << 15);
5567398Sgblack@eecs.umich.edu    if (top)
5577398Sgblack@eecs.umich.edu        replaceBits(destBits, 31, 16, result);
5587398Sgblack@eecs.umich.edu    else
5597398Sgblack@eecs.umich.edu        replaceBits(destBits, 15, 0, result);
5607398Sgblack@eecs.umich.edu    return bitsToFp(destBits, junk);
5617398Sgblack@eecs.umich.edu}
5627398Sgblack@eecs.umich.edu
5637398Sgblack@eecs.umich.edustatic inline float
5647398Sgblack@eecs.umich.eduvcvtFpHFpS(FPSCR &fpscr, float op, bool top)
5657398Sgblack@eecs.umich.edu{
5667398Sgblack@eecs.umich.edu    float junk = 0.0;
5677398Sgblack@eecs.umich.edu    uint32_t opBits = fpToBits(op);
5687398Sgblack@eecs.umich.edu    // Extract the operand.
5697398Sgblack@eecs.umich.edu    if (top)
5707398Sgblack@eecs.umich.edu        opBits = bits(opBits, 31, 16);
5717398Sgblack@eecs.umich.edu    else
5727398Sgblack@eecs.umich.edu        opBits = bits(opBits, 15, 0);
5737398Sgblack@eecs.umich.edu    // Extract the bitfields.
5747398Sgblack@eecs.umich.edu    bool neg = bits(opBits, 15);
5757398Sgblack@eecs.umich.edu    uint32_t exponent = bits(opBits, 14, 10);
5767398Sgblack@eecs.umich.edu    uint32_t mantissa = bits(opBits, 9, 0);
5777398Sgblack@eecs.umich.edu    // Do the conversion.
5787398Sgblack@eecs.umich.edu    if (exponent == 0) {
5797398Sgblack@eecs.umich.edu        if (mantissa != 0) {
5807398Sgblack@eecs.umich.edu            // Normalize the value.
5817398Sgblack@eecs.umich.edu            exponent = exponent + (127 - 15) + 1;
5827398Sgblack@eecs.umich.edu            while (mantissa < (1 << 10)) {
5837398Sgblack@eecs.umich.edu                mantissa = mantissa << 1;
5847398Sgblack@eecs.umich.edu                exponent--;
5857398Sgblack@eecs.umich.edu            }
5867398Sgblack@eecs.umich.edu        }
5877398Sgblack@eecs.umich.edu        mantissa = mantissa << (23 - 10);
5887398Sgblack@eecs.umich.edu    } else if (exponent == 0x1f && !fpscr.ahp) {
5897398Sgblack@eecs.umich.edu        // Infinities and nans.
5907398Sgblack@eecs.umich.edu        exponent = 0xff;
5917398Sgblack@eecs.umich.edu        if (mantissa != 0) {
5927398Sgblack@eecs.umich.edu            // Nans.
5937398Sgblack@eecs.umich.edu            mantissa = mantissa << (23 - 10);
5947398Sgblack@eecs.umich.edu            if (bits(mantissa, 22) == 0) {
5957398Sgblack@eecs.umich.edu                // Signalling nan.
5967398Sgblack@eecs.umich.edu                fpscr.ioc = 1;
5977398Sgblack@eecs.umich.edu                mantissa |= (1 << 22);
5987398Sgblack@eecs.umich.edu            }
5997398Sgblack@eecs.umich.edu            if (fpscr.dn) {
6007398Sgblack@eecs.umich.edu                mantissa &= ~mask(22);
6017398Sgblack@eecs.umich.edu                neg = false;
6027398Sgblack@eecs.umich.edu            }
6037398Sgblack@eecs.umich.edu        }
6047398Sgblack@eecs.umich.edu    } else {
6057398Sgblack@eecs.umich.edu        exponent = exponent + (127 - 15);
6067398Sgblack@eecs.umich.edu        mantissa = mantissa << (23 - 10);
6077398Sgblack@eecs.umich.edu    }
6087398Sgblack@eecs.umich.edu    // Reassemble the result.
6097398Sgblack@eecs.umich.edu    uint32_t result = bits(mantissa, 22, 0);
6107398Sgblack@eecs.umich.edu    replaceBits(result, 30, 23, exponent);
6117398Sgblack@eecs.umich.edu    if (neg)
6127398Sgblack@eecs.umich.edu        result |= (1 << 31);
6137398Sgblack@eecs.umich.edu    return bitsToFp(result, junk);
6147398Sgblack@eecs.umich.edu}
6157398Sgblack@eecs.umich.edu
6167396Sgblack@eecs.umich.edustatic inline double
6177396Sgblack@eecs.umich.edumakeDouble(uint32_t low, uint32_t high)
6187396Sgblack@eecs.umich.edu{
6197396Sgblack@eecs.umich.edu    double junk = 0.0;
6207396Sgblack@eecs.umich.edu    return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk);
6217396Sgblack@eecs.umich.edu}
6227396Sgblack@eecs.umich.edu
6237396Sgblack@eecs.umich.edustatic inline uint32_t
6247396Sgblack@eecs.umich.edulowFromDouble(double val)
6257396Sgblack@eecs.umich.edu{
6267396Sgblack@eecs.umich.edu    return fpToBits(val);
6277396Sgblack@eecs.umich.edu}
6287396Sgblack@eecs.umich.edu
6297396Sgblack@eecs.umich.edustatic inline uint32_t
6307396Sgblack@eecs.umich.eduhighFromDouble(double val)
6317396Sgblack@eecs.umich.edu{
6327396Sgblack@eecs.umich.edu    return fpToBits(val) >> 32;
6337396Sgblack@eecs.umich.edu}
6347396Sgblack@eecs.umich.edu
6357379Sgblack@eecs.umich.edustatic inline uint64_t
6367388Sgblack@eecs.umich.eduvfpFpSToFixed(float val, bool isSigned, bool half,
6377388Sgblack@eecs.umich.edu              uint8_t imm, bool rzero = true)
6387379Sgblack@eecs.umich.edu{
6397396Sgblack@eecs.umich.edu    int rmode = rzero ? FeRoundZero : fegetround();
6407396Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (rmode) : "m" (rmode));
6417388Sgblack@eecs.umich.edu    fesetround(FeRoundNearest);
6427379Sgblack@eecs.umich.edu    val = val * powf(2.0, imm);
6437379Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (val) : "m" (val));
6447396Sgblack@eecs.umich.edu    fesetround(rmode);
6457379Sgblack@eecs.umich.edu    feclearexcept(FeAllExceptions);
6467382Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (val) : "m" (val));
6477382Sgblack@eecs.umich.edu    float origVal = val;
6487382Sgblack@eecs.umich.edu    val = rintf(val);
6497382Sgblack@eecs.umich.edu    int fpType = std::fpclassify(val);
6507382Sgblack@eecs.umich.edu    if (fpType == FP_SUBNORMAL || fpType == FP_NAN) {
6517382Sgblack@eecs.umich.edu        if (fpType == FP_NAN) {
6527382Sgblack@eecs.umich.edu            feraiseexcept(FeInvalid);
6537382Sgblack@eecs.umich.edu        }
6547382Sgblack@eecs.umich.edu        val = 0.0;
6557382Sgblack@eecs.umich.edu    } else if (origVal != val) {
6567396Sgblack@eecs.umich.edu        switch (rmode) {
6577396Sgblack@eecs.umich.edu          case FeRoundNearest:
6587396Sgblack@eecs.umich.edu            if (origVal - val > 0.5)
6597396Sgblack@eecs.umich.edu                val += 1.0;
6607396Sgblack@eecs.umich.edu            else if (val - origVal > 0.5)
6617396Sgblack@eecs.umich.edu                val -= 1.0;
6627396Sgblack@eecs.umich.edu            break;
6637396Sgblack@eecs.umich.edu          case FeRoundDown:
6647396Sgblack@eecs.umich.edu            if (origVal < val)
6657396Sgblack@eecs.umich.edu                val -= 1.0;
6667396Sgblack@eecs.umich.edu            break;
6677396Sgblack@eecs.umich.edu          case FeRoundUpward:
6687396Sgblack@eecs.umich.edu            if (origVal > val)
6697396Sgblack@eecs.umich.edu                val += 1.0;
6707396Sgblack@eecs.umich.edu            break;
6717396Sgblack@eecs.umich.edu        }
6727382Sgblack@eecs.umich.edu        feraiseexcept(FeInexact);
6737382Sgblack@eecs.umich.edu    }
6747382Sgblack@eecs.umich.edu
6757379Sgblack@eecs.umich.edu    if (isSigned) {
6767379Sgblack@eecs.umich.edu        if (half) {
6777381Sgblack@eecs.umich.edu            if ((double)val < (int16_t)(1 << 15)) {
6787379Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
6797382Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
6807379Sgblack@eecs.umich.edu                return (int16_t)(1 << 15);
6817379Sgblack@eecs.umich.edu            }
6827381Sgblack@eecs.umich.edu            if ((double)val > (int16_t)mask(15)) {
6837379Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
6847382Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
6857379Sgblack@eecs.umich.edu                return (int16_t)mask(15);
6867379Sgblack@eecs.umich.edu            }
6877379Sgblack@eecs.umich.edu            return (int16_t)val;
6887379Sgblack@eecs.umich.edu        } else {
6897381Sgblack@eecs.umich.edu            if ((double)val < (int32_t)(1 << 31)) {
6907379Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
6917382Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
6927379Sgblack@eecs.umich.edu                return (int32_t)(1 << 31);
6937379Sgblack@eecs.umich.edu            }
6947381Sgblack@eecs.umich.edu            if ((double)val > (int32_t)mask(31)) {
6957379Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
6967382Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
6977379Sgblack@eecs.umich.edu                return (int32_t)mask(31);
6987379Sgblack@eecs.umich.edu            }
6997379Sgblack@eecs.umich.edu            return (int32_t)val;
7007379Sgblack@eecs.umich.edu        }
7017379Sgblack@eecs.umich.edu    } else {
7027379Sgblack@eecs.umich.edu        if (half) {
7037381Sgblack@eecs.umich.edu            if ((double)val < 0) {
7047379Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
7057382Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
7067379Sgblack@eecs.umich.edu                return 0;
7077379Sgblack@eecs.umich.edu            }
7087381Sgblack@eecs.umich.edu            if ((double)val > (mask(16))) {
7097379Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
7107382Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
7117379Sgblack@eecs.umich.edu                return mask(16);
7127379Sgblack@eecs.umich.edu            }
7137379Sgblack@eecs.umich.edu            return (uint16_t)val;
7147379Sgblack@eecs.umich.edu        } else {
7157381Sgblack@eecs.umich.edu            if ((double)val < 0) {
7167379Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
7177382Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
7187379Sgblack@eecs.umich.edu                return 0;
7197379Sgblack@eecs.umich.edu            }
7207381Sgblack@eecs.umich.edu            if ((double)val > (mask(32))) {
7217379Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
7227382Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
7237379Sgblack@eecs.umich.edu                return mask(32);
7247379Sgblack@eecs.umich.edu            }
7257379Sgblack@eecs.umich.edu            return (uint32_t)val;
7267379Sgblack@eecs.umich.edu        }
7277379Sgblack@eecs.umich.edu    }
7287379Sgblack@eecs.umich.edu}
7297379Sgblack@eecs.umich.edu
7307379Sgblack@eecs.umich.edustatic inline float
7317386Sgblack@eecs.umich.eduvfpUFixedToFpS(FPSCR fpscr, uint32_t val, bool half, uint8_t imm)
7327379Sgblack@eecs.umich.edu{
7337379Sgblack@eecs.umich.edu    fesetround(FeRoundNearest);
7347379Sgblack@eecs.umich.edu    if (half)
7357379Sgblack@eecs.umich.edu        val = (uint16_t)val;
7367382Sgblack@eecs.umich.edu    float scale = powf(2.0, imm);
7377382Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
7387382Sgblack@eecs.umich.edu    feclearexcept(FeAllExceptions);
7397382Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
7407386Sgblack@eecs.umich.edu    return fixDivDest(fpscr, val / scale, (float)val, scale);
7417379Sgblack@eecs.umich.edu}
7427379Sgblack@eecs.umich.edu
7437379Sgblack@eecs.umich.edustatic inline float
7447386Sgblack@eecs.umich.eduvfpSFixedToFpS(FPSCR fpscr, int32_t val, bool half, uint8_t imm)
7457379Sgblack@eecs.umich.edu{
7467379Sgblack@eecs.umich.edu    fesetround(FeRoundNearest);
7477379Sgblack@eecs.umich.edu    if (half)
7487379Sgblack@eecs.umich.edu        val = sext<16>(val & mask(16));
7497382Sgblack@eecs.umich.edu    float scale = powf(2.0, imm);
7507382Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
7517382Sgblack@eecs.umich.edu    feclearexcept(FeAllExceptions);
7527382Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
7537386Sgblack@eecs.umich.edu    return fixDivDest(fpscr, val / scale, (float)val, scale);
7547379Sgblack@eecs.umich.edu}
7557379Sgblack@eecs.umich.edu
7567379Sgblack@eecs.umich.edustatic inline uint64_t
7577388Sgblack@eecs.umich.eduvfpFpDToFixed(double val, bool isSigned, bool half,
7587388Sgblack@eecs.umich.edu              uint8_t imm, bool rzero = true)
7597379Sgblack@eecs.umich.edu{
7607396Sgblack@eecs.umich.edu    int rmode = rzero ? FeRoundZero : fegetround();
7617382Sgblack@eecs.umich.edu    fesetround(FeRoundNearest);
7627379Sgblack@eecs.umich.edu    val = val * pow(2.0, imm);
7637379Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (val) : "m" (val));
7647396Sgblack@eecs.umich.edu    fesetround(rmode);
7657379Sgblack@eecs.umich.edu    feclearexcept(FeAllExceptions);
7667382Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (val) : "m" (val));
7677382Sgblack@eecs.umich.edu    double origVal = val;
7687382Sgblack@eecs.umich.edu    val = rint(val);
7697382Sgblack@eecs.umich.edu    int fpType = std::fpclassify(val);
7707382Sgblack@eecs.umich.edu    if (fpType == FP_SUBNORMAL || fpType == FP_NAN) {
7717382Sgblack@eecs.umich.edu        if (fpType == FP_NAN) {
7727382Sgblack@eecs.umich.edu            feraiseexcept(FeInvalid);
7737382Sgblack@eecs.umich.edu        }
7747382Sgblack@eecs.umich.edu        val = 0.0;
7757382Sgblack@eecs.umich.edu    } else if (origVal != val) {
7767396Sgblack@eecs.umich.edu        switch (rmode) {
7777396Sgblack@eecs.umich.edu          case FeRoundNearest:
7787396Sgblack@eecs.umich.edu            if (origVal - val > 0.5)
7797396Sgblack@eecs.umich.edu                val += 1.0;
7807396Sgblack@eecs.umich.edu            else if (val - origVal > 0.5)
7817396Sgblack@eecs.umich.edu                val -= 1.0;
7827396Sgblack@eecs.umich.edu            break;
7837396Sgblack@eecs.umich.edu          case FeRoundDown:
7847396Sgblack@eecs.umich.edu            if (origVal < val)
7857396Sgblack@eecs.umich.edu                val -= 1.0;
7867396Sgblack@eecs.umich.edu            break;
7877396Sgblack@eecs.umich.edu          case FeRoundUpward:
7887396Sgblack@eecs.umich.edu            if (origVal > val)
7897396Sgblack@eecs.umich.edu                val += 1.0;
7907396Sgblack@eecs.umich.edu            break;
7917396Sgblack@eecs.umich.edu        }
7927382Sgblack@eecs.umich.edu        feraiseexcept(FeInexact);
7937382Sgblack@eecs.umich.edu    }
7947379Sgblack@eecs.umich.edu    if (isSigned) {
7957379Sgblack@eecs.umich.edu        if (half) {
7967379Sgblack@eecs.umich.edu            if (val < (int16_t)(1 << 15)) {
7977379Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
7987382Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
7997379Sgblack@eecs.umich.edu                return (int16_t)(1 << 15);
8007379Sgblack@eecs.umich.edu            }
8017379Sgblack@eecs.umich.edu            if (val > (int16_t)mask(15)) {
8027379Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
8037382Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
8047379Sgblack@eecs.umich.edu                return (int16_t)mask(15);
8057379Sgblack@eecs.umich.edu            }
8067379Sgblack@eecs.umich.edu            return (int16_t)val;
8077379Sgblack@eecs.umich.edu        } else {
8087379Sgblack@eecs.umich.edu            if (val < (int32_t)(1 << 31)) {
8097379Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
8107382Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
8117379Sgblack@eecs.umich.edu                return (int32_t)(1 << 31);
8127379Sgblack@eecs.umich.edu            }
8137379Sgblack@eecs.umich.edu            if (val > (int32_t)mask(31)) {
8147379Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
8157382Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
8167379Sgblack@eecs.umich.edu                return (int32_t)mask(31);
8177379Sgblack@eecs.umich.edu            }
8187379Sgblack@eecs.umich.edu            return (int32_t)val;
8197379Sgblack@eecs.umich.edu        }
8207379Sgblack@eecs.umich.edu    } else {
8217379Sgblack@eecs.umich.edu        if (half) {
8227379Sgblack@eecs.umich.edu            if (val < 0) {
8237379Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
8247382Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
8257379Sgblack@eecs.umich.edu                return 0;
8267379Sgblack@eecs.umich.edu            }
8277379Sgblack@eecs.umich.edu            if (val > mask(16)) {
8287379Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
8297382Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
8307379Sgblack@eecs.umich.edu                return mask(16);
8317379Sgblack@eecs.umich.edu            }
8327379Sgblack@eecs.umich.edu            return (uint16_t)val;
8337379Sgblack@eecs.umich.edu        } else {
8347379Sgblack@eecs.umich.edu            if (val < 0) {
8357379Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
8367382Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
8377379Sgblack@eecs.umich.edu                return 0;
8387379Sgblack@eecs.umich.edu            }
8397379Sgblack@eecs.umich.edu            if (val > mask(32)) {
8407379Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
8417382Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
8427379Sgblack@eecs.umich.edu                return mask(32);
8437379Sgblack@eecs.umich.edu            }
8447379Sgblack@eecs.umich.edu            return (uint32_t)val;
8457379Sgblack@eecs.umich.edu        }
8467379Sgblack@eecs.umich.edu    }
8477379Sgblack@eecs.umich.edu}
8487379Sgblack@eecs.umich.edu
8497379Sgblack@eecs.umich.edustatic inline double
8507386Sgblack@eecs.umich.eduvfpUFixedToFpD(FPSCR fpscr, uint32_t val, bool half, uint8_t imm)
8517379Sgblack@eecs.umich.edu{
8527379Sgblack@eecs.umich.edu    fesetround(FeRoundNearest);
8537379Sgblack@eecs.umich.edu    if (half)
8547379Sgblack@eecs.umich.edu        val = (uint16_t)val;
8557382Sgblack@eecs.umich.edu    double scale = pow(2.0, imm);
8567382Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
8577382Sgblack@eecs.umich.edu    feclearexcept(FeAllExceptions);
8587382Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
8597386Sgblack@eecs.umich.edu    return fixDivDest(fpscr, val / scale, (double)val, scale);
8607379Sgblack@eecs.umich.edu}
8617379Sgblack@eecs.umich.edu
8627379Sgblack@eecs.umich.edustatic inline double
8637386Sgblack@eecs.umich.eduvfpSFixedToFpD(FPSCR fpscr, int32_t val, bool half, uint8_t imm)
8647379Sgblack@eecs.umich.edu{
8657379Sgblack@eecs.umich.edu    fesetround(FeRoundNearest);
8667379Sgblack@eecs.umich.edu    if (half)
8677379Sgblack@eecs.umich.edu        val = sext<16>(val & mask(16));
8687382Sgblack@eecs.umich.edu    double scale = pow(2.0, imm);
8697382Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
8707382Sgblack@eecs.umich.edu    feclearexcept(FeAllExceptions);
8717382Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
8727386Sgblack@eecs.umich.edu    return fixDivDest(fpscr, val / scale, (double)val, scale);
8737379Sgblack@eecs.umich.edu}
8747379Sgblack@eecs.umich.edu
8757376Sgblack@eecs.umich.educlass VfpMacroOp : public PredMacroOp
8767376Sgblack@eecs.umich.edu{
8777376Sgblack@eecs.umich.edu  public:
8787376Sgblack@eecs.umich.edu    static bool
8797376Sgblack@eecs.umich.edu    inScalarBank(IntRegIndex idx)
8807376Sgblack@eecs.umich.edu    {
8817376Sgblack@eecs.umich.edu        return (idx % 32) < 8;
8827376Sgblack@eecs.umich.edu    }
8837376Sgblack@eecs.umich.edu
8847376Sgblack@eecs.umich.edu  protected:
8857376Sgblack@eecs.umich.edu    bool wide;
8867376Sgblack@eecs.umich.edu
8877376Sgblack@eecs.umich.edu    VfpMacroOp(const char *mnem, ExtMachInst _machInst,
8887376Sgblack@eecs.umich.edu            OpClass __opClass, bool _wide) :
8897376Sgblack@eecs.umich.edu        PredMacroOp(mnem, _machInst, __opClass), wide(_wide)
8907376Sgblack@eecs.umich.edu    {}
8917376Sgblack@eecs.umich.edu
8927376Sgblack@eecs.umich.edu    IntRegIndex
8937376Sgblack@eecs.umich.edu    addStride(IntRegIndex idx, unsigned stride)
8947376Sgblack@eecs.umich.edu    {
8957376Sgblack@eecs.umich.edu        if (wide) {
8967376Sgblack@eecs.umich.edu            stride *= 2;
8977376Sgblack@eecs.umich.edu        }
8987376Sgblack@eecs.umich.edu        unsigned offset = idx % 8;
8997376Sgblack@eecs.umich.edu        idx = (IntRegIndex)(idx - offset);
9007376Sgblack@eecs.umich.edu        offset += stride;
9017376Sgblack@eecs.umich.edu        idx = (IntRegIndex)(idx + (offset % 8));
9027376Sgblack@eecs.umich.edu        return idx;
9037376Sgblack@eecs.umich.edu    }
9047376Sgblack@eecs.umich.edu
9057376Sgblack@eecs.umich.edu    void
9067376Sgblack@eecs.umich.edu    nextIdxs(IntRegIndex &dest, IntRegIndex &op1, IntRegIndex &op2)
9077376Sgblack@eecs.umich.edu    {
9087376Sgblack@eecs.umich.edu        unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2;
9097376Sgblack@eecs.umich.edu        assert(!inScalarBank(dest));
9107376Sgblack@eecs.umich.edu        dest = addStride(dest, stride);
9117376Sgblack@eecs.umich.edu        op1 = addStride(op1, stride);
9127376Sgblack@eecs.umich.edu        if (!inScalarBank(op2)) {
9137376Sgblack@eecs.umich.edu            op2 = addStride(op2, stride);
9147376Sgblack@eecs.umich.edu        }
9157376Sgblack@eecs.umich.edu    }
9167376Sgblack@eecs.umich.edu
9177376Sgblack@eecs.umich.edu    void
9187376Sgblack@eecs.umich.edu    nextIdxs(IntRegIndex &dest, IntRegIndex &op1)
9197376Sgblack@eecs.umich.edu    {
9207376Sgblack@eecs.umich.edu        unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2;
9217376Sgblack@eecs.umich.edu        assert(!inScalarBank(dest));
9227376Sgblack@eecs.umich.edu        dest = addStride(dest, stride);
9237376Sgblack@eecs.umich.edu        if (!inScalarBank(op1)) {
9247376Sgblack@eecs.umich.edu            op1 = addStride(op1, stride);
9257376Sgblack@eecs.umich.edu        }
9267376Sgblack@eecs.umich.edu    }
9277376Sgblack@eecs.umich.edu
9287376Sgblack@eecs.umich.edu    void
9297376Sgblack@eecs.umich.edu    nextIdxs(IntRegIndex &dest)
9307376Sgblack@eecs.umich.edu    {
9317376Sgblack@eecs.umich.edu        unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2;
9327376Sgblack@eecs.umich.edu        assert(!inScalarBank(dest));
9337376Sgblack@eecs.umich.edu        dest = addStride(dest, stride);
9347376Sgblack@eecs.umich.edu    }
9357376Sgblack@eecs.umich.edu};
9367376Sgblack@eecs.umich.edu
9377396Sgblack@eecs.umich.edustatic inline float
9387396Sgblack@eecs.umich.edufpAddS(float a, float b)
9397396Sgblack@eecs.umich.edu{
9407396Sgblack@eecs.umich.edu    return a + b;
9417396Sgblack@eecs.umich.edu}
9427396Sgblack@eecs.umich.edu
9437396Sgblack@eecs.umich.edustatic inline double
9447396Sgblack@eecs.umich.edufpAddD(double a, double b)
9457396Sgblack@eecs.umich.edu{
9467396Sgblack@eecs.umich.edu    return a + b;
9477396Sgblack@eecs.umich.edu}
9487396Sgblack@eecs.umich.edu
9497396Sgblack@eecs.umich.edustatic inline float
9507396Sgblack@eecs.umich.edufpSubS(float a, float b)
9517396Sgblack@eecs.umich.edu{
9527396Sgblack@eecs.umich.edu    return a - b;
9537396Sgblack@eecs.umich.edu}
9547396Sgblack@eecs.umich.edu
9557396Sgblack@eecs.umich.edustatic inline double
9567396Sgblack@eecs.umich.edufpSubD(double a, double b)
9577396Sgblack@eecs.umich.edu{
9587396Sgblack@eecs.umich.edu    return a - b;
9597396Sgblack@eecs.umich.edu}
9607396Sgblack@eecs.umich.edu
9617396Sgblack@eecs.umich.edustatic inline float
9627396Sgblack@eecs.umich.edufpDivS(float a, float b)
9637396Sgblack@eecs.umich.edu{
9647396Sgblack@eecs.umich.edu    return a / b;
9657396Sgblack@eecs.umich.edu}
9667396Sgblack@eecs.umich.edu
9677396Sgblack@eecs.umich.edustatic inline double
9687396Sgblack@eecs.umich.edufpDivD(double a, double b)
9697396Sgblack@eecs.umich.edu{
9707396Sgblack@eecs.umich.edu    return a / b;
9717396Sgblack@eecs.umich.edu}
9727396Sgblack@eecs.umich.edu
9737396Sgblack@eecs.umich.edustatic inline float
9747396Sgblack@eecs.umich.edufpMulS(float a, float b)
9757396Sgblack@eecs.umich.edu{
9767396Sgblack@eecs.umich.edu    return a * b;
9777396Sgblack@eecs.umich.edu}
9787396Sgblack@eecs.umich.edu
9797396Sgblack@eecs.umich.edustatic inline double
9807396Sgblack@eecs.umich.edufpMulD(double a, double b)
9817396Sgblack@eecs.umich.edu{
9827396Sgblack@eecs.umich.edu    return a * b;
9837396Sgblack@eecs.umich.edu}
9847396Sgblack@eecs.umich.edu
9857396Sgblack@eecs.umich.educlass FpOp : public PredOp
9867375Sgblack@eecs.umich.edu{
9877375Sgblack@eecs.umich.edu  protected:
9887396Sgblack@eecs.umich.edu    FpOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
9897396Sgblack@eecs.umich.edu        PredOp(mnem, _machInst, __opClass)
9907396Sgblack@eecs.umich.edu    {}
9917396Sgblack@eecs.umich.edu
9927396Sgblack@eecs.umich.edu    virtual float
9937396Sgblack@eecs.umich.edu    doOp(float op1, float op2) const
9947396Sgblack@eecs.umich.edu    {
9957396Sgblack@eecs.umich.edu        panic("Unimplemented version of doOp called.\n");
9967396Sgblack@eecs.umich.edu    }
9977396Sgblack@eecs.umich.edu
9987396Sgblack@eecs.umich.edu    virtual float
9997396Sgblack@eecs.umich.edu    doOp(float op1) const
10007396Sgblack@eecs.umich.edu    {
10017396Sgblack@eecs.umich.edu        panic("Unimplemented version of doOp called.\n");
10027396Sgblack@eecs.umich.edu    }
10037396Sgblack@eecs.umich.edu
10047396Sgblack@eecs.umich.edu    virtual double
10057396Sgblack@eecs.umich.edu    doOp(double op1, double op2) const
10067396Sgblack@eecs.umich.edu    {
10077396Sgblack@eecs.umich.edu        panic("Unimplemented version of doOp called.\n");
10087396Sgblack@eecs.umich.edu    }
10097396Sgblack@eecs.umich.edu
10107396Sgblack@eecs.umich.edu    virtual double
10117396Sgblack@eecs.umich.edu    doOp(double op1) const
10127396Sgblack@eecs.umich.edu    {
10137396Sgblack@eecs.umich.edu        panic("Unimplemented version of doOp called.\n");
10147396Sgblack@eecs.umich.edu    }
10157396Sgblack@eecs.umich.edu
10167396Sgblack@eecs.umich.edu    double
10177396Sgblack@eecs.umich.edu    dbl(uint32_t low, uint32_t high) const
10187396Sgblack@eecs.umich.edu    {
10197396Sgblack@eecs.umich.edu        double junk = 0.0;
10207396Sgblack@eecs.umich.edu        return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk);
10217396Sgblack@eecs.umich.edu    }
10227396Sgblack@eecs.umich.edu
10237396Sgblack@eecs.umich.edu    uint32_t
10247396Sgblack@eecs.umich.edu    dblLow(double val) const
10257396Sgblack@eecs.umich.edu    {
10267396Sgblack@eecs.umich.edu        return fpToBits(val);
10277396Sgblack@eecs.umich.edu    }
10287396Sgblack@eecs.umich.edu
10297396Sgblack@eecs.umich.edu    uint32_t
10307396Sgblack@eecs.umich.edu    dblHi(double val) const
10317396Sgblack@eecs.umich.edu    {
10327396Sgblack@eecs.umich.edu        return fpToBits(val) >> 32;
10337396Sgblack@eecs.umich.edu    }
10347396Sgblack@eecs.umich.edu
10357396Sgblack@eecs.umich.edu    template <class fpType>
10367396Sgblack@eecs.umich.edu    fpType
10377396Sgblack@eecs.umich.edu    binaryOp(FPSCR &fpscr, fpType op1, fpType op2,
10387396Sgblack@eecs.umich.edu            fpType (*func)(fpType, fpType),
10397396Sgblack@eecs.umich.edu            bool flush, uint32_t rMode) const
10407396Sgblack@eecs.umich.edu    {
10417396Sgblack@eecs.umich.edu        const bool single = (sizeof(fpType) == sizeof(float));
10427396Sgblack@eecs.umich.edu        fpType junk = 0.0;
10437396Sgblack@eecs.umich.edu
10447396Sgblack@eecs.umich.edu        if (flush && flushToZero(op1, op2))
10457396Sgblack@eecs.umich.edu            fpscr.idc = 1;
10467396Sgblack@eecs.umich.edu        VfpSavedState state = prepFpState(rMode);
10477396Sgblack@eecs.umich.edu        __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2), "=m" (state)
10487396Sgblack@eecs.umich.edu                                 : "m" (op1), "m" (op2), "m" (state));
10497396Sgblack@eecs.umich.edu        fpType dest = func(op1, op2);
10507396Sgblack@eecs.umich.edu        __asm__ __volatile__ ("" : "=m" (dest) : "m" (dest));
10517396Sgblack@eecs.umich.edu
10527396Sgblack@eecs.umich.edu        int fpClass = std::fpclassify(dest);
10537396Sgblack@eecs.umich.edu        // Get NAN behavior right. This varies between x86 and ARM.
10547396Sgblack@eecs.umich.edu        if (fpClass == FP_NAN) {
10557396Sgblack@eecs.umich.edu            const bool single = (sizeof(fpType) == sizeof(float));
10567396Sgblack@eecs.umich.edu            const uint64_t qnan =
10577396Sgblack@eecs.umich.edu                single ? 0x7fc00000 : ULL(0x7ff8000000000000);
10587396Sgblack@eecs.umich.edu            const bool nan1 = std::isnan(op1);
10597396Sgblack@eecs.umich.edu            const bool nan2 = std::isnan(op2);
10607396Sgblack@eecs.umich.edu            const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan);
10617396Sgblack@eecs.umich.edu            const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan);
10627396Sgblack@eecs.umich.edu            if ((!nan1 && !nan2) || (fpscr.dn == 1)) {
10637396Sgblack@eecs.umich.edu                dest = bitsToFp(qnan, junk);
10647396Sgblack@eecs.umich.edu            } else if (signal1) {
10657396Sgblack@eecs.umich.edu                dest = bitsToFp(fpToBits(op1) | qnan, junk);
10667396Sgblack@eecs.umich.edu            } else if (signal2) {
10677396Sgblack@eecs.umich.edu                dest = bitsToFp(fpToBits(op2) | qnan, junk);
10687396Sgblack@eecs.umich.edu            } else if (nan1) {
10697396Sgblack@eecs.umich.edu                dest = op1;
10707396Sgblack@eecs.umich.edu            } else if (nan2) {
10717396Sgblack@eecs.umich.edu                dest = op2;
10727396Sgblack@eecs.umich.edu            }
10737396Sgblack@eecs.umich.edu        } else if (flush && flushToZero(dest)) {
10747396Sgblack@eecs.umich.edu            feraiseexcept(FeUnderflow);
10757396Sgblack@eecs.umich.edu        } else if ((
10767396Sgblack@eecs.umich.edu                    (single && (dest == bitsToFp(0x00800000, junk) ||
10777396Sgblack@eecs.umich.edu                         dest == bitsToFp(0x80800000, junk))) ||
10787396Sgblack@eecs.umich.edu                    (!single &&
10797396Sgblack@eecs.umich.edu                        (dest == bitsToFp(ULL(0x0010000000000000), junk) ||
10807396Sgblack@eecs.umich.edu                         dest == bitsToFp(ULL(0x8010000000000000), junk)))
10817396Sgblack@eecs.umich.edu                   ) && rMode != VfpRoundZero) {
10827396Sgblack@eecs.umich.edu            /*
10837396Sgblack@eecs.umich.edu             * Correct for the fact that underflow is detected -before- rounding
10847396Sgblack@eecs.umich.edu             * in ARM and -after- rounding in x86.
10857396Sgblack@eecs.umich.edu             */
10867396Sgblack@eecs.umich.edu            fesetround(FeRoundZero);
10877396Sgblack@eecs.umich.edu            __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2)
10887396Sgblack@eecs.umich.edu                                     : "m" (op1), "m" (op2));
10897396Sgblack@eecs.umich.edu            fpType temp = func(op1, op2);
10907396Sgblack@eecs.umich.edu            __asm__ __volatile__ ("" : "=m" (temp) : "m" (temp));
10917396Sgblack@eecs.umich.edu            if (flush && flushToZero(temp)) {
10927396Sgblack@eecs.umich.edu                dest = temp;
10937396Sgblack@eecs.umich.edu            }
10947396Sgblack@eecs.umich.edu        }
10957396Sgblack@eecs.umich.edu        finishVfp(fpscr, state);
10967396Sgblack@eecs.umich.edu        return dest;
10977396Sgblack@eecs.umich.edu    }
10987396Sgblack@eecs.umich.edu
10997396Sgblack@eecs.umich.edu    template <class fpType>
11007396Sgblack@eecs.umich.edu    fpType
11017396Sgblack@eecs.umich.edu    unaryOp(FPSCR &fpscr, fpType op1,
11027396Sgblack@eecs.umich.edu            fpType (*func)(fpType),
11037396Sgblack@eecs.umich.edu            bool flush, uint32_t rMode) const
11047396Sgblack@eecs.umich.edu    {
11057396Sgblack@eecs.umich.edu        const bool single = (sizeof(fpType) == sizeof(float));
11067396Sgblack@eecs.umich.edu        fpType junk = 0.0;
11077396Sgblack@eecs.umich.edu
11087396Sgblack@eecs.umich.edu        if (flush && flushToZero(op1))
11097396Sgblack@eecs.umich.edu            fpscr.idc = 1;
11107396Sgblack@eecs.umich.edu        VfpSavedState state = prepFpState(rMode);
11117396Sgblack@eecs.umich.edu        __asm__ __volatile__ ("" : "=m" (op1), "=m" (state)
11127396Sgblack@eecs.umich.edu                                 : "m" (op1), "m" (state));
11137396Sgblack@eecs.umich.edu        fpType dest = func(op1);
11147396Sgblack@eecs.umich.edu        __asm__ __volatile__ ("" : "=m" (dest) : "m" (dest));
11157396Sgblack@eecs.umich.edu
11167396Sgblack@eecs.umich.edu        int fpClass = std::fpclassify(dest);
11177396Sgblack@eecs.umich.edu        // Get NAN behavior right. This varies between x86 and ARM.
11187396Sgblack@eecs.umich.edu        if (fpClass == FP_NAN) {
11197396Sgblack@eecs.umich.edu            const bool single = (sizeof(fpType) == sizeof(float));
11207396Sgblack@eecs.umich.edu            const uint64_t qnan =
11217396Sgblack@eecs.umich.edu                single ? 0x7fc00000 : ULL(0x7ff8000000000000);
11227396Sgblack@eecs.umich.edu            const bool nan = std::isnan(op1);
11237396Sgblack@eecs.umich.edu            if (!nan || fpscr.dn == 1) {
11247396Sgblack@eecs.umich.edu                dest = bitsToFp(qnan, junk);
11257396Sgblack@eecs.umich.edu            } else if (nan) {
11267396Sgblack@eecs.umich.edu                dest = bitsToFp(fpToBits(op1) | qnan, junk);
11277396Sgblack@eecs.umich.edu            }
11287396Sgblack@eecs.umich.edu        } else if (flush && flushToZero(dest)) {
11297396Sgblack@eecs.umich.edu            feraiseexcept(FeUnderflow);
11307396Sgblack@eecs.umich.edu        } else if ((
11317396Sgblack@eecs.umich.edu                    (single && (dest == bitsToFp(0x00800000, junk) ||
11327396Sgblack@eecs.umich.edu                         dest == bitsToFp(0x80800000, junk))) ||
11337396Sgblack@eecs.umich.edu                    (!single &&
11347396Sgblack@eecs.umich.edu                        (dest == bitsToFp(ULL(0x0010000000000000), junk) ||
11357396Sgblack@eecs.umich.edu                         dest == bitsToFp(ULL(0x8010000000000000), junk)))
11367396Sgblack@eecs.umich.edu                   ) && rMode != VfpRoundZero) {
11377396Sgblack@eecs.umich.edu            /*
11387396Sgblack@eecs.umich.edu             * Correct for the fact that underflow is detected -before- rounding
11397396Sgblack@eecs.umich.edu             * in ARM and -after- rounding in x86.
11407396Sgblack@eecs.umich.edu             */
11417396Sgblack@eecs.umich.edu            fesetround(FeRoundZero);
11427396Sgblack@eecs.umich.edu            __asm__ __volatile__ ("" : "=m" (op1) : "m" (op1));
11437396Sgblack@eecs.umich.edu            fpType temp = func(op1);
11447396Sgblack@eecs.umich.edu            __asm__ __volatile__ ("" : "=m" (temp) : "m" (temp));
11457396Sgblack@eecs.umich.edu            if (flush && flushToZero(temp)) {
11467396Sgblack@eecs.umich.edu                dest = temp;
11477396Sgblack@eecs.umich.edu            }
11487396Sgblack@eecs.umich.edu        }
11497396Sgblack@eecs.umich.edu        finishVfp(fpscr, state);
11507396Sgblack@eecs.umich.edu        return dest;
11517396Sgblack@eecs.umich.edu    }
11527396Sgblack@eecs.umich.edu};
11537396Sgblack@eecs.umich.edu
11547396Sgblack@eecs.umich.educlass FpRegRegOp : public FpOp
11557396Sgblack@eecs.umich.edu{
11567396Sgblack@eecs.umich.edu  protected:
11577396Sgblack@eecs.umich.edu    IntRegIndex dest;
11587396Sgblack@eecs.umich.edu    IntRegIndex op1;
11597396Sgblack@eecs.umich.edu
11607396Sgblack@eecs.umich.edu    FpRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
11617396Sgblack@eecs.umich.edu               IntRegIndex _dest, IntRegIndex _op1,
11627396Sgblack@eecs.umich.edu               VfpMicroMode mode = VfpNotAMicroop) :
11637396Sgblack@eecs.umich.edu        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1)
11647375Sgblack@eecs.umich.edu    {
11657375Sgblack@eecs.umich.edu        setVfpMicroFlags(mode, flags);
11667375Sgblack@eecs.umich.edu    }
11677396Sgblack@eecs.umich.edu
11687396Sgblack@eecs.umich.edu    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
11697375Sgblack@eecs.umich.edu};
11707375Sgblack@eecs.umich.edu
11717396Sgblack@eecs.umich.educlass FpRegImmOp : public FpOp
11727375Sgblack@eecs.umich.edu{
11737375Sgblack@eecs.umich.edu  protected:
11747396Sgblack@eecs.umich.edu    IntRegIndex dest;
11757396Sgblack@eecs.umich.edu    uint64_t imm;
11767396Sgblack@eecs.umich.edu
11777396Sgblack@eecs.umich.edu    FpRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
11787396Sgblack@eecs.umich.edu               IntRegIndex _dest, uint64_t _imm,
11797396Sgblack@eecs.umich.edu               VfpMicroMode mode = VfpNotAMicroop) :
11807396Sgblack@eecs.umich.edu        FpOp(mnem, _machInst, __opClass), dest(_dest), imm(_imm)
11817375Sgblack@eecs.umich.edu    {
11827375Sgblack@eecs.umich.edu        setVfpMicroFlags(mode, flags);
11837375Sgblack@eecs.umich.edu    }
11847396Sgblack@eecs.umich.edu
11857396Sgblack@eecs.umich.edu    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
11867375Sgblack@eecs.umich.edu};
11877375Sgblack@eecs.umich.edu
11887396Sgblack@eecs.umich.educlass FpRegRegImmOp : public FpOp
11897375Sgblack@eecs.umich.edu{
11907375Sgblack@eecs.umich.edu  protected:
11917396Sgblack@eecs.umich.edu    IntRegIndex dest;
11927396Sgblack@eecs.umich.edu    IntRegIndex op1;
11937396Sgblack@eecs.umich.edu    uint64_t imm;
11947396Sgblack@eecs.umich.edu
11957396Sgblack@eecs.umich.edu    FpRegRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
11967396Sgblack@eecs.umich.edu                  IntRegIndex _dest, IntRegIndex _op1,
11977396Sgblack@eecs.umich.edu                  uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) :
11987396Sgblack@eecs.umich.edu        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), imm(_imm)
11997375Sgblack@eecs.umich.edu    {
12007375Sgblack@eecs.umich.edu        setVfpMicroFlags(mode, flags);
12017375Sgblack@eecs.umich.edu    }
12027396Sgblack@eecs.umich.edu
12037396Sgblack@eecs.umich.edu    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
12047375Sgblack@eecs.umich.edu};
12057375Sgblack@eecs.umich.edu
12067396Sgblack@eecs.umich.educlass FpRegRegRegOp : public FpOp
12077375Sgblack@eecs.umich.edu{
12087375Sgblack@eecs.umich.edu  protected:
12097396Sgblack@eecs.umich.edu    IntRegIndex dest;
12107396Sgblack@eecs.umich.edu    IntRegIndex op1;
12117396Sgblack@eecs.umich.edu    IntRegIndex op2;
12127396Sgblack@eecs.umich.edu
12137396Sgblack@eecs.umich.edu    FpRegRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
12147396Sgblack@eecs.umich.edu                  IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2,
12157396Sgblack@eecs.umich.edu                  VfpMicroMode mode = VfpNotAMicroop) :
12167396Sgblack@eecs.umich.edu        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), op2(_op2)
12177375Sgblack@eecs.umich.edu    {
12187375Sgblack@eecs.umich.edu        setVfpMicroFlags(mode, flags);
12197375Sgblack@eecs.umich.edu    }
12207396Sgblack@eecs.umich.edu
12217396Sgblack@eecs.umich.edu    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
12227375Sgblack@eecs.umich.edu};
12237375Sgblack@eecs.umich.edu
12247384Sgblack@eecs.umich.edu}
12257384Sgblack@eecs.umich.edu
12267375Sgblack@eecs.umich.edu#endif //__ARCH_ARM_INSTS_VFP_HH__
1227