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