vfp.cc revision 7434
17396Sgblack@eecs.umich.edu/* 27396Sgblack@eecs.umich.edu * Copyright (c) 2010 ARM Limited 37396Sgblack@eecs.umich.edu * All rights reserved 47396Sgblack@eecs.umich.edu * 57396Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall 67396Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual 77396Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating 87396Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software 97396Sgblack@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 107396Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 117396Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 127396Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form. 137396Sgblack@eecs.umich.edu * 147396Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 157396Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 167396Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 177396Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 187396Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 197396Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 207396Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 217396Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 227396Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 237396Sgblack@eecs.umich.edu * this software without specific prior written permission. 247396Sgblack@eecs.umich.edu * 257396Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 267396Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 277396Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 287396Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 297396Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 307396Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 317396Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 327396Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 337396Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 347396Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 357396Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 367396Sgblack@eecs.umich.edu * 377396Sgblack@eecs.umich.edu * Authors: Gabe Black 387396Sgblack@eecs.umich.edu */ 397396Sgblack@eecs.umich.edu 407396Sgblack@eecs.umich.edu#include "arch/arm/insts/vfp.hh" 417396Sgblack@eecs.umich.edu 427434Sgblack@eecs.umich.edu/* 437434Sgblack@eecs.umich.edu * The asm statements below are to keep gcc from reordering code. Otherwise 447434Sgblack@eecs.umich.edu * the rounding mode might be set after the operation it was intended for, the 457434Sgblack@eecs.umich.edu * exception bits read before it, etc. 467434Sgblack@eecs.umich.edu */ 477434Sgblack@eecs.umich.edu 487396Sgblack@eecs.umich.edustd::string 497396Sgblack@eecs.umich.eduFpRegRegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const 507396Sgblack@eecs.umich.edu{ 517396Sgblack@eecs.umich.edu std::stringstream ss; 527396Sgblack@eecs.umich.edu printMnemonic(ss); 537396Sgblack@eecs.umich.edu printReg(ss, dest + FP_Base_DepTag); 547396Sgblack@eecs.umich.edu ss << ", "; 557396Sgblack@eecs.umich.edu printReg(ss, op1 + FP_Base_DepTag); 567396Sgblack@eecs.umich.edu return ss.str(); 577396Sgblack@eecs.umich.edu} 587396Sgblack@eecs.umich.edu 597396Sgblack@eecs.umich.edustd::string 607396Sgblack@eecs.umich.eduFpRegImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const 617396Sgblack@eecs.umich.edu{ 627396Sgblack@eecs.umich.edu std::stringstream ss; 637396Sgblack@eecs.umich.edu printMnemonic(ss); 647396Sgblack@eecs.umich.edu printReg(ss, dest + FP_Base_DepTag); 657396Sgblack@eecs.umich.edu ccprintf(ss, ", #%d", imm); 667396Sgblack@eecs.umich.edu return ss.str(); 677396Sgblack@eecs.umich.edu} 687396Sgblack@eecs.umich.edu 697396Sgblack@eecs.umich.edustd::string 707396Sgblack@eecs.umich.eduFpRegRegImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const 717396Sgblack@eecs.umich.edu{ 727396Sgblack@eecs.umich.edu std::stringstream ss; 737396Sgblack@eecs.umich.edu printMnemonic(ss); 747396Sgblack@eecs.umich.edu printReg(ss, dest + FP_Base_DepTag); 757396Sgblack@eecs.umich.edu ss << ", "; 767396Sgblack@eecs.umich.edu printReg(ss, op1 + FP_Base_DepTag); 777396Sgblack@eecs.umich.edu ccprintf(ss, ", #%d", imm); 787396Sgblack@eecs.umich.edu return ss.str(); 797396Sgblack@eecs.umich.edu} 807396Sgblack@eecs.umich.edu 817396Sgblack@eecs.umich.edustd::string 827396Sgblack@eecs.umich.eduFpRegRegRegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const 837396Sgblack@eecs.umich.edu{ 847396Sgblack@eecs.umich.edu std::stringstream ss; 857396Sgblack@eecs.umich.edu printMnemonic(ss); 867396Sgblack@eecs.umich.edu printReg(ss, dest + FP_Base_DepTag); 877396Sgblack@eecs.umich.edu ss << ", "; 887396Sgblack@eecs.umich.edu printReg(ss, op1 + FP_Base_DepTag); 897396Sgblack@eecs.umich.edu ss << ", "; 907396Sgblack@eecs.umich.edu printReg(ss, op2 + FP_Base_DepTag); 917396Sgblack@eecs.umich.edu return ss.str(); 927396Sgblack@eecs.umich.edu} 937430Sgblack@eecs.umich.edu 947430Sgblack@eecs.umich.edunamespace ArmISA 957430Sgblack@eecs.umich.edu{ 967430Sgblack@eecs.umich.edu 977430Sgblack@eecs.umich.eduVfpSavedState 987430Sgblack@eecs.umich.eduprepFpState(uint32_t rMode) 997430Sgblack@eecs.umich.edu{ 1007430Sgblack@eecs.umich.edu int roundingMode = fegetround(); 1017430Sgblack@eecs.umich.edu feclearexcept(FeAllExceptions); 1027430Sgblack@eecs.umich.edu switch (rMode) { 1037430Sgblack@eecs.umich.edu case VfpRoundNearest: 1047430Sgblack@eecs.umich.edu fesetround(FeRoundNearest); 1057430Sgblack@eecs.umich.edu break; 1067430Sgblack@eecs.umich.edu case VfpRoundUpward: 1077430Sgblack@eecs.umich.edu fesetround(FeRoundUpward); 1087430Sgblack@eecs.umich.edu break; 1097430Sgblack@eecs.umich.edu case VfpRoundDown: 1107430Sgblack@eecs.umich.edu fesetround(FeRoundDown); 1117430Sgblack@eecs.umich.edu break; 1127430Sgblack@eecs.umich.edu case VfpRoundZero: 1137430Sgblack@eecs.umich.edu fesetround(FeRoundZero); 1147430Sgblack@eecs.umich.edu break; 1157430Sgblack@eecs.umich.edu } 1167430Sgblack@eecs.umich.edu return roundingMode; 1177430Sgblack@eecs.umich.edu} 1187430Sgblack@eecs.umich.edu 1197430Sgblack@eecs.umich.eduvoid 1207430Sgblack@eecs.umich.edufinishVfp(FPSCR &fpscr, VfpSavedState state) 1217430Sgblack@eecs.umich.edu{ 1227430Sgblack@eecs.umich.edu int exceptions = fetestexcept(FeAllExceptions); 1237430Sgblack@eecs.umich.edu bool underflow = false; 1247430Sgblack@eecs.umich.edu if (exceptions & FeInvalid) { 1257430Sgblack@eecs.umich.edu fpscr.ioc = 1; 1267430Sgblack@eecs.umich.edu } 1277430Sgblack@eecs.umich.edu if (exceptions & FeDivByZero) { 1287430Sgblack@eecs.umich.edu fpscr.dzc = 1; 1297430Sgblack@eecs.umich.edu } 1307430Sgblack@eecs.umich.edu if (exceptions & FeOverflow) { 1317430Sgblack@eecs.umich.edu fpscr.ofc = 1; 1327430Sgblack@eecs.umich.edu } 1337430Sgblack@eecs.umich.edu if (exceptions & FeUnderflow) { 1347430Sgblack@eecs.umich.edu underflow = true; 1357430Sgblack@eecs.umich.edu fpscr.ufc = 1; 1367430Sgblack@eecs.umich.edu } 1377430Sgblack@eecs.umich.edu if ((exceptions & FeInexact) && !(underflow && fpscr.fz)) { 1387430Sgblack@eecs.umich.edu fpscr.ixc = 1; 1397430Sgblack@eecs.umich.edu } 1407430Sgblack@eecs.umich.edu fesetround(state); 1417430Sgblack@eecs.umich.edu} 1427430Sgblack@eecs.umich.edu 1437430Sgblack@eecs.umich.edutemplate <class fpType> 1447430Sgblack@eecs.umich.edufpType 1457430Sgblack@eecs.umich.edufixDest(FPSCR fpscr, fpType val, fpType op1) 1467430Sgblack@eecs.umich.edu{ 1477430Sgblack@eecs.umich.edu int fpClass = std::fpclassify(val); 1487430Sgblack@eecs.umich.edu fpType junk = 0.0; 1497430Sgblack@eecs.umich.edu if (fpClass == FP_NAN) { 1507430Sgblack@eecs.umich.edu const bool single = (sizeof(val) == sizeof(float)); 1517430Sgblack@eecs.umich.edu const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000); 1527430Sgblack@eecs.umich.edu const bool nan = std::isnan(op1); 1537430Sgblack@eecs.umich.edu if (!nan || (fpscr.dn == 1)) { 1547430Sgblack@eecs.umich.edu val = bitsToFp(qnan, junk); 1557430Sgblack@eecs.umich.edu } else if (nan) { 1567430Sgblack@eecs.umich.edu val = bitsToFp(fpToBits(op1) | qnan, junk); 1577430Sgblack@eecs.umich.edu } 1587430Sgblack@eecs.umich.edu } else if (fpClass == FP_SUBNORMAL && fpscr.fz == 1) { 1597430Sgblack@eecs.umich.edu // Turn val into a zero with the correct sign; 1607430Sgblack@eecs.umich.edu uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1); 1617430Sgblack@eecs.umich.edu val = bitsToFp(fpToBits(val) & bitMask, junk); 1627430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 1637430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 1647430Sgblack@eecs.umich.edu } 1657430Sgblack@eecs.umich.edu return val; 1667430Sgblack@eecs.umich.edu} 1677430Sgblack@eecs.umich.edu 1687430Sgblack@eecs.umich.edutemplate 1697430Sgblack@eecs.umich.edufloat fixDest<float>(FPSCR fpscr, float val, float op1); 1707430Sgblack@eecs.umich.edutemplate 1717430Sgblack@eecs.umich.edudouble fixDest<double>(FPSCR fpscr, double val, double op1); 1727430Sgblack@eecs.umich.edu 1737430Sgblack@eecs.umich.edutemplate <class fpType> 1747430Sgblack@eecs.umich.edufpType 1757430Sgblack@eecs.umich.edufixDest(FPSCR fpscr, fpType val, fpType op1, fpType op2) 1767430Sgblack@eecs.umich.edu{ 1777430Sgblack@eecs.umich.edu int fpClass = std::fpclassify(val); 1787430Sgblack@eecs.umich.edu fpType junk = 0.0; 1797430Sgblack@eecs.umich.edu if (fpClass == FP_NAN) { 1807430Sgblack@eecs.umich.edu const bool single = (sizeof(val) == sizeof(float)); 1817430Sgblack@eecs.umich.edu const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000); 1827430Sgblack@eecs.umich.edu const bool nan1 = std::isnan(op1); 1837430Sgblack@eecs.umich.edu const bool nan2 = std::isnan(op2); 1847430Sgblack@eecs.umich.edu const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan); 1857430Sgblack@eecs.umich.edu const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan); 1867430Sgblack@eecs.umich.edu if ((!nan1 && !nan2) || (fpscr.dn == 1)) { 1877430Sgblack@eecs.umich.edu val = bitsToFp(qnan, junk); 1887430Sgblack@eecs.umich.edu } else if (signal1) { 1897430Sgblack@eecs.umich.edu val = bitsToFp(fpToBits(op1) | qnan, junk); 1907430Sgblack@eecs.umich.edu } else if (signal2) { 1917430Sgblack@eecs.umich.edu val = bitsToFp(fpToBits(op2) | qnan, junk); 1927430Sgblack@eecs.umich.edu } else if (nan1) { 1937430Sgblack@eecs.umich.edu val = op1; 1947430Sgblack@eecs.umich.edu } else if (nan2) { 1957430Sgblack@eecs.umich.edu val = op2; 1967430Sgblack@eecs.umich.edu } 1977430Sgblack@eecs.umich.edu } else if (fpClass == FP_SUBNORMAL && fpscr.fz == 1) { 1987430Sgblack@eecs.umich.edu // Turn val into a zero with the correct sign; 1997430Sgblack@eecs.umich.edu uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1); 2007430Sgblack@eecs.umich.edu val = bitsToFp(fpToBits(val) & bitMask, junk); 2017430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 2027430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 2037430Sgblack@eecs.umich.edu } 2047430Sgblack@eecs.umich.edu return val; 2057430Sgblack@eecs.umich.edu} 2067430Sgblack@eecs.umich.edu 2077430Sgblack@eecs.umich.edutemplate 2087430Sgblack@eecs.umich.edufloat fixDest<float>(FPSCR fpscr, float val, float op1, float op2); 2097430Sgblack@eecs.umich.edutemplate 2107430Sgblack@eecs.umich.edudouble fixDest<double>(FPSCR fpscr, double val, double op1, double op2); 2117430Sgblack@eecs.umich.edu 2127430Sgblack@eecs.umich.edutemplate <class fpType> 2137430Sgblack@eecs.umich.edufpType 2147430Sgblack@eecs.umich.edufixDivDest(FPSCR fpscr, fpType val, fpType op1, fpType op2) 2157430Sgblack@eecs.umich.edu{ 2167430Sgblack@eecs.umich.edu fpType mid = fixDest(fpscr, val, op1, op2); 2177430Sgblack@eecs.umich.edu const bool single = (sizeof(fpType) == sizeof(float)); 2187430Sgblack@eecs.umich.edu const fpType junk = 0.0; 2197430Sgblack@eecs.umich.edu if ((single && (val == bitsToFp(0x00800000, junk) || 2207430Sgblack@eecs.umich.edu val == bitsToFp(0x80800000, junk))) || 2217430Sgblack@eecs.umich.edu (!single && (val == bitsToFp(ULL(0x0010000000000000), junk) || 2227430Sgblack@eecs.umich.edu val == bitsToFp(ULL(0x8010000000000000), junk))) 2237430Sgblack@eecs.umich.edu ) { 2247430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (op1) : "m" (op1)); 2257430Sgblack@eecs.umich.edu fesetround(FeRoundZero); 2267430Sgblack@eecs.umich.edu fpType temp = 0.0; 2277430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (temp) : "m" (temp)); 2287430Sgblack@eecs.umich.edu temp = op1 / op2; 2297430Sgblack@eecs.umich.edu if (flushToZero(temp)) { 2307430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 2317430Sgblack@eecs.umich.edu if (fpscr.fz) { 2327430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 2337430Sgblack@eecs.umich.edu mid = temp; 2347430Sgblack@eecs.umich.edu } 2357430Sgblack@eecs.umich.edu } 2367430Sgblack@eecs.umich.edu __asm__ __volatile__("" :: "m" (temp)); 2377430Sgblack@eecs.umich.edu } 2387430Sgblack@eecs.umich.edu return mid; 2397430Sgblack@eecs.umich.edu} 2407430Sgblack@eecs.umich.edu 2417430Sgblack@eecs.umich.edutemplate 2427430Sgblack@eecs.umich.edufloat fixDivDest<float>(FPSCR fpscr, float val, float op1, float op2); 2437430Sgblack@eecs.umich.edutemplate 2447430Sgblack@eecs.umich.edudouble fixDivDest<double>(FPSCR fpscr, double val, double op1, double op2); 2457430Sgblack@eecs.umich.edu 2467430Sgblack@eecs.umich.edufloat 2477430Sgblack@eecs.umich.edufixFpDFpSDest(FPSCR fpscr, double val) 2487430Sgblack@eecs.umich.edu{ 2497430Sgblack@eecs.umich.edu const float junk = 0.0; 2507430Sgblack@eecs.umich.edu float op1 = 0.0; 2517430Sgblack@eecs.umich.edu if (std::isnan(val)) { 2527430Sgblack@eecs.umich.edu uint64_t valBits = fpToBits(val); 2537430Sgblack@eecs.umich.edu uint32_t op1Bits = bits(valBits, 50, 29) | 2547430Sgblack@eecs.umich.edu (mask(9) << 22) | 2557430Sgblack@eecs.umich.edu (bits(valBits, 63) << 31); 2567430Sgblack@eecs.umich.edu op1 = bitsToFp(op1Bits, junk); 2577430Sgblack@eecs.umich.edu } 2587430Sgblack@eecs.umich.edu float mid = fixDest(fpscr, (float)val, op1); 2597430Sgblack@eecs.umich.edu if (fpscr.fz && fetestexcept(FeUnderflow | FeInexact) == 2607430Sgblack@eecs.umich.edu (FeUnderflow | FeInexact)) { 2617430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 2627430Sgblack@eecs.umich.edu } 2637430Sgblack@eecs.umich.edu if (mid == bitsToFp(0x00800000, junk) || 2647430Sgblack@eecs.umich.edu mid == bitsToFp(0x80800000, junk)) { 2657430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (val) : "m" (val)); 2667430Sgblack@eecs.umich.edu fesetround(FeRoundZero); 2677430Sgblack@eecs.umich.edu float temp = 0.0; 2687430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (temp) : "m" (temp)); 2697430Sgblack@eecs.umich.edu temp = val; 2707430Sgblack@eecs.umich.edu if (flushToZero(temp)) { 2717430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 2727430Sgblack@eecs.umich.edu if (fpscr.fz) { 2737430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 2747430Sgblack@eecs.umich.edu mid = temp; 2757430Sgblack@eecs.umich.edu } 2767430Sgblack@eecs.umich.edu } 2777430Sgblack@eecs.umich.edu __asm__ __volatile__("" :: "m" (temp)); 2787430Sgblack@eecs.umich.edu } 2797430Sgblack@eecs.umich.edu return mid; 2807430Sgblack@eecs.umich.edu} 2817430Sgblack@eecs.umich.edu 2827430Sgblack@eecs.umich.edudouble 2837430Sgblack@eecs.umich.edufixFpSFpDDest(FPSCR fpscr, float val) 2847430Sgblack@eecs.umich.edu{ 2857430Sgblack@eecs.umich.edu const double junk = 0.0; 2867430Sgblack@eecs.umich.edu double op1 = 0.0; 2877430Sgblack@eecs.umich.edu if (std::isnan(val)) { 2887430Sgblack@eecs.umich.edu uint32_t valBits = fpToBits(val); 2897430Sgblack@eecs.umich.edu uint64_t op1Bits = ((uint64_t)bits(valBits, 21, 0) << 29) | 2907430Sgblack@eecs.umich.edu (mask(12) << 51) | 2917430Sgblack@eecs.umich.edu ((uint64_t)bits(valBits, 31) << 63); 2927430Sgblack@eecs.umich.edu op1 = bitsToFp(op1Bits, junk); 2937430Sgblack@eecs.umich.edu } 2947430Sgblack@eecs.umich.edu double mid = fixDest(fpscr, (double)val, op1); 2957430Sgblack@eecs.umich.edu if (mid == bitsToFp(ULL(0x0010000000000000), junk) || 2967430Sgblack@eecs.umich.edu mid == bitsToFp(ULL(0x8010000000000000), junk)) { 2977430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (val) : "m" (val)); 2987430Sgblack@eecs.umich.edu fesetround(FeRoundZero); 2997430Sgblack@eecs.umich.edu double temp = 0.0; 3007430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (temp) : "m" (temp)); 3017430Sgblack@eecs.umich.edu temp = val; 3027430Sgblack@eecs.umich.edu if (flushToZero(temp)) { 3037430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 3047430Sgblack@eecs.umich.edu if (fpscr.fz) { 3057430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 3067430Sgblack@eecs.umich.edu mid = temp; 3077430Sgblack@eecs.umich.edu } 3087430Sgblack@eecs.umich.edu } 3097430Sgblack@eecs.umich.edu __asm__ __volatile__("" :: "m" (temp)); 3107430Sgblack@eecs.umich.edu } 3117430Sgblack@eecs.umich.edu return mid; 3127430Sgblack@eecs.umich.edu} 3137430Sgblack@eecs.umich.edu 3147430Sgblack@eecs.umich.edufloat 3157430Sgblack@eecs.umich.eduvcvtFpSFpH(FPSCR &fpscr, float op, float dest, bool top) 3167430Sgblack@eecs.umich.edu{ 3177430Sgblack@eecs.umich.edu float junk = 0.0; 3187430Sgblack@eecs.umich.edu uint32_t destBits = fpToBits(dest); 3197430Sgblack@eecs.umich.edu uint32_t opBits = fpToBits(op); 3207430Sgblack@eecs.umich.edu // Extract the operand. 3217430Sgblack@eecs.umich.edu bool neg = bits(opBits, 31); 3227430Sgblack@eecs.umich.edu uint32_t exponent = bits(opBits, 30, 23); 3237430Sgblack@eecs.umich.edu uint32_t oldMantissa = bits(opBits, 22, 0); 3247430Sgblack@eecs.umich.edu uint32_t mantissa = oldMantissa >> (23 - 10); 3257430Sgblack@eecs.umich.edu // Do the conversion. 3267430Sgblack@eecs.umich.edu uint32_t extra = oldMantissa & mask(23 - 10); 3277430Sgblack@eecs.umich.edu if (exponent == 0xff) { 3287430Sgblack@eecs.umich.edu if (oldMantissa != 0) { 3297430Sgblack@eecs.umich.edu // Nans. 3307430Sgblack@eecs.umich.edu if (bits(mantissa, 9) == 0) { 3317430Sgblack@eecs.umich.edu // Signalling nan. 3327430Sgblack@eecs.umich.edu fpscr.ioc = 1; 3337430Sgblack@eecs.umich.edu } 3347430Sgblack@eecs.umich.edu if (fpscr.ahp) { 3357430Sgblack@eecs.umich.edu mantissa = 0; 3367430Sgblack@eecs.umich.edu exponent = 0; 3377430Sgblack@eecs.umich.edu fpscr.ioc = 1; 3387430Sgblack@eecs.umich.edu } else if (fpscr.dn) { 3397430Sgblack@eecs.umich.edu mantissa = (1 << 9); 3407430Sgblack@eecs.umich.edu exponent = 0x1f; 3417430Sgblack@eecs.umich.edu neg = false; 3427430Sgblack@eecs.umich.edu } else { 3437430Sgblack@eecs.umich.edu exponent = 0x1f; 3447430Sgblack@eecs.umich.edu mantissa |= (1 << 9); 3457430Sgblack@eecs.umich.edu } 3467430Sgblack@eecs.umich.edu } else { 3477430Sgblack@eecs.umich.edu // Infinities. 3487430Sgblack@eecs.umich.edu exponent = 0x1F; 3497430Sgblack@eecs.umich.edu if (fpscr.ahp) { 3507430Sgblack@eecs.umich.edu fpscr.ioc = 1; 3517430Sgblack@eecs.umich.edu mantissa = 0x3ff; 3527430Sgblack@eecs.umich.edu } else { 3537430Sgblack@eecs.umich.edu mantissa = 0; 3547430Sgblack@eecs.umich.edu } 3557430Sgblack@eecs.umich.edu } 3567430Sgblack@eecs.umich.edu } else if (exponent == 0 && oldMantissa == 0) { 3577430Sgblack@eecs.umich.edu // Zero, don't need to do anything. 3587430Sgblack@eecs.umich.edu } else { 3597430Sgblack@eecs.umich.edu // Normalized or denormalized numbers. 3607430Sgblack@eecs.umich.edu 3617430Sgblack@eecs.umich.edu bool inexact = (extra != 0); 3627430Sgblack@eecs.umich.edu 3637430Sgblack@eecs.umich.edu if (exponent == 0) { 3647430Sgblack@eecs.umich.edu // Denormalized. 3657430Sgblack@eecs.umich.edu 3667430Sgblack@eecs.umich.edu // If flush to zero is on, this shouldn't happen. 3677430Sgblack@eecs.umich.edu assert(fpscr.fz == 0); 3687430Sgblack@eecs.umich.edu 3697430Sgblack@eecs.umich.edu // Check for underflow 3707430Sgblack@eecs.umich.edu if (inexact || fpscr.ufe) 3717430Sgblack@eecs.umich.edu fpscr.ufc = 1; 3727430Sgblack@eecs.umich.edu 3737430Sgblack@eecs.umich.edu // Handle rounding. 3747430Sgblack@eecs.umich.edu unsigned mode = fpscr.rMode; 3757430Sgblack@eecs.umich.edu if ((mode == VfpRoundUpward && !neg && extra) || 3767430Sgblack@eecs.umich.edu (mode == VfpRoundDown && neg && extra) || 3777430Sgblack@eecs.umich.edu (mode == VfpRoundNearest && 3787430Sgblack@eecs.umich.edu (extra > (1 << 9) || 3797430Sgblack@eecs.umich.edu (extra == (1 << 9) && bits(mantissa, 0))))) { 3807430Sgblack@eecs.umich.edu mantissa++; 3817430Sgblack@eecs.umich.edu } 3827430Sgblack@eecs.umich.edu 3837430Sgblack@eecs.umich.edu // See if the number became normalized after rounding. 3847430Sgblack@eecs.umich.edu if (mantissa == (1 << 10)) { 3857430Sgblack@eecs.umich.edu mantissa = 0; 3867430Sgblack@eecs.umich.edu exponent = 1; 3877430Sgblack@eecs.umich.edu } 3887430Sgblack@eecs.umich.edu } else { 3897430Sgblack@eecs.umich.edu // Normalized. 3907430Sgblack@eecs.umich.edu 3917430Sgblack@eecs.umich.edu // We need to track the dropped bits differently since 3927430Sgblack@eecs.umich.edu // more can be dropped by denormalizing. 3937430Sgblack@eecs.umich.edu bool topOne = bits(extra, 12); 3947430Sgblack@eecs.umich.edu bool restZeros = bits(extra, 11, 0) == 0; 3957430Sgblack@eecs.umich.edu 3967430Sgblack@eecs.umich.edu if (exponent <= (127 - 15)) { 3977430Sgblack@eecs.umich.edu // The result is too small. Denormalize. 3987430Sgblack@eecs.umich.edu mantissa |= (1 << 10); 3997430Sgblack@eecs.umich.edu while (mantissa && exponent <= (127 - 15)) { 4007430Sgblack@eecs.umich.edu restZeros = restZeros && !topOne; 4017430Sgblack@eecs.umich.edu topOne = bits(mantissa, 0); 4027430Sgblack@eecs.umich.edu mantissa = mantissa >> 1; 4037430Sgblack@eecs.umich.edu exponent++; 4047430Sgblack@eecs.umich.edu } 4057430Sgblack@eecs.umich.edu if (topOne || !restZeros) 4067430Sgblack@eecs.umich.edu inexact = true; 4077430Sgblack@eecs.umich.edu exponent = 0; 4087430Sgblack@eecs.umich.edu } else { 4097430Sgblack@eecs.umich.edu // Change bias. 4107430Sgblack@eecs.umich.edu exponent -= (127 - 15); 4117430Sgblack@eecs.umich.edu } 4127430Sgblack@eecs.umich.edu 4137430Sgblack@eecs.umich.edu if (exponent == 0 && (inexact || fpscr.ufe)) { 4147430Sgblack@eecs.umich.edu // Underflow 4157430Sgblack@eecs.umich.edu fpscr.ufc = 1; 4167430Sgblack@eecs.umich.edu } 4177430Sgblack@eecs.umich.edu 4187430Sgblack@eecs.umich.edu // Handle rounding. 4197430Sgblack@eecs.umich.edu unsigned mode = fpscr.rMode; 4207430Sgblack@eecs.umich.edu bool nonZero = topOne || !restZeros; 4217430Sgblack@eecs.umich.edu if ((mode == VfpRoundUpward && !neg && nonZero) || 4227430Sgblack@eecs.umich.edu (mode == VfpRoundDown && neg && nonZero) || 4237430Sgblack@eecs.umich.edu (mode == VfpRoundNearest && topOne && 4247430Sgblack@eecs.umich.edu (!restZeros || bits(mantissa, 0)))) { 4257430Sgblack@eecs.umich.edu mantissa++; 4267430Sgblack@eecs.umich.edu } 4277430Sgblack@eecs.umich.edu 4287430Sgblack@eecs.umich.edu // See if we rounded up and need to bump the exponent. 4297430Sgblack@eecs.umich.edu if (mantissa == (1 << 10)) { 4307430Sgblack@eecs.umich.edu mantissa = 0; 4317430Sgblack@eecs.umich.edu exponent++; 4327430Sgblack@eecs.umich.edu } 4337430Sgblack@eecs.umich.edu 4347430Sgblack@eecs.umich.edu // Deal with overflow 4357430Sgblack@eecs.umich.edu if (fpscr.ahp) { 4367430Sgblack@eecs.umich.edu if (exponent >= 0x20) { 4377430Sgblack@eecs.umich.edu exponent = 0x1f; 4387430Sgblack@eecs.umich.edu mantissa = 0x3ff; 4397430Sgblack@eecs.umich.edu fpscr.ioc = 1; 4407430Sgblack@eecs.umich.edu // Supress inexact exception. 4417430Sgblack@eecs.umich.edu inexact = false; 4427430Sgblack@eecs.umich.edu } 4437430Sgblack@eecs.umich.edu } else { 4447430Sgblack@eecs.umich.edu if (exponent >= 0x1f) { 4457430Sgblack@eecs.umich.edu if ((mode == VfpRoundNearest) || 4467430Sgblack@eecs.umich.edu (mode == VfpRoundUpward && !neg) || 4477430Sgblack@eecs.umich.edu (mode == VfpRoundDown && neg)) { 4487430Sgblack@eecs.umich.edu // Overflow to infinity. 4497430Sgblack@eecs.umich.edu exponent = 0x1f; 4507430Sgblack@eecs.umich.edu mantissa = 0; 4517430Sgblack@eecs.umich.edu } else { 4527430Sgblack@eecs.umich.edu // Overflow to max normal. 4537430Sgblack@eecs.umich.edu exponent = 0x1e; 4547430Sgblack@eecs.umich.edu mantissa = 0x3ff; 4557430Sgblack@eecs.umich.edu } 4567430Sgblack@eecs.umich.edu fpscr.ofc = 1; 4577430Sgblack@eecs.umich.edu inexact = true; 4587430Sgblack@eecs.umich.edu } 4597430Sgblack@eecs.umich.edu } 4607430Sgblack@eecs.umich.edu } 4617430Sgblack@eecs.umich.edu 4627430Sgblack@eecs.umich.edu if (inexact) { 4637430Sgblack@eecs.umich.edu fpscr.ixc = 1; 4647430Sgblack@eecs.umich.edu } 4657430Sgblack@eecs.umich.edu } 4667430Sgblack@eecs.umich.edu // Reassemble and install the result. 4677430Sgblack@eecs.umich.edu uint32_t result = bits(mantissa, 9, 0); 4687430Sgblack@eecs.umich.edu replaceBits(result, 14, 10, exponent); 4697430Sgblack@eecs.umich.edu if (neg) 4707430Sgblack@eecs.umich.edu result |= (1 << 15); 4717430Sgblack@eecs.umich.edu if (top) 4727430Sgblack@eecs.umich.edu replaceBits(destBits, 31, 16, result); 4737430Sgblack@eecs.umich.edu else 4747430Sgblack@eecs.umich.edu replaceBits(destBits, 15, 0, result); 4757430Sgblack@eecs.umich.edu return bitsToFp(destBits, junk); 4767430Sgblack@eecs.umich.edu} 4777430Sgblack@eecs.umich.edu 4787430Sgblack@eecs.umich.edufloat 4797430Sgblack@eecs.umich.eduvcvtFpHFpS(FPSCR &fpscr, float op, bool top) 4807430Sgblack@eecs.umich.edu{ 4817430Sgblack@eecs.umich.edu float junk = 0.0; 4827430Sgblack@eecs.umich.edu uint32_t opBits = fpToBits(op); 4837430Sgblack@eecs.umich.edu // Extract the operand. 4847430Sgblack@eecs.umich.edu if (top) 4857430Sgblack@eecs.umich.edu opBits = bits(opBits, 31, 16); 4867430Sgblack@eecs.umich.edu else 4877430Sgblack@eecs.umich.edu opBits = bits(opBits, 15, 0); 4887430Sgblack@eecs.umich.edu // Extract the bitfields. 4897430Sgblack@eecs.umich.edu bool neg = bits(opBits, 15); 4907430Sgblack@eecs.umich.edu uint32_t exponent = bits(opBits, 14, 10); 4917430Sgblack@eecs.umich.edu uint32_t mantissa = bits(opBits, 9, 0); 4927430Sgblack@eecs.umich.edu // Do the conversion. 4937430Sgblack@eecs.umich.edu if (exponent == 0) { 4947430Sgblack@eecs.umich.edu if (mantissa != 0) { 4957430Sgblack@eecs.umich.edu // Normalize the value. 4967430Sgblack@eecs.umich.edu exponent = exponent + (127 - 15) + 1; 4977430Sgblack@eecs.umich.edu while (mantissa < (1 << 10)) { 4987430Sgblack@eecs.umich.edu mantissa = mantissa << 1; 4997430Sgblack@eecs.umich.edu exponent--; 5007430Sgblack@eecs.umich.edu } 5017430Sgblack@eecs.umich.edu } 5027430Sgblack@eecs.umich.edu mantissa = mantissa << (23 - 10); 5037430Sgblack@eecs.umich.edu } else if (exponent == 0x1f && !fpscr.ahp) { 5047430Sgblack@eecs.umich.edu // Infinities and nans. 5057430Sgblack@eecs.umich.edu exponent = 0xff; 5067430Sgblack@eecs.umich.edu if (mantissa != 0) { 5077430Sgblack@eecs.umich.edu // Nans. 5087430Sgblack@eecs.umich.edu mantissa = mantissa << (23 - 10); 5097430Sgblack@eecs.umich.edu if (bits(mantissa, 22) == 0) { 5107430Sgblack@eecs.umich.edu // Signalling nan. 5117430Sgblack@eecs.umich.edu fpscr.ioc = 1; 5127430Sgblack@eecs.umich.edu mantissa |= (1 << 22); 5137430Sgblack@eecs.umich.edu } 5147430Sgblack@eecs.umich.edu if (fpscr.dn) { 5157430Sgblack@eecs.umich.edu mantissa &= ~mask(22); 5167430Sgblack@eecs.umich.edu neg = false; 5177430Sgblack@eecs.umich.edu } 5187430Sgblack@eecs.umich.edu } 5197430Sgblack@eecs.umich.edu } else { 5207430Sgblack@eecs.umich.edu exponent = exponent + (127 - 15); 5217430Sgblack@eecs.umich.edu mantissa = mantissa << (23 - 10); 5227430Sgblack@eecs.umich.edu } 5237430Sgblack@eecs.umich.edu // Reassemble the result. 5247430Sgblack@eecs.umich.edu uint32_t result = bits(mantissa, 22, 0); 5257430Sgblack@eecs.umich.edu replaceBits(result, 30, 23, exponent); 5267430Sgblack@eecs.umich.edu if (neg) 5277430Sgblack@eecs.umich.edu result |= (1 << 31); 5287430Sgblack@eecs.umich.edu return bitsToFp(result, junk); 5297430Sgblack@eecs.umich.edu} 5307430Sgblack@eecs.umich.edu 5317430Sgblack@eecs.umich.eduuint64_t 5327430Sgblack@eecs.umich.eduvfpFpSToFixed(float val, bool isSigned, bool half, 5337430Sgblack@eecs.umich.edu uint8_t imm, bool rzero) 5347430Sgblack@eecs.umich.edu{ 5357430Sgblack@eecs.umich.edu int rmode = rzero ? FeRoundZero : fegetround(); 5367430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (rmode) : "m" (rmode)); 5377430Sgblack@eecs.umich.edu fesetround(FeRoundNearest); 5387430Sgblack@eecs.umich.edu val = val * powf(2.0, imm); 5397430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (val) : "m" (val)); 5407430Sgblack@eecs.umich.edu fesetround(rmode); 5417430Sgblack@eecs.umich.edu feclearexcept(FeAllExceptions); 5427430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (val) : "m" (val)); 5437430Sgblack@eecs.umich.edu float origVal = val; 5447430Sgblack@eecs.umich.edu val = rintf(val); 5457430Sgblack@eecs.umich.edu int fpType = std::fpclassify(val); 5467430Sgblack@eecs.umich.edu if (fpType == FP_SUBNORMAL || fpType == FP_NAN) { 5477430Sgblack@eecs.umich.edu if (fpType == FP_NAN) { 5487430Sgblack@eecs.umich.edu feraiseexcept(FeInvalid); 5497430Sgblack@eecs.umich.edu } 5507430Sgblack@eecs.umich.edu val = 0.0; 5517430Sgblack@eecs.umich.edu } else if (origVal != val) { 5527430Sgblack@eecs.umich.edu switch (rmode) { 5537430Sgblack@eecs.umich.edu case FeRoundNearest: 5547430Sgblack@eecs.umich.edu if (origVal - val > 0.5) 5557430Sgblack@eecs.umich.edu val += 1.0; 5567430Sgblack@eecs.umich.edu else if (val - origVal > 0.5) 5577430Sgblack@eecs.umich.edu val -= 1.0; 5587430Sgblack@eecs.umich.edu break; 5597430Sgblack@eecs.umich.edu case FeRoundDown: 5607430Sgblack@eecs.umich.edu if (origVal < val) 5617430Sgblack@eecs.umich.edu val -= 1.0; 5627430Sgblack@eecs.umich.edu break; 5637430Sgblack@eecs.umich.edu case FeRoundUpward: 5647430Sgblack@eecs.umich.edu if (origVal > val) 5657430Sgblack@eecs.umich.edu val += 1.0; 5667430Sgblack@eecs.umich.edu break; 5677430Sgblack@eecs.umich.edu } 5687430Sgblack@eecs.umich.edu feraiseexcept(FeInexact); 5697430Sgblack@eecs.umich.edu } 5707430Sgblack@eecs.umich.edu 5717430Sgblack@eecs.umich.edu if (isSigned) { 5727430Sgblack@eecs.umich.edu if (half) { 5737430Sgblack@eecs.umich.edu if ((double)val < (int16_t)(1 << 15)) { 5747430Sgblack@eecs.umich.edu feraiseexcept(FeInvalid); 5757430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 5767430Sgblack@eecs.umich.edu return (int16_t)(1 << 15); 5777430Sgblack@eecs.umich.edu } 5787430Sgblack@eecs.umich.edu if ((double)val > (int16_t)mask(15)) { 5797430Sgblack@eecs.umich.edu feraiseexcept(FeInvalid); 5807430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 5817430Sgblack@eecs.umich.edu return (int16_t)mask(15); 5827430Sgblack@eecs.umich.edu } 5837430Sgblack@eecs.umich.edu return (int16_t)val; 5847430Sgblack@eecs.umich.edu } else { 5857430Sgblack@eecs.umich.edu if ((double)val < (int32_t)(1 << 31)) { 5867430Sgblack@eecs.umich.edu feraiseexcept(FeInvalid); 5877430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 5887430Sgblack@eecs.umich.edu return (int32_t)(1 << 31); 5897430Sgblack@eecs.umich.edu } 5907430Sgblack@eecs.umich.edu if ((double)val > (int32_t)mask(31)) { 5917430Sgblack@eecs.umich.edu feraiseexcept(FeInvalid); 5927430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 5937430Sgblack@eecs.umich.edu return (int32_t)mask(31); 5947430Sgblack@eecs.umich.edu } 5957430Sgblack@eecs.umich.edu return (int32_t)val; 5967430Sgblack@eecs.umich.edu } 5977430Sgblack@eecs.umich.edu } else { 5987430Sgblack@eecs.umich.edu if (half) { 5997430Sgblack@eecs.umich.edu if ((double)val < 0) { 6007430Sgblack@eecs.umich.edu feraiseexcept(FeInvalid); 6017430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 6027430Sgblack@eecs.umich.edu return 0; 6037430Sgblack@eecs.umich.edu } 6047430Sgblack@eecs.umich.edu if ((double)val > (mask(16))) { 6057430Sgblack@eecs.umich.edu feraiseexcept(FeInvalid); 6067430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 6077430Sgblack@eecs.umich.edu return mask(16); 6087430Sgblack@eecs.umich.edu } 6097430Sgblack@eecs.umich.edu return (uint16_t)val; 6107430Sgblack@eecs.umich.edu } else { 6117430Sgblack@eecs.umich.edu if ((double)val < 0) { 6127430Sgblack@eecs.umich.edu feraiseexcept(FeInvalid); 6137430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 6147430Sgblack@eecs.umich.edu return 0; 6157430Sgblack@eecs.umich.edu } 6167430Sgblack@eecs.umich.edu if ((double)val > (mask(32))) { 6177430Sgblack@eecs.umich.edu feraiseexcept(FeInvalid); 6187430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 6197430Sgblack@eecs.umich.edu return mask(32); 6207430Sgblack@eecs.umich.edu } 6217430Sgblack@eecs.umich.edu return (uint32_t)val; 6227430Sgblack@eecs.umich.edu } 6237430Sgblack@eecs.umich.edu } 6247430Sgblack@eecs.umich.edu} 6257430Sgblack@eecs.umich.edu 6267430Sgblack@eecs.umich.edufloat 6277430Sgblack@eecs.umich.eduvfpUFixedToFpS(FPSCR fpscr, uint32_t val, bool half, uint8_t imm) 6287430Sgblack@eecs.umich.edu{ 6297430Sgblack@eecs.umich.edu fesetround(FeRoundNearest); 6307430Sgblack@eecs.umich.edu if (half) 6317430Sgblack@eecs.umich.edu val = (uint16_t)val; 6327430Sgblack@eecs.umich.edu float scale = powf(2.0, imm); 6337430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 6347430Sgblack@eecs.umich.edu feclearexcept(FeAllExceptions); 6357430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 6367430Sgblack@eecs.umich.edu return fixDivDest(fpscr, val / scale, (float)val, scale); 6377430Sgblack@eecs.umich.edu} 6387430Sgblack@eecs.umich.edu 6397430Sgblack@eecs.umich.edufloat 6407430Sgblack@eecs.umich.eduvfpSFixedToFpS(FPSCR fpscr, int32_t val, bool half, uint8_t imm) 6417430Sgblack@eecs.umich.edu{ 6427430Sgblack@eecs.umich.edu fesetround(FeRoundNearest); 6437430Sgblack@eecs.umich.edu if (half) 6447430Sgblack@eecs.umich.edu val = sext<16>(val & mask(16)); 6457430Sgblack@eecs.umich.edu float scale = powf(2.0, imm); 6467430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 6477430Sgblack@eecs.umich.edu feclearexcept(FeAllExceptions); 6487430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 6497430Sgblack@eecs.umich.edu return fixDivDest(fpscr, val / scale, (float)val, scale); 6507430Sgblack@eecs.umich.edu} 6517430Sgblack@eecs.umich.edu 6527430Sgblack@eecs.umich.eduuint64_t 6537430Sgblack@eecs.umich.eduvfpFpDToFixed(double val, bool isSigned, bool half, 6547430Sgblack@eecs.umich.edu uint8_t imm, bool rzero) 6557430Sgblack@eecs.umich.edu{ 6567430Sgblack@eecs.umich.edu int rmode = rzero ? FeRoundZero : fegetround(); 6577430Sgblack@eecs.umich.edu fesetround(FeRoundNearest); 6587430Sgblack@eecs.umich.edu val = val * pow(2.0, imm); 6597430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (val) : "m" (val)); 6607430Sgblack@eecs.umich.edu fesetround(rmode); 6617430Sgblack@eecs.umich.edu feclearexcept(FeAllExceptions); 6627430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (val) : "m" (val)); 6637430Sgblack@eecs.umich.edu double origVal = val; 6647430Sgblack@eecs.umich.edu val = rint(val); 6657430Sgblack@eecs.umich.edu int fpType = std::fpclassify(val); 6667430Sgblack@eecs.umich.edu if (fpType == FP_SUBNORMAL || fpType == FP_NAN) { 6677430Sgblack@eecs.umich.edu if (fpType == FP_NAN) { 6687430Sgblack@eecs.umich.edu feraiseexcept(FeInvalid); 6697430Sgblack@eecs.umich.edu } 6707430Sgblack@eecs.umich.edu val = 0.0; 6717430Sgblack@eecs.umich.edu } else if (origVal != val) { 6727430Sgblack@eecs.umich.edu switch (rmode) { 6737430Sgblack@eecs.umich.edu case FeRoundNearest: 6747430Sgblack@eecs.umich.edu if (origVal - val > 0.5) 6757430Sgblack@eecs.umich.edu val += 1.0; 6767430Sgblack@eecs.umich.edu else if (val - origVal > 0.5) 6777430Sgblack@eecs.umich.edu val -= 1.0; 6787430Sgblack@eecs.umich.edu break; 6797430Sgblack@eecs.umich.edu case FeRoundDown: 6807430Sgblack@eecs.umich.edu if (origVal < val) 6817430Sgblack@eecs.umich.edu val -= 1.0; 6827430Sgblack@eecs.umich.edu break; 6837430Sgblack@eecs.umich.edu case FeRoundUpward: 6847430Sgblack@eecs.umich.edu if (origVal > val) 6857430Sgblack@eecs.umich.edu val += 1.0; 6867430Sgblack@eecs.umich.edu break; 6877430Sgblack@eecs.umich.edu } 6887430Sgblack@eecs.umich.edu feraiseexcept(FeInexact); 6897430Sgblack@eecs.umich.edu } 6907430Sgblack@eecs.umich.edu if (isSigned) { 6917430Sgblack@eecs.umich.edu if (half) { 6927430Sgblack@eecs.umich.edu if (val < (int16_t)(1 << 15)) { 6937430Sgblack@eecs.umich.edu feraiseexcept(FeInvalid); 6947430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 6957430Sgblack@eecs.umich.edu return (int16_t)(1 << 15); 6967430Sgblack@eecs.umich.edu } 6977430Sgblack@eecs.umich.edu if (val > (int16_t)mask(15)) { 6987430Sgblack@eecs.umich.edu feraiseexcept(FeInvalid); 6997430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 7007430Sgblack@eecs.umich.edu return (int16_t)mask(15); 7017430Sgblack@eecs.umich.edu } 7027430Sgblack@eecs.umich.edu return (int16_t)val; 7037430Sgblack@eecs.umich.edu } else { 7047430Sgblack@eecs.umich.edu if (val < (int32_t)(1 << 31)) { 7057430Sgblack@eecs.umich.edu feraiseexcept(FeInvalid); 7067430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 7077430Sgblack@eecs.umich.edu return (int32_t)(1 << 31); 7087430Sgblack@eecs.umich.edu } 7097430Sgblack@eecs.umich.edu if (val > (int32_t)mask(31)) { 7107430Sgblack@eecs.umich.edu feraiseexcept(FeInvalid); 7117430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 7127430Sgblack@eecs.umich.edu return (int32_t)mask(31); 7137430Sgblack@eecs.umich.edu } 7147430Sgblack@eecs.umich.edu return (int32_t)val; 7157430Sgblack@eecs.umich.edu } 7167430Sgblack@eecs.umich.edu } else { 7177430Sgblack@eecs.umich.edu if (half) { 7187430Sgblack@eecs.umich.edu if (val < 0) { 7197430Sgblack@eecs.umich.edu feraiseexcept(FeInvalid); 7207430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 7217430Sgblack@eecs.umich.edu return 0; 7227430Sgblack@eecs.umich.edu } 7237430Sgblack@eecs.umich.edu if (val > mask(16)) { 7247430Sgblack@eecs.umich.edu feraiseexcept(FeInvalid); 7257430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 7267430Sgblack@eecs.umich.edu return mask(16); 7277430Sgblack@eecs.umich.edu } 7287430Sgblack@eecs.umich.edu return (uint16_t)val; 7297430Sgblack@eecs.umich.edu } else { 7307430Sgblack@eecs.umich.edu if (val < 0) { 7317430Sgblack@eecs.umich.edu feraiseexcept(FeInvalid); 7327430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 7337430Sgblack@eecs.umich.edu return 0; 7347430Sgblack@eecs.umich.edu } 7357430Sgblack@eecs.umich.edu if (val > mask(32)) { 7367430Sgblack@eecs.umich.edu feraiseexcept(FeInvalid); 7377430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 7387430Sgblack@eecs.umich.edu return mask(32); 7397430Sgblack@eecs.umich.edu } 7407430Sgblack@eecs.umich.edu return (uint32_t)val; 7417430Sgblack@eecs.umich.edu } 7427430Sgblack@eecs.umich.edu } 7437430Sgblack@eecs.umich.edu} 7447430Sgblack@eecs.umich.edu 7457430Sgblack@eecs.umich.edudouble 7467430Sgblack@eecs.umich.eduvfpUFixedToFpD(FPSCR fpscr, uint32_t val, bool half, uint8_t imm) 7477430Sgblack@eecs.umich.edu{ 7487430Sgblack@eecs.umich.edu fesetround(FeRoundNearest); 7497430Sgblack@eecs.umich.edu if (half) 7507430Sgblack@eecs.umich.edu val = (uint16_t)val; 7517430Sgblack@eecs.umich.edu double scale = pow(2.0, imm); 7527430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 7537430Sgblack@eecs.umich.edu feclearexcept(FeAllExceptions); 7547430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 7557430Sgblack@eecs.umich.edu return fixDivDest(fpscr, val / scale, (double)val, scale); 7567430Sgblack@eecs.umich.edu} 7577430Sgblack@eecs.umich.edu 7587430Sgblack@eecs.umich.edudouble 7597430Sgblack@eecs.umich.eduvfpSFixedToFpD(FPSCR fpscr, int32_t val, bool half, uint8_t imm) 7607430Sgblack@eecs.umich.edu{ 7617430Sgblack@eecs.umich.edu fesetround(FeRoundNearest); 7627430Sgblack@eecs.umich.edu if (half) 7637430Sgblack@eecs.umich.edu val = sext<16>(val & mask(16)); 7647430Sgblack@eecs.umich.edu double scale = pow(2.0, imm); 7657430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 7667430Sgblack@eecs.umich.edu feclearexcept(FeAllExceptions); 7677430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 7687430Sgblack@eecs.umich.edu return fixDivDest(fpscr, val / scale, (double)val, scale); 7697430Sgblack@eecs.umich.edu} 7707430Sgblack@eecs.umich.edu 7717430Sgblack@eecs.umich.edutemplate <class fpType> 7727430Sgblack@eecs.umich.edufpType 7737430Sgblack@eecs.umich.eduFpOp::binaryOp(FPSCR &fpscr, fpType op1, fpType op2, 7747430Sgblack@eecs.umich.edu fpType (*func)(fpType, fpType), 7757430Sgblack@eecs.umich.edu bool flush, uint32_t rMode) const 7767430Sgblack@eecs.umich.edu{ 7777430Sgblack@eecs.umich.edu const bool single = (sizeof(fpType) == sizeof(float)); 7787430Sgblack@eecs.umich.edu fpType junk = 0.0; 7797430Sgblack@eecs.umich.edu 7807430Sgblack@eecs.umich.edu if (flush && flushToZero(op1, op2)) 7817430Sgblack@eecs.umich.edu fpscr.idc = 1; 7827430Sgblack@eecs.umich.edu VfpSavedState state = prepFpState(rMode); 7837430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2), "=m" (state) 7847430Sgblack@eecs.umich.edu : "m" (op1), "m" (op2), "m" (state)); 7857430Sgblack@eecs.umich.edu fpType dest = func(op1, op2); 7867430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (dest) : "m" (dest)); 7877430Sgblack@eecs.umich.edu 7887430Sgblack@eecs.umich.edu int fpClass = std::fpclassify(dest); 7897430Sgblack@eecs.umich.edu // Get NAN behavior right. This varies between x86 and ARM. 7907430Sgblack@eecs.umich.edu if (fpClass == FP_NAN) { 7917430Sgblack@eecs.umich.edu const bool single = (sizeof(fpType) == sizeof(float)); 7927430Sgblack@eecs.umich.edu const uint64_t qnan = 7937430Sgblack@eecs.umich.edu single ? 0x7fc00000 : ULL(0x7ff8000000000000); 7947430Sgblack@eecs.umich.edu const bool nan1 = std::isnan(op1); 7957430Sgblack@eecs.umich.edu const bool nan2 = std::isnan(op2); 7967430Sgblack@eecs.umich.edu const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan); 7977430Sgblack@eecs.umich.edu const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan); 7987430Sgblack@eecs.umich.edu if ((!nan1 && !nan2) || (fpscr.dn == 1)) { 7997430Sgblack@eecs.umich.edu dest = bitsToFp(qnan, junk); 8007430Sgblack@eecs.umich.edu } else if (signal1) { 8017430Sgblack@eecs.umich.edu dest = bitsToFp(fpToBits(op1) | qnan, junk); 8027430Sgblack@eecs.umich.edu } else if (signal2) { 8037430Sgblack@eecs.umich.edu dest = bitsToFp(fpToBits(op2) | qnan, junk); 8047430Sgblack@eecs.umich.edu } else if (nan1) { 8057430Sgblack@eecs.umich.edu dest = op1; 8067430Sgblack@eecs.umich.edu } else if (nan2) { 8077430Sgblack@eecs.umich.edu dest = op2; 8087430Sgblack@eecs.umich.edu } 8097430Sgblack@eecs.umich.edu } else if (flush && flushToZero(dest)) { 8107430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 8117430Sgblack@eecs.umich.edu } else if (( 8127430Sgblack@eecs.umich.edu (single && (dest == bitsToFp(0x00800000, junk) || 8137430Sgblack@eecs.umich.edu dest == bitsToFp(0x80800000, junk))) || 8147430Sgblack@eecs.umich.edu (!single && 8157430Sgblack@eecs.umich.edu (dest == bitsToFp(ULL(0x0010000000000000), junk) || 8167430Sgblack@eecs.umich.edu dest == bitsToFp(ULL(0x8010000000000000), junk))) 8177430Sgblack@eecs.umich.edu ) && rMode != VfpRoundZero) { 8187430Sgblack@eecs.umich.edu /* 8197430Sgblack@eecs.umich.edu * Correct for the fact that underflow is detected -before- rounding 8207430Sgblack@eecs.umich.edu * in ARM and -after- rounding in x86. 8217430Sgblack@eecs.umich.edu */ 8227430Sgblack@eecs.umich.edu fesetround(FeRoundZero); 8237430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2) 8247430Sgblack@eecs.umich.edu : "m" (op1), "m" (op2)); 8257430Sgblack@eecs.umich.edu fpType temp = func(op1, op2); 8267430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (temp) : "m" (temp)); 8277430Sgblack@eecs.umich.edu if (flush && flushToZero(temp)) { 8287430Sgblack@eecs.umich.edu dest = temp; 8297430Sgblack@eecs.umich.edu } 8307430Sgblack@eecs.umich.edu } 8317430Sgblack@eecs.umich.edu finishVfp(fpscr, state); 8327430Sgblack@eecs.umich.edu return dest; 8337430Sgblack@eecs.umich.edu} 8347430Sgblack@eecs.umich.edu 8357430Sgblack@eecs.umich.edutemplate 8367430Sgblack@eecs.umich.edufloat FpOp::binaryOp(FPSCR &fpscr, float op1, float op2, 8377430Sgblack@eecs.umich.edu float (*func)(float, float), 8387430Sgblack@eecs.umich.edu bool flush, uint32_t rMode) const; 8397430Sgblack@eecs.umich.edutemplate 8407430Sgblack@eecs.umich.edudouble FpOp::binaryOp(FPSCR &fpscr, double op1, double op2, 8417430Sgblack@eecs.umich.edu double (*func)(double, double), 8427430Sgblack@eecs.umich.edu bool flush, uint32_t rMode) const; 8437430Sgblack@eecs.umich.edu 8447430Sgblack@eecs.umich.edutemplate <class fpType> 8457430Sgblack@eecs.umich.edufpType 8467430Sgblack@eecs.umich.eduFpOp::unaryOp(FPSCR &fpscr, fpType op1, fpType (*func)(fpType), 8477430Sgblack@eecs.umich.edu bool flush, uint32_t rMode) const 8487430Sgblack@eecs.umich.edu{ 8497430Sgblack@eecs.umich.edu const bool single = (sizeof(fpType) == sizeof(float)); 8507430Sgblack@eecs.umich.edu fpType junk = 0.0; 8517430Sgblack@eecs.umich.edu 8527430Sgblack@eecs.umich.edu if (flush && flushToZero(op1)) 8537430Sgblack@eecs.umich.edu fpscr.idc = 1; 8547430Sgblack@eecs.umich.edu VfpSavedState state = prepFpState(rMode); 8557430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (op1), "=m" (state) 8567430Sgblack@eecs.umich.edu : "m" (op1), "m" (state)); 8577430Sgblack@eecs.umich.edu fpType dest = func(op1); 8587430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (dest) : "m" (dest)); 8597430Sgblack@eecs.umich.edu 8607430Sgblack@eecs.umich.edu int fpClass = std::fpclassify(dest); 8617430Sgblack@eecs.umich.edu // Get NAN behavior right. This varies between x86 and ARM. 8627430Sgblack@eecs.umich.edu if (fpClass == FP_NAN) { 8637430Sgblack@eecs.umich.edu const bool single = (sizeof(fpType) == sizeof(float)); 8647430Sgblack@eecs.umich.edu const uint64_t qnan = 8657430Sgblack@eecs.umich.edu single ? 0x7fc00000 : ULL(0x7ff8000000000000); 8667430Sgblack@eecs.umich.edu const bool nan = std::isnan(op1); 8677430Sgblack@eecs.umich.edu if (!nan || fpscr.dn == 1) { 8687430Sgblack@eecs.umich.edu dest = bitsToFp(qnan, junk); 8697430Sgblack@eecs.umich.edu } else if (nan) { 8707430Sgblack@eecs.umich.edu dest = bitsToFp(fpToBits(op1) | qnan, junk); 8717430Sgblack@eecs.umich.edu } 8727430Sgblack@eecs.umich.edu } else if (flush && flushToZero(dest)) { 8737430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 8747430Sgblack@eecs.umich.edu } else if (( 8757430Sgblack@eecs.umich.edu (single && (dest == bitsToFp(0x00800000, junk) || 8767430Sgblack@eecs.umich.edu dest == bitsToFp(0x80800000, junk))) || 8777430Sgblack@eecs.umich.edu (!single && 8787430Sgblack@eecs.umich.edu (dest == bitsToFp(ULL(0x0010000000000000), junk) || 8797430Sgblack@eecs.umich.edu dest == bitsToFp(ULL(0x8010000000000000), junk))) 8807430Sgblack@eecs.umich.edu ) && rMode != VfpRoundZero) { 8817430Sgblack@eecs.umich.edu /* 8827430Sgblack@eecs.umich.edu * Correct for the fact that underflow is detected -before- rounding 8837430Sgblack@eecs.umich.edu * in ARM and -after- rounding in x86. 8847430Sgblack@eecs.umich.edu */ 8857430Sgblack@eecs.umich.edu fesetround(FeRoundZero); 8867430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (op1) : "m" (op1)); 8877430Sgblack@eecs.umich.edu fpType temp = func(op1); 8887430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (temp) : "m" (temp)); 8897430Sgblack@eecs.umich.edu if (flush && flushToZero(temp)) { 8907430Sgblack@eecs.umich.edu dest = temp; 8917430Sgblack@eecs.umich.edu } 8927430Sgblack@eecs.umich.edu } 8937430Sgblack@eecs.umich.edu finishVfp(fpscr, state); 8947430Sgblack@eecs.umich.edu return dest; 8957430Sgblack@eecs.umich.edu} 8967430Sgblack@eecs.umich.edu 8977430Sgblack@eecs.umich.edutemplate 8987430Sgblack@eecs.umich.edufloat FpOp::unaryOp(FPSCR &fpscr, float op1, float (*func)(float), 8997430Sgblack@eecs.umich.edu bool flush, uint32_t rMode) const; 9007430Sgblack@eecs.umich.edutemplate 9017430Sgblack@eecs.umich.edudouble FpOp::unaryOp(FPSCR &fpscr, double op1, double (*func)(double), 9027430Sgblack@eecs.umich.edu bool flush, uint32_t rMode) const; 9037430Sgblack@eecs.umich.edu 9047430Sgblack@eecs.umich.eduIntRegIndex 9057430Sgblack@eecs.umich.eduVfpMacroOp::addStride(IntRegIndex idx, unsigned stride) 9067430Sgblack@eecs.umich.edu{ 9077430Sgblack@eecs.umich.edu if (wide) { 9087430Sgblack@eecs.umich.edu stride *= 2; 9097430Sgblack@eecs.umich.edu } 9107430Sgblack@eecs.umich.edu unsigned offset = idx % 8; 9117430Sgblack@eecs.umich.edu idx = (IntRegIndex)(idx - offset); 9127430Sgblack@eecs.umich.edu offset += stride; 9137430Sgblack@eecs.umich.edu idx = (IntRegIndex)(idx + (offset % 8)); 9147430Sgblack@eecs.umich.edu return idx; 9157430Sgblack@eecs.umich.edu} 9167430Sgblack@eecs.umich.edu 9177430Sgblack@eecs.umich.eduvoid 9187430Sgblack@eecs.umich.eduVfpMacroOp::nextIdxs(IntRegIndex &dest, IntRegIndex &op1, IntRegIndex &op2) 9197430Sgblack@eecs.umich.edu{ 9207430Sgblack@eecs.umich.edu unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2; 9217430Sgblack@eecs.umich.edu assert(!inScalarBank(dest)); 9227430Sgblack@eecs.umich.edu dest = addStride(dest, stride); 9237430Sgblack@eecs.umich.edu op1 = addStride(op1, stride); 9247430Sgblack@eecs.umich.edu if (!inScalarBank(op2)) { 9257430Sgblack@eecs.umich.edu op2 = addStride(op2, stride); 9267430Sgblack@eecs.umich.edu } 9277430Sgblack@eecs.umich.edu} 9287430Sgblack@eecs.umich.edu 9297430Sgblack@eecs.umich.eduvoid 9307430Sgblack@eecs.umich.eduVfpMacroOp::nextIdxs(IntRegIndex &dest, IntRegIndex &op1) 9317430Sgblack@eecs.umich.edu{ 9327430Sgblack@eecs.umich.edu unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2; 9337430Sgblack@eecs.umich.edu assert(!inScalarBank(dest)); 9347430Sgblack@eecs.umich.edu dest = addStride(dest, stride); 9357430Sgblack@eecs.umich.edu if (!inScalarBank(op1)) { 9367430Sgblack@eecs.umich.edu op1 = addStride(op1, stride); 9377430Sgblack@eecs.umich.edu } 9387430Sgblack@eecs.umich.edu} 9397430Sgblack@eecs.umich.edu 9407430Sgblack@eecs.umich.eduvoid 9417430Sgblack@eecs.umich.eduVfpMacroOp::nextIdxs(IntRegIndex &dest) 9427430Sgblack@eecs.umich.edu{ 9437430Sgblack@eecs.umich.edu unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2; 9447430Sgblack@eecs.umich.edu assert(!inScalarBank(dest)); 9457430Sgblack@eecs.umich.edu dest = addStride(dest, stride); 9467430Sgblack@eecs.umich.edu} 9477430Sgblack@eecs.umich.edu 9487430Sgblack@eecs.umich.edu} 949