authorgravatar for fhossein@qti.qualcomm.comFateme Hosseini <fhossein@qti.qualcomm.com> 2026-10-14 12:11:04-07:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-10-21 06:08:50+02:00
log3c08167cb766f8d00fc5a219e382abba12e57ede
treed9ad2cbb393e9d0eb960f0a15e2d1cf6f3adca09
parentc8bb44618a9c3c7bfff4a9f672a451fdeda1bb02
signature Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

compiler-rt: add hexagon v79 QFloat HVX runtime conversion funcs

Add four assembly files for half-float to integer conversions using QFloat (qf16) on Hexagon V79. Each function provides IEEE round-to-nearest-even or fast round-half-away-from-zero conversion for signed and unsigned 8-bit and 16-bit integer destinations. V79 lacks direct half-float to integer conversion. V75 and below have native IEEE vcvt instructions, while V81 and newer have dedicated hardware support. Co-authored-by: Sumanth Gundapaneni <sgundapa@quicinc.com>

1 files changed, 588 insertions(+), 0 deletions(-)

lib/compiler_rt/hexagon.zig+588
...@@ -1759,6 +1759,584 @@ fn __hexagon_sqrtdf2() align(32) callconv(.naked) noreturn {...@@ -1759,6 +1759,584 @@ fn __hexagon_sqrtdf2() align(32) callconv(.naked) noreturn {
1759 );1759 );
1760}1760}
17611761
1762fn __qf_convert_hf_to_b_rne() align(32) callconv(.naked) noreturn {
1763 asm volatile (
1764 \\ //V0 and V1 have input
1765 \\ //First rnd, replaces V0.h=V0.hf
1766 \\ //Convert input vector to half word
1767 \\ {
1768 \\ R1=#0x3800 //+.5
1769 \\ R2=#0xB800 //-.5
1770 \\ V7.h=V0.hf //Convert and truncate half precision
1771 \\ }
1772 \\ {
1773 \\ V6=#0
1774 \\ R3=#0x00010001
1775 \\ R4=#0x37FF
1776 \\ }
1777 \\ {
1778 \\ V10=vsplat(R3)
1779 \\ V12.h=vsplat(R4)
1780 \\ V15.hf=V7.h //Convert truncated back to hf
1781 \\ }
1782 \\ {
1783 \\ V23.h=vsplat(R1) //V3 = +.5
1784 \\ V24.h=vsplat(R2) //V4 = -.5
1785 \\ V5.qf16=vsub(V0.hf,V15.hf) //Sub truncated value from original value
1786 \\ R0=#0x7FFF //Mask off sign bit of IEEE-754
1787 \\ }
1788 \\ {
1789 \\ Q0=vcmp.gt(V0.hf,V6.hf) // hf value is pos (hf > 0)
1790 \\ V5.hf=V5.qf16 //V5 is the fractional of original value
1791 \\ V22.h=vsplat(R0) //Splat R0 to Mask off sign bit
1792 \\ }
1793 \\ {
1794 \\ V15=vmux(Q0,V23,V24) //If input is pos value, use +.5. If neg value, use -.5 (Q in prev packet)
1795 \\ V2=vand(V22,V5) //V2=abs(frac)
1796 \\ V13=vand(V0,V22) //V13 = abs(input)
1797 \\ }
1798 \\ {
1799 \\ Q1=vcmp.eq(V2.h,V23.h) // frac == .5 (0x3800)
1800 \\ V15=vsplat(R3) //V1=1
1801 \\ V4.qf16=vadd(V0.hf,V15.hf) // Add +.5 or -.5 to V0
1802 \\ Q3=vcmp.eq(V13.h,V12.h) //Q3 = if(input == abs(.4998))
1803 \\ }
1804 \\ {
1805 \\ V11=vand(V7,V10) //Mask off all the lower bits
1806 \\ V3.h = vadd(V15.h,V15.h) //V3 is 2
1807 \\ }
1808 \\ {
1809 \\ Q2=vcmp.eq(V11.h,V10.h) //Is input value odd if halfword equals 0x1
1810 \\ V4.hf=V4.qf16 //hf value after add/sub .5
1811 \\ }
1812 \\ {
1813 \\ Q1=and(Q1,!Q2) //Is frac .5 and input is even
1814 \\ if (Q0) V15.h-=V3.h //If input is pos, sub 2 so V1 is -1
1815 \\ V4=vmux(Q3,V6,V4)
1816 \\ }
1817 \\ {
1818 \\ V4.h=V4.hf //Truncate, V4 has converted value
1819 \\ V15=vmux(Q1,V15,V6) //If frac == .5 and input is even, use +1/-1. Else 0
1820 \\ }
1821 \\ {
1822 \\ //Second rnd, replaces V1.h=V1.hf //Convert input vector to half word
1823 \\ V7.h=V1.hf //Convert and truncate half precision
1824 \\ }
1825 \\ {
1826 \\ V16.h = vadd(V4.h,V15.h) //Add +1/-1 or 0. V4 has the result
1827 \\ V1.hf=V7.h //Convert truncated back to hf
1828 \\ }
1829 \\ {
1830 \\ V5.qf16=vsub(V0.hf,V1.hf) //Sub truncated value from original value
1831 \\ R0=#0x7FFF //Mask off sign bit of IEEE-754
1832 \\ }
1833 \\ {
1834 \\ Q0=vcmp.gt(V0.hf,V6.hf) // hf value is pos (hf > 0)
1835 \\ V5.hf=V5.qf16 //V5 is the fractional of original value
1836 \\ }
1837 \\ {
1838 \\ V1=vmux(Q0,V23,V24) //If input is pos value, use +.5. If neg value, use -.5 (Q in prev packet)
1839 \\ V2=vand(V22,V5) //V2=abs(frac)
1840 \\ V13=vand(V0,V22) //V13 = abs(input)
1841 \\ }
1842 \\ {
1843 \\ Q1=vcmp.eq(V2.h,V23.h) // frac == .5 (0x3800)
1844 \\ V1=vsplat(R3) //V1=1
1845 \\ V4.qf16=vadd(V0.hf,V1.hf) // Add +.5 or -.5 to V0
1846 \\ Q3=vcmp.eq(V13.h,V12.h) //Q3 = if(input == abs(.4998))
1847 \\ }
1848 \\ {
1849 \\ V11=vand(V7,V10) //Mask off all the lower bits
1850 \\ V3.h = vadd(V1.h,V1.h) //V3 is 2
1851 \\ }
1852 \\ {
1853 \\ Q2=vcmp.eq(V11.h,V10.h) //Is input value odd if halfword equals 0x1
1854 \\ V4.hf=V4.qf16 //hf value after add/sub .5
1855 \\ }
1856 \\ {
1857 \\ Q1=and(Q1,!Q2) //Is frac .5 and input is even
1858 \\ if (Q0) V1.h-=V3.h //If input is pos, sub 2 so V1 is -1
1859 \\ V4=vmux(Q3,V6,V4)
1860 \\ }
1861 \\ {
1862 \\ V4.h=V4.hf //Truncate, V4 has converted value
1863 \\ V1=vmux(Q1,V1,V6) //If frac == .5 and input is even, use +1/-1. Else 0
1864 \\ }
1865 \\ {
1866 \\ V17.h = vadd(V4.h,V1.h) //Add +1/-1 or 0. V4 has the result
1867 \\ }
1868 \\ {
1869 \\ V0.b = vpack(V17.h,V16.h):sat
1870 \\ }
1871 \\ {
1872 \\ V0.h=vshuff(V0.h)
1873 \\ jumpr R31
1874 \\ }
1875 );
1876}
1877
1878fn __qf_convert_hf_to_h_rne() align(32) callconv(.naked) noreturn {
1879 asm volatile (
1880 \\ {
1881 \\ R1=#0x3800 //+.5
1882 \\ R2=#0xB800 //-.5
1883 \\ V7.h=V0.hf //Convert and truncate half precision
1884 \\ }
1885 \\ {
1886 \\ V6=#0
1887 \\ R3=#0x00010001
1888 \\ R4=#0x37FF
1889 \\ }
1890 \\ {
1891 \\ V10=vsplat(R3)
1892 \\ V12.h=vsplat(R4)
1893 \\ V1.hf=V7.h //Convert truncated back to hf
1894 \\ }
1895 \\ {
1896 \\ V3.h=vsplat(R1) //V3 = +.5
1897 \\ V4.h=vsplat(R2) //V4 = -.5
1898 \\ V5.qf16=vsub(V0.hf,V1.hf) //Sub truncated value from original value
1899 \\ R0=#0x7FFF //Mask off sign bit of IEEE-754
1900 \\ }
1901 \\ {
1902 \\ Q0=vcmp.gt(V0.hf,V6.hf) // hf value is pos (hf > 0)
1903 \\ V5.hf=V5.qf16 //V5 is the fractional of original value
1904 \\ V2.h=vsplat(R0) //Splat R0 to Mask off sign bit
1905 \\ }
1906 \\ {
1907 \\ V1=vmux(Q0,V3,V4) //If input is pos value, use +.5. If neg value, use -.5 (Q in prev packet)
1908 \\ V2=vand(V2,V5) //V2=abs(frac)
1909 \\ V13=vand(V0,V2) //V13 = abs(input)
1910 \\ }
1911 \\ {
1912 \\ Q1=vcmp.eq(V2.h,V3.h) // frac == .5 (0x3800)
1913 \\ V1=vsplat(R3) //V1=1
1914 \\ V4.qf16=vadd(V0.hf,V1.hf) // Add +.5 or -.5 to V0
1915 \\ Q3=vcmp.eq(V13.h,V12.h) //Q3 = if(input == abs(.4998))
1916 \\ }
1917 \\ {
1918 \\ V11=vand(V7,V10) //Mask off all the lower bits
1919 \\ V3.h = vadd(V1.h,V1.h) //V3 is 2
1920 \\ }
1921 \\ {
1922 \\ Q2=vcmp.eq(V11.h,V10.h) //Is input value odd if halfword equals 0x1
1923 \\ V4.hf=V4.qf16 //hf value after add/sub .5
1924 \\ }
1925 \\ {
1926 \\ Q1=and(Q1,!Q2) //Is frac .5 and input is even
1927 \\ if (Q0) V1.h-=V3.h //If input is pos, sub 2 so V1 is -1
1928 \\ V4=vmux(Q3,V6,V4)
1929 \\ }
1930 \\ {
1931 \\ V4.h=V4.hf //Truncate, V4 has converted value
1932 \\ V1=vmux(Q1,V1,V6) //If frac == .5 and input is even, use +1/-1. Else 0
1933 \\ }
1934 \\ {
1935 \\ V0.h = vadd(V4.h,V1.h) //Add +1/-1 or 0. V4 has the result
1936 \\ jumpr LR
1937 \\ }
1938 );
1939}
1940
1941fn __qf_convert_hf_to_ub_rne() align(32) callconv(.naked) noreturn {
1942 asm volatile (
1943 \\ //V0 and V1 have input
1944 \\ //First rnd, replaces V0.h=V0.hf
1945 \\ //Convert input vector to half word
1946 \\ {
1947 \\ R1=#0x3800 //+.5
1948 \\ R2=#0xB800 //-.5
1949 \\ V7.h=V0.hf //Convert and truncate half precision
1950 \\ }
1951 \\ {
1952 \\ V6=#0
1953 \\ R3=#0x00010001
1954 \\ R4=#0x37FF
1955 \\ }
1956 \\ {
1957 \\ V10=vsplat(R3)
1958 \\ V12.h=vsplat(R4)
1959 \\ V15.hf=V7.h //Convert truncated back to hf
1960 \\ }
1961 \\ {
1962 \\ V23.h=vsplat(R1) //V3 = +.5
1963 \\ V24.h=vsplat(R2) //V4 = -.5
1964 \\ V5.qf16=vsub(V0.hf,V15.hf) //Sub truncated value from original value
1965 \\ R0=#0x7FFF //Mask off sign bit of IEEE-754
1966 \\ }
1967 \\ {
1968 \\ Q0=vcmp.gt(V0.hf,V6.hf) // hf value is pos (hf > 0)
1969 \\ V5.hf=V5.qf16 //V5 is the fractional of original value
1970 \\ V22.h=vsplat(R0) //Splat R0 to Mask off sign bit
1971 \\ }
1972 \\ {
1973 \\ V15=vmux(Q0,V23,V24) //If input is pos value, use +.5. If neg value, use -.5 (Q in prev packet)
1974 \\ V2=vand(V22,V5) //V2=abs(frac)
1975 \\ V13=vand(V0,V22) //V13 = abs(input)
1976 \\ }
1977 \\ {
1978 \\ Q1=vcmp.eq(V2.h,V23.h) // frac == .5 (0x3800)
1979 \\ V15=vsplat(R3) //V1=1
1980 \\ V4.qf16=vadd(V0.hf,V15.hf) // Add +.5 or -.5 to V0
1981 \\ Q3=vcmp.eq(V13.h,V12.h) //Q3 = if(input == abs(.4998))
1982 \\ }
1983 \\ {
1984 \\ V11=vand(V7,V10) //Mask off all the lower bits
1985 \\ V3.h = vadd(V15.h,V15.h) //V3 is 2
1986 \\ }
1987 \\ {
1988 \\ Q2=vcmp.eq(V11.h,V10.h) //Is input value odd if halfword equals 0x1
1989 \\ V4.hf=V4.qf16 //hf value after add/sub .5
1990 \\ }
1991 \\ {
1992 \\ Q1=and(Q1,!Q2) //Is frac .5 and input is even
1993 \\ if (Q0) V15.h-=V3.h //If input is pos, sub 2 so V1 is -1
1994 \\ V4=vmux(Q3,V6,V4)
1995 \\ }
1996 \\ {
1997 \\ V4.h=V4.hf //Truncate, V4 has converted value
1998 \\ V15=vmux(Q1,V15,V6) //If frac == .5 and input is even, use +1/-1. Else 0
1999 \\ }
2000 \\ {
2001 \\ //Second rnd, replaces V1.h=V1.hf //Convert input vector to half word
2002 \\ V7.h=V1.hf //Convert and truncate half precision
2003 \\ }
2004 \\ {
2005 \\ V16.h = vadd(V4.h,V15.h) //Add +1/-1 or 0. V4 has the result
2006 \\ V1.hf=V7.h //Convert truncated back to hf
2007 \\ }
2008 \\ {
2009 \\ V5.qf16=vsub(V0.hf,V1.hf) //Sub truncated value from original value
2010 \\ R0=#0x7FFF //Mask off sign bit of IEEE-754
2011 \\ }
2012 \\ {
2013 \\ Q0=vcmp.gt(V0.hf,V6.hf) // hf value is pos (hf > 0)
2014 \\ V5.hf=V5.qf16 //V5 is the fractional of original value
2015 \\ }
2016 \\ {
2017 \\ V1=vmux(Q0,V23,V24) //If input is pos value, use +.5. If neg value, use -.5 (Q in prev packet)
2018 \\ V2=vand(V22,V5) //V2=abs(frac)
2019 \\ V13=vand(V0,V22) //V13 = abs(input)
2020 \\ }
2021 \\ {
2022 \\ Q1=vcmp.eq(V2.h,V23.h) // frac == .5 (0x3800)
2023 \\ V1=vsplat(R3) //V1=1
2024 \\ V4.qf16=vadd(V0.hf,V1.hf) // Add +.5 or -.5 to V0
2025 \\ Q3=vcmp.eq(V13.h,V12.h) //Q3 = if(input == abs(.4998))
2026 \\ }
2027 \\ {
2028 \\ V11=vand(V7,V10) //Mask off all the lower bits
2029 \\ V3.h = vadd(V1.h,V1.h) //V3 is 2
2030 \\ }
2031 \\ {
2032 \\ Q2=vcmp.eq(V11.h,V10.h) //Is input value odd if halfword equals 0x1
2033 \\ V4.hf=V4.qf16 //hf value after add/sub .5
2034 \\ }
2035 \\ {
2036 \\ Q1=and(Q1,!Q2) //Is frac .5 and input is even
2037 \\ if (Q0) V1.h-=V3.h //If input is pos, sub 2 so V1 is -1
2038 \\ V4=vmux(Q3,V6,V4)
2039 \\ }
2040 \\ {
2041 \\ V4.h=V4.hf //Truncate, V4 has converted value
2042 \\ V1=vmux(Q1,V1,V6) //If frac == .5 and input is even, use +1/-1. Else 0
2043 \\ }
2044 \\ {
2045 \\ V17.h = vadd(V4.h,V1.h) //Add +1/-1 or 0. V4 has the result
2046 \\ }
2047 \\ {
2048 \\ V0.ub = vpack(V17.h,V16.h):sat
2049 \\ }
2050 \\ {
2051 \\ V0.h=vshuff(V0.h)
2052 \\ jumpr LR
2053 \\ }
2054 );
2055}
2056
2057fn __qf_convert_hf_to_uh_rne() align(32) callconv(.naked) noreturn {
2058 asm volatile (
2059 \\ {
2060 \\ R20=#0x38003800 //.5
2061 \\ R21=#0x77FF //Number right before 2^15
2062 \\ R22=#1
2063 \\ R23=#0x7BFF //num right under Inf
2064 \\ }
2065 \\ {
2066 \\ V21=#0
2067 \\ V23.qf16=vmpy(V0.hf,R20.hf) //Multiply .5
2068 \\ }
2069 \\ //First rnd, replaces V22.h=V0.hf
2070 \\ //Convert input vector to half word
2071 \\ {
2072 \\ R1=#0x3800 //+.5
2073 \\ R2=#0xB800 //-.5
2074 \\ V7.h=V0.hf //Convert and truncate half precision
2075 \\ }
2076 \\ {
2077 \\ V6=#0
2078 \\ R3=#0x00010001
2079 \\ R4=#0x37FF
2080 \\ }
2081 \\ {
2082 \\ V10=vsplat(R3)
2083 \\ V12.h=vsplat(R4)
2084 \\ V1.hf=V7.h //Convert truncated back to hf
2085 \\ }
2086 \\ {
2087 \\ V26.h=vsplat(R1) //V3 = +.5
2088 \\ V27.h=vsplat(R2) //V4 = -.5
2089 \\ V5.qf16=vsub(V0.hf,V1.hf) //Sub truncated value from original value
2090 \\ R0=#0x7FFF //Mask off sign bit of IEEE-754
2091 \\ }
2092 \\ {
2093 \\ Q0=vcmp.gt(V0.hf,V6.hf) // hf value is pos (hf > 0)
2094 \\ V5.hf=V5.qf16 //V5 is the fractional of original value
2095 \\ V25.h=vsplat(R0) //Splat R0 to Mask off sign bit
2096 \\ }
2097 \\ {
2098 \\ V1=vmux(Q0,V26,V27) //If input is pos value, use +.5. If neg value, use -.5 (Q in prev packet)
2099 \\ V2=vand(V25,V5) //V2=abs(frac)
2100 \\ V13=vand(V0,V25) //V13 = abs(input)
2101 \\ }
2102 \\ {
2103 \\ Q1=vcmp.eq(V2.h,V26.h) // frac == .5 (0x3800)
2104 \\ V1=vsplat(R3) //V1=1
2105 \\ V4.qf16=vadd(V0.hf,V1.hf) // Add +.5 or -.5 to V0
2106 \\ Q3=vcmp.eq(V13.h,V12.h) //Q3 = if(input == abs(.4998))
2107 \\ }
2108 \\ {
2109 \\ V11=vand(V7,V10) //Mask off all the lower bits
2110 \\ V3.h = vadd(V1.h,V1.h) //V3 is 2
2111 \\ }
2112 \\ {
2113 \\ Q2=vcmp.eq(V11.h,V10.h) //Is input value odd if halfword equals 0x1
2114 \\ V4.hf=V4.qf16 //hf value after add/sub .5
2115 \\ }
2116 \\ {
2117 \\ Q1=and(Q1,!Q2) //Is frac .5 and input is even
2118 \\ if (Q0) V1.h-=V3.h //If input is pos, sub 2 so V1 is -1
2119 \\ V4=vmux(Q3,V6,V4)
2120 \\ }
2121 \\ {
2122 \\ V4.h=V4.hf //Truncate, V4 has converted value
2123 \\ V1=vmux(Q1,V1,V6) //If frac == .5 and input is even, use +1/-1. Else 0
2124 \\ }
2125 \\ {
2126 \\ V22.h = vadd(V4.h,V1.h) //Add +1/-1 or 0. V4 has the result
2127 \\ }
2128 \\ {
2129 \\ V23.hf=V23.qf16 //Convert multiply back to hf
2130 \\ V21.h=vmax(V21.h,V22.h) //Filter out anything lower than 0
2131 \\ }
2132 \\ {
2133 \\ V22.h=vsplat(R21) //Splat overflow value for compare
2134 \\ //Second rnd, replaces V23.h=V23.hf
2135 \\ //Convert input vector to half word
2136 \\ V7.h=V23.hf //Convert and truncate half precision
2137 \\ }
2138 \\ {
2139 \\ V1.hf=V7.h //Convert truncated back to hf
2140 \\ }
2141 \\ {
2142 \\ V5.qf16=vsub(V23.hf,V1.hf) //Sub truncated value from original value
2143 \\ }
2144 \\ {
2145 \\ Q0=vcmp.gt(V23.hf,V6.hf) // hf value is pos (hf > 0)
2146 \\ V5.hf=V5.qf16 //V5 is the fractional of original value
2147 \\ }
2148 \\ {
2149 \\ V1=vmux(Q0,V26,V27) //If input is pos value, use +.5. If neg value, use -.5 (Q in prev packet)
2150 \\ V2=vand(V25,V5) //V2=abs(frac)
2151 \\ V13=vand(V23,V25) //V13 = abs(input)
2152 \\ }
2153 \\ {
2154 \\ Q1=vcmp.eq(V2.h,V26.h) // frac == .5 (0x3800)
2155 \\ V1=vsplat(R3) //V1=1
2156 \\ V4.qf16=vadd(V23.hf,V1.hf) // Add +.5 or -.5 to V0
2157 \\ Q3=vcmp.eq(V13.h,V12.h) //Q3 = if(input == abs(.4998))
2158 \\ }
2159 \\ {
2160 \\ V11=vand(V7,V10) //Mask off all the lower bits
2161 \\ V3.h = vadd(V1.h,V1.h) //V3 is 2
2162 \\ }
2163 \\ {
2164 \\ Q2=vcmp.eq(V11.h,V10.h) //Is input value odd if halfword equals 0x1
2165 \\ V4.hf=V4.qf16 //hf value after add/sub .5
2166 \\ }
2167 \\ {
2168 \\ Q1=and(Q1,!Q2) //Is frac .5 and input is even
2169 \\ if (Q0) V1.h-=V3.h //If input is pos, sub 2 so V1 is -1
2170 \\ V4=vmux(Q3,V6,V4)
2171 \\ }
2172 \\ {
2173 \\ V4.h=V4.hf //Truncate, V4 has converted value
2174 \\ V1=vmux(Q1,V1,V6) //If frac == .5 and input is even, use +1/-1. Else 0
2175 \\ }
2176 \\ {
2177 \\ V23.h = vadd(V4.h,V1.h) //Add +1/-1 or 0. V4 has the result
2178 \\ }
2179 \\ {
2180 \\ Q1=vcmp.gt(V22.hf,V0.hf) //Q1 is if value doesn't overflow on hf=h convert (V0 is input, V2 is right before 2^15)
2181 \\ V23.h=vasl(V23.h,R22) //Left shift converted value
2182 \\ V24.h=vsplat(R23) //Splat inf
2183 \\ }
2184 \\ {
2185 \\ Q1|=vcmp.gt(V0.uh,V24.uh) //Q1 is value is < inf/nan
2186 \\ }
2187 \\ {
2188 \\ V0=vmux(Q1,V21,V23) //If value is not overflow or input is Inf, set to converted input. Else, set to overflow
2189 \\ jumpr LR
2190 \\ }
2191 );
2192}
2193
2194fn __qf_fast_convert_hf_to_b_rne() align(32) callconv(.naked) noreturn {
2195 asm volatile (
2196 \\ //V0.hf and V1.hf has value to be converted
2197 \\ {
2198 \\ R1=#0x3800 //+.5
2199 \\ R2=#0xB800 //-.5
2200 \\ V2=#0
2201 \\ }
2202 \\ {
2203 \\ Q0=vcmp.gt(V0.hf,V2.hf) // hf value is pos (hf > 0)
2204 \\ Q1=vcmp.gt(V1.hf,V2.hf) // hf value is pos (hf > 0)
2205 \\ V2.h=vsplat(R1) //V1 = +.5
2206 \\ V3.h=vsplat(R2) //V2 = -.5
2207 \\ }
2208 \\ {
2209 \\ V2=vmux(Q0,V2,V3) //If pos value, use +.5. If neg value, use -.5
2210 \\ V3=vmux(Q1,V2,V3) //If pos value, use +.5. If neg value, use -.5
2211 \\ }
2212 \\ {
2213 \\ V4.qf16=vadd(V0.hf,V2.hf) // Add +.5 or -.5 to V0
2214 \\ }
2215 \\ {
2216 \\ V5.qf16=vadd(V1.hf,V3.hf) // Add +.5 or -.5 to V1
2217 \\ }
2218 \\ {
2219 \\ V4.hf=V4.qf16
2220 \\ }
2221 \\ {
2222 \\ V5.hf=V5.qf16
2223 \\ }
2224 \\ {
2225 \\ V4.h=V4.hf //Truncate, V4 has converted value
2226 \\ }
2227 \\ {
2228 \\ V5.h=V5.hf //Truncate, V5 has converted value
2229 \\ }
2230 \\ {
2231 \\ V0.ub = vpack(V4.h,V5.h):sat
2232 \\ }
2233 \\ {
2234 \\ V0.h = vshuff(V0.h)
2235 \\ jumpr LR
2236 \\ }
2237 );
2238}
2239
2240fn __qf_fast_convert_hf_to_h_rne() align(32) callconv(.naked) noreturn {
2241 asm volatile (
2242 \\ //V0.hf has value to be converted
2243 \\ {
2244 \\ R1=#0x3800 //+.5
2245 \\ R2=#0xB800 //-.5
2246 \\ V1=#0
2247 \\ }
2248 \\ {
2249 \\ Q0=vcmp.gt(V0.hf,V1.hf) // hf value is pos (hf > 0)
2250 \\ V1.h=vsplat(R1) //V1 = +.5
2251 \\ V2.h=vsplat(R2) //V2 = -.5
2252 \\ }
2253 \\ {
2254 \\ V1=vmux(Q0,V1,V2) //If pos value, use +.5. If neg value, use -.5
2255 \\ }
2256 \\ {
2257 \\ V4.qf16=vadd(V0.hf,V1.hf) // Add +.5 or -.5 to V0
2258 \\ }
2259 \\ {
2260 \\ V4.hf=V4.qf16
2261 \\ }
2262 \\ {
2263 \\ V0.h=V4.hf //Truncate, V4 has converted value
2264 \\ jumpr LR
2265 \\ }
2266 );
2267}
2268
2269fn __qf_fast_convert_hf_to_ub_rne() align(32) callconv(.naked) noreturn {
2270 asm volatile (
2271 \\ //V0.hf and V1.hf have value to be converted
2272 \\ {
2273 \\ R1=#0x3800 //+.5
2274 \\ V3=#0
2275 \\ }
2276 \\ {
2277 \\ Q0=vcmp.gt(V0.hf,V3.hf) // hf value is pos (hf > 0)
2278 \\ Q1=vcmp.gt(V1.hf,V3.hf) // hf value is pos (hf > 0)
2279 \\ V2.h=vsplat(R1) //V1 = +.5
2280 \\ }
2281 \\ {
2282 \\ V4.qf16=vadd(V0.hf,V2.hf) // Add +.5
2283 \\ }
2284 \\ {
2285 \\ V5.qf16=vadd(V1.hf,V2.hf) // Add +.5
2286 \\ }
2287 \\ {
2288 \\ V4.hf=V4.qf16
2289 \\ }
2290 \\ {
2291 \\ V5.hf=V5.qf16
2292 \\ }
2293 \\ {
2294 \\ V4.h=V4.hf //Truncate, V4 has converted value
2295 \\ }
2296 \\ {
2297 \\ V5.h=V5.hf //Truncate, V5 has converted value
2298 \\ }
2299 \\ {
2300 \\ V4=vmux(Q0,V4,V3) //If original pos value, use converted. Else 0
2301 \\ V5=vmux(Q0,V5,V3) //If original pos value, use converted. Else 0
2302 \\ }
2303 \\ {
2304 \\ V0.ub = vpack(V4.h,V5.h):sat
2305 \\ }
2306 \\ {
2307 \\ V0.h = vshuff(V0.h)
2308 \\ jumpr LR
2309 \\ }
2310 );
2311}
2312
2313fn __qf_fast_convert_hf_to_uh_rne() align(32) callconv(.naked) noreturn {
2314 asm volatile (
2315 \\ //V0.hf has value to be converted
2316 \\ {
2317 \\ R1=#0x3800 //+.5
2318 \\ V3=#0
2319 \\ }
2320 \\ {
2321 \\ Q0=vcmp.gt(V0.hf,V3.hf) // hf value is pos (hf > 0)
2322 \\ V1.h=vsplat(R1) //V1 = +.5
2323 \\ }
2324 \\ {
2325 \\ V4.qf16=vadd(V0.hf,V1.hf) // Add +.5
2326 \\ }
2327 \\ {
2328 \\ V4.hf=V4.qf16
2329 \\ }
2330 \\ {
2331 \\ V4.h=V4.hf //Truncate, V4 has converted value
2332 \\ }
2333 \\ {
2334 \\ V0=vmux(Q0,V4,V3) //If original pos value, use converted. Else 0
2335 \\ jumpr LR
2336 \\ }
2337 );
2338}
2339
1762comptime {2340comptime {
1763 if (builtin.cpu.arch == .hexagon) {2341 if (builtin.cpu.arch == .hexagon) {
1764 symbol(&__hexagon_adddf3, "__hexagon_adddf3");2342 symbol(&__hexagon_adddf3, "__hexagon_adddf3");
...@@ -1785,5 +2363,15 @@ comptime {...@@ -1785,5 +2363,15 @@ comptime {
1785 symbol(&__hexagon_modsi3, "__hexagon_modsi3");2363 symbol(&__hexagon_modsi3, "__hexagon_modsi3");
1786 symbol(&__hexagon_memcpy_likely_aligned_min32bytes_mult8bytes, "__hexagon_memcpy_likely_aligned_min32bytes_mult8bytes");2364 symbol(&__hexagon_memcpy_likely_aligned_min32bytes_mult8bytes, "__hexagon_memcpy_likely_aligned_min32bytes_mult8bytes");
1787 symbol(&__hexagon_udivsi3, "__hexagon_udivsi3");2365 symbol(&__hexagon_udivsi3, "__hexagon_udivsi3");
2366 if (builtin.cpu.has(.hexagon, .hvxv79)) {
2367 symbol(&__qf_convert_hf_to_b_rne, "__qf_convert_hf_to_b_rne");
2368 symbol(&__qf_fast_convert_hf_to_b_rne, "__qf_fast_convert_hf_to_b_rne");
2369 symbol(&__qf_convert_hf_to_h_rne, "__qf_convert_hf_to_h_rne");
2370 symbol(&__qf_fast_convert_hf_to_h_rne, "__qf_fast_convert_hf_to_h_rne");
2371 symbol(&__qf_convert_hf_to_ub_rne, "__qf_convert_hf_to_ub_rne");
2372 symbol(&__qf_fast_convert_hf_to_ub_rne, "__qf_fast_convert_hf_to_ub_rne");
2373 symbol(&__qf_convert_hf_to_uh_rne, "__qf_convert_hf_to_uh_rne");
2374 symbol(&__qf_fast_convert_hf_to_uh_rne, "__qf_fast_convert_hf_to_uh_rne");
2375 }
1788 }2376 }
1789}2377}