| 1 | /* |
| 2 | * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. |
| 3 | * |
| 4 | * This program is free software; you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU General Public License as published by |
| 6 | * the Free Software Foundation; either version 2 of the License, or |
| 7 | * (at your option) any later version. |
| 8 | * |
| 9 | * This program is distributed in the hope that it will be useful, |
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | * GNU General Public License for more details. |
| 13 | * |
| 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | */ |
| 17 | |
| 18 | /* |
| 19 | * Floating-Point Instructions |
| 20 | */ |
| 21 | |
| 22 | /*************************************/ |
| 23 | /* Scalar FP */ |
| 24 | /*************************************/ |
| 25 | Q6INSN(F2_sfadd,"Rd32=sfadd(Rs32,Rt32)",ATTRIBS(), |
| 26 | "Floating-Point Add", |
| 27 | { RdV=fUNFLOAT(fFLOAT(RsV)+fFLOAT(RtV));}) |
| 28 | |
| 29 | Q6INSN(F2_sfsub,"Rd32=sfsub(Rs32,Rt32)",ATTRIBS(), |
| 30 | "Floating-Point Subtract", |
| 31 | { RdV=fUNFLOAT(fFLOAT(RsV)-fFLOAT(RtV));}) |
| 32 | |
| 33 | Q6INSN(F2_sfmpy,"Rd32=sfmpy(Rs32,Rt32)",ATTRIBS(), |
| 34 | "Floating-Point Multiply", |
| 35 | { RdV=fUNFLOAT(fSFMPY(fFLOAT(RsV),fFLOAT(RtV)));}) |
| 36 | |
| 37 | Q6INSN(F2_sffma,"Rx32+=sfmpy(Rs32,Rt32)",ATTRIBS(), |
| 38 | "Floating-Point Fused Multiply Add", |
| 39 | { RxV=fUNFLOAT(fFMAF(fFLOAT(RsV),fFLOAT(RtV),fFLOAT(RxV)));}) |
| 40 | |
| 41 | Q6INSN(F2_sffma_sc,"Rx32+=sfmpy(Rs32,Rt32,Pu4):scale",ATTRIBS(), |
| 42 | "Floating-Point Fused Multiply Add w/ Additional Scaling (2**Pu)", |
| 43 | { |
| 44 | fHIDE(size4s_t tmp;) |
| 45 | fCHECKSFNAN3(RxV,RxV,RsV,RtV); |
| 46 | tmp=fUNFLOAT(fFMAFX(fFLOAT(RsV),fFLOAT(RtV),fFLOAT(RxV),PuV)); |
| 47 | if (!((fFLOAT(RxV) == 0.0) && fISZEROPROD(fFLOAT(RsV),fFLOAT(RtV)))) RxV = tmp; |
| 48 | }) |
| 49 | |
| 50 | Q6INSN(F2_sffms,"Rx32-=sfmpy(Rs32,Rt32)",ATTRIBS(), |
| 51 | "Floating-Point Fused Multiply Add", |
| 52 | { RxV=fUNFLOAT(fFMAF(-fFLOAT(RsV),fFLOAT(RtV),fFLOAT(RxV))); }) |
| 53 | |
| 54 | Q6INSN(F2_sffma_lib,"Rx32+=sfmpy(Rs32,Rt32):lib",ATTRIBS(), |
| 55 | "Floating-Point Fused Multiply Add for Library Routines", |
| 56 | { fFPSETROUND_NEAREST(); fHIDE(int infinp; int infminusinf; size4s_t tmp;) |
| 57 | infminusinf = ((isinf(fFLOAT(RxV))) && |
| 58 | (fISINFPROD(fFLOAT(RsV),fFLOAT(RtV))) && |
| 59 | (fGETBIT(31,RsV ^ RxV ^ RtV) != 0)); |
| 60 | infinp = (isinf(fFLOAT(RxV))) || (isinf(fFLOAT(RtV))) || (isinf(fFLOAT(RsV))); |
| 61 | fCHECKSFNAN3(RxV,RxV,RsV,RtV); |
| 62 | tmp=fUNFLOAT(fFMAF(fFLOAT(RsV),fFLOAT(RtV),fFLOAT(RxV))); |
| 63 | if (!((fFLOAT(RxV) == 0.0) && fISZEROPROD(fFLOAT(RsV),fFLOAT(RtV)))) RxV = tmp; |
| 64 | fFPCANCELFLAGS(); |
| 65 | if (isinf(fFLOAT(RxV)) && !infinp) RxV = RxV - 1; |
| 66 | if (infminusinf) RxV = 0; |
| 67 | }) |
| 68 | |
| 69 | Q6INSN(F2_sffms_lib,"Rx32-=sfmpy(Rs32,Rt32):lib",ATTRIBS(), |
| 70 | "Floating-Point Fused Multiply Add for Library Routines", |
| 71 | { fFPSETROUND_NEAREST(); fHIDE(int infinp; int infminusinf; size4s_t tmp;) |
| 72 | infminusinf = ((isinf(fFLOAT(RxV))) && |
| 73 | (fISINFPROD(fFLOAT(RsV),fFLOAT(RtV))) && |
| 74 | (fGETBIT(31,RsV ^ RxV ^ RtV) == 0)); |
| 75 | infinp = (isinf(fFLOAT(RxV))) || (isinf(fFLOAT(RtV))) || (isinf(fFLOAT(RsV))); |
| 76 | fCHECKSFNAN3(RxV,RxV,RsV,RtV); |
| 77 | tmp=fUNFLOAT(fFMAF(-fFLOAT(RsV),fFLOAT(RtV),fFLOAT(RxV))); |
| 78 | if (!((fFLOAT(RxV) == 0.0) && fISZEROPROD(fFLOAT(RsV),fFLOAT(RtV)))) RxV = tmp; |
| 79 | fFPCANCELFLAGS(); |
| 80 | if (isinf(fFLOAT(RxV)) && !infinp) RxV = RxV - 1; |
| 81 | if (infminusinf) RxV = 0; |
| 82 | }) |
| 83 | |
| 84 | |
| 85 | Q6INSN(F2_sfcmpeq,"Pd4=sfcmp.eq(Rs32,Rt32)",ATTRIBS(), |
| 86 | "Floating Point Compare for Equal", |
| 87 | {PdV=f8BITSOF(fFLOAT(RsV)==fFLOAT(RtV));}) |
| 88 | |
| 89 | Q6INSN(F2_sfcmpgt,"Pd4=sfcmp.gt(Rs32,Rt32)",ATTRIBS(), |
| 90 | "Floating-Point Compare for Greater Than", |
| 91 | {PdV=f8BITSOF(fFLOAT(RsV)>fFLOAT(RtV));}) |
| 92 | |
| 93 | /* cmpge is not the same as !cmpgt(swapops) in IEEE */ |
| 94 | |
| 95 | Q6INSN(F2_sfcmpge,"Pd4=sfcmp.ge(Rs32,Rt32)",ATTRIBS(), |
| 96 | "Floating-Point Compare for Greater Than / Equal To", |
| 97 | {PdV=f8BITSOF(fFLOAT(RsV)>=fFLOAT(RtV));}) |
| 98 | |
| 99 | /* Everyone seems to have this... */ |
| 100 | |
| 101 | Q6INSN(F2_sfcmpuo,"Pd4=sfcmp.uo(Rs32,Rt32)",ATTRIBS(), |
| 102 | "Floating-Point Compare for Unordered", |
| 103 | {PdV=f8BITSOF(isunordered(fFLOAT(RsV),fFLOAT(RtV)));}) |
| 104 | |
| 105 | |
| 106 | Q6INSN(F2_sfmax,"Rd32=sfmax(Rs32,Rt32)",ATTRIBS(), |
| 107 | "Maximum of Floating-Point values", |
| 108 | { RdV = fUNFLOAT(fSF_MAX(fFLOAT(RsV),fFLOAT(RtV))); }) |
| 109 | |
| 110 | Q6INSN(F2_sfmin,"Rd32=sfmin(Rs32,Rt32)",ATTRIBS(), |
| 111 | "Minimum of Floating-Point values", |
| 112 | { RdV = fUNFLOAT(fSF_MIN(fFLOAT(RsV),fFLOAT(RtV))); }) |
| 113 | |
| 114 | |
| 115 | Q6INSN(F2_sfclass,"Pd4=sfclass(Rs32,#u5)",ATTRIBS(), |
| 116 | "Classify Floating-Point Value", |
| 117 | { |
| 118 | fHIDE(int class;) |
| 119 | PdV = 0; |
| 120 | class = fpclassify(fFLOAT(RsV)); |
| 121 | /* Is the value zero? */ |
| 122 | if (fGETBIT(0,uiV) && (class == FP_ZERO)) PdV = 0xff; |
| 123 | if (fGETBIT(1,uiV) && (class == FP_NORMAL)) PdV = 0xff; |
| 124 | if (fGETBIT(2,uiV) && (class == FP_SUBNORMAL)) PdV = 0xff; |
| 125 | if (fGETBIT(3,uiV) && (class == FP_INFINITE)) PdV = 0xff; |
| 126 | if (fGETBIT(4,uiV) && (class == FP_NAN)) PdV = 0xff; |
| 127 | fFPCANCELFLAGS(); |
| 128 | }) |
| 129 | |
| 130 | /* Range: +/- (1.0 .. 1+(63/64)) * 2**(-6 .. +9) */ |
| 131 | /* More immediate bits should probably be used for more precision? */ |
| 132 | |
| 133 | Q6INSN(F2_sfimm_p,"Rd32=sfmake(#u10):pos",ATTRIBS(), |
| 134 | "Make Floating Point Value", |
| 135 | { |
| 136 | RdV = (127 - 6) << 23; |
| 137 | RdV += uiV << 17; |
| 138 | }) |
| 139 | |
| 140 | Q6INSN(F2_sfimm_n,"Rd32=sfmake(#u10):neg",ATTRIBS(), |
| 141 | "Make Floating Point Value", |
| 142 | { |
| 143 | RdV = (127 - 6) << 23; |
| 144 | RdV += (uiV << 17); |
| 145 | RdV |= (1 << 31); |
| 146 | }) |
| 147 | |
| 148 | |
| 149 | Q6INSN(F2_sfrecipa,"Rd32,Pe4=sfrecipa(Rs32,Rt32)",ATTRIBS(), |
| 150 | "Reciprocal Approximation for Division", |
| 151 | { |
| 152 | fHIDE(int idx;) |
| 153 | fHIDE(int adjust;) |
| 154 | fHIDE(int mant;) |
| 155 | fHIDE(int exp;) |
| 156 | if (fSF_RECIP_COMMON(RsV,RtV,RdV,adjust)) { |
| 157 | PeV = adjust; |
| 158 | idx = (RtV >> 16) & 0x7f; |
| 159 | mant = (fSF_RECIP_LOOKUP(idx) << 15) | 1; |
| 160 | exp = fSF_BIAS() - (fSF_GETEXP(RtV) - fSF_BIAS()) - 1; |
| 161 | RdV = fMAKESF(fGETBIT(31,RtV),exp,mant); |
| 162 | } |
| 163 | }) |
| 164 | |
| 165 | Q6INSN(F2_sffixupn,"Rd32=sffixupn(Rs32,Rt32)",ATTRIBS(), |
| 166 | "Fix Up Numerator", |
| 167 | { |
| 168 | fHIDE(int adjust;) |
| 169 | fSF_RECIP_COMMON(RsV,RtV,RdV,adjust); |
| 170 | RdV = RsV; |
| 171 | }) |
| 172 | |
| 173 | Q6INSN(F2_sffixupd,"Rd32=sffixupd(Rs32,Rt32)",ATTRIBS(), |
| 174 | "Fix Up Denominator", |
| 175 | { |
| 176 | fHIDE(int adjust;) |
| 177 | fSF_RECIP_COMMON(RsV,RtV,RdV,adjust); |
| 178 | RdV = RtV; |
| 179 | }) |
| 180 | |
| 181 | Q6INSN(F2_sfinvsqrta,"Rd32,Pe4=sfinvsqrta(Rs32)",ATTRIBS(), |
| 182 | "Reciprocal Square Root Approximation", |
| 183 | { |
| 184 | fHIDE(int idx;) |
| 185 | fHIDE(int adjust;) |
| 186 | fHIDE(int mant;) |
| 187 | fHIDE(int exp;) |
| 188 | if (fSF_INVSQRT_COMMON(RsV,RdV,adjust)) { |
| 189 | PeV = adjust; |
| 190 | idx = (RsV >> 17) & 0x7f; |
| 191 | mant = (fSF_INVSQRT_LOOKUP(idx) << 15); |
| 192 | exp = fSF_BIAS() - ((fSF_GETEXP(RsV) - fSF_BIAS()) >> 1) - 1; |
| 193 | RdV = fMAKESF(fGETBIT(31,RsV),exp,mant); |
| 194 | } |
| 195 | }) |
| 196 | |
| 197 | Q6INSN(F2_sffixupr,"Rd32=sffixupr(Rs32)",ATTRIBS(), |
| 198 | "Fix Up Radicand", |
| 199 | { |
| 200 | fHIDE(int adjust;) |
| 201 | fSF_INVSQRT_COMMON(RsV,RdV,adjust); |
| 202 | RdV = RsV; |
| 203 | }) |
| 204 | |
| 205 | /*************************************/ |
| 206 | /* Scalar DP */ |
| 207 | /*************************************/ |
| 208 | Q6INSN(F2_dfadd,"Rdd32=dfadd(Rss32,Rtt32)",ATTRIBS(), |
| 209 | "Floating-Point Add", |
| 210 | { RddV=fUNDOUBLE(fDOUBLE(RssV)+fDOUBLE(RttV));}) |
| 211 | |
| 212 | Q6INSN(F2_dfsub,"Rdd32=dfsub(Rss32,Rtt32)",ATTRIBS(), |
| 213 | "Floating-Point Subtract", |
| 214 | { RddV=fUNDOUBLE(fDOUBLE(RssV)-fDOUBLE(RttV));}) |
| 215 | |
| 216 | Q6INSN(F2_dfmax,"Rdd32=dfmax(Rss32,Rtt32)",ATTRIBS(), |
| 217 | "Maximum of Floating-Point values", |
| 218 | { RddV = fUNDOUBLE(fDF_MAX(fDOUBLE(RssV),fDOUBLE(RttV))); }) |
| 219 | |
| 220 | Q6INSN(F2_dfmin,"Rdd32=dfmin(Rss32,Rtt32)",ATTRIBS(), |
| 221 | "Minimum of Floating-Point values", |
| 222 | { RddV = fUNDOUBLE(fDF_MIN(fDOUBLE(RssV),fDOUBLE(RttV))); }) |
| 223 | |
| 224 | Q6INSN(F2_dfmpyfix,"Rdd32=dfmpyfix(Rss32,Rtt32)",ATTRIBS(), |
| 225 | "Fix Up Multiplicand for Multiplication", |
| 226 | { |
| 227 | if (fDF_ISDENORM(RssV) && fDF_ISBIG(RttV) && fDF_ISNORMAL(RttV)) RddV = fUNDOUBLE(fDOUBLE(RssV) * 0x1.0p52); |
| 228 | else if (fDF_ISDENORM(RttV) && fDF_ISBIG(RssV) && fDF_ISNORMAL(RssV)) RddV = fUNDOUBLE(fDOUBLE(RssV) * 0x1.0p-52); |
| 229 | else RddV = RssV; |
| 230 | }) |
| 231 | |
| 232 | Q6INSN(F2_dfmpyll,"Rdd32=dfmpyll(Rss32,Rtt32)",ATTRIBS(), |
| 233 | "Multiply low*low and shift off low 32 bits into sticky (in MSB)", |
| 234 | { |
| 235 | fHIDE(size8u_t prod;) |
| 236 | prod = fMPY32UU(fGETUWORD(0,RssV),fGETUWORD(0,RttV)); |
| 237 | RddV = (prod >> 32) << 1; |
| 238 | if (fGETUWORD(0,prod) != 0) fSETBIT(0,RddV,1); |
| 239 | }) |
| 240 | |
| 241 | Q6INSN(F2_dfmpylh,"Rxx32+=dfmpylh(Rss32,Rtt32)",ATTRIBS(), |
| 242 | "Multiply low*high and accumulate", |
| 243 | { |
| 244 | RxxV += (fGETUWORD(0,RssV) * (0x00100000 | fZXTN(20,64,fGETUWORD(1,RttV)))) << 1; |
| 245 | }) |
| 246 | |
| 247 | Q6INSN(F2_dfmpyhh,"Rxx32+=dfmpyhh(Rss32,Rtt32)",ATTRIBS(), |
| 248 | "Multiply high*high and accumulate with L*H value", |
| 249 | { |
| 250 | RxxV = fUNDOUBLE(fDF_MPY_HH(fDOUBLE(RssV),fDOUBLE(RttV),RxxV)); |
| 251 | }) |
| 252 | |
| 253 | |
| 254 | |
| 255 | Q6INSN(F2_dfcmpeq,"Pd4=dfcmp.eq(Rss32,Rtt32)",ATTRIBS(), |
| 256 | "Floating Point Compare for Equal", |
| 257 | {PdV=f8BITSOF(fDOUBLE(RssV)==fDOUBLE(RttV));}) |
| 258 | |
| 259 | Q6INSN(F2_dfcmpgt,"Pd4=dfcmp.gt(Rss32,Rtt32)",ATTRIBS(), |
| 260 | "Floating-Point Compare for Greater Than", |
| 261 | {PdV=f8BITSOF(fDOUBLE(RssV)>fDOUBLE(RttV));}) |
| 262 | |
| 263 | |
| 264 | /* cmpge is not the same as !cmpgt(swapops) in IEEE */ |
| 265 | |
| 266 | Q6INSN(F2_dfcmpge,"Pd4=dfcmp.ge(Rss32,Rtt32)",ATTRIBS(), |
| 267 | "Floating-Point Compare for Greater Than / Equal To", |
| 268 | {PdV=f8BITSOF(fDOUBLE(RssV)>=fDOUBLE(RttV));}) |
| 269 | |
| 270 | /* Everyone seems to have this... */ |
| 271 | |
| 272 | Q6INSN(F2_dfcmpuo,"Pd4=dfcmp.uo(Rss32,Rtt32)",ATTRIBS(), |
| 273 | "Floating-Point Compare for Unordered", |
| 274 | {PdV=f8BITSOF(isunordered(fDOUBLE(RssV),fDOUBLE(RttV)));}) |
| 275 | |
| 276 | |
| 277 | Q6INSN(F2_dfclass,"Pd4=dfclass(Rss32,#u5)",ATTRIBS(), |
| 278 | "Classify Floating-Point Value", |
| 279 | { |
| 280 | fHIDE(int class;) |
| 281 | PdV = 0; |
| 282 | class = fpclassify(fDOUBLE(RssV)); |
| 283 | /* Is the value zero? */ |
| 284 | if (fGETBIT(0,uiV) && (class == FP_ZERO)) PdV = 0xff; |
| 285 | if (fGETBIT(1,uiV) && (class == FP_NORMAL)) PdV = 0xff; |
| 286 | if (fGETBIT(2,uiV) && (class == FP_SUBNORMAL)) PdV = 0xff; |
| 287 | if (fGETBIT(3,uiV) && (class == FP_INFINITE)) PdV = 0xff; |
| 288 | if (fGETBIT(4,uiV) && (class == FP_NAN)) PdV = 0xff; |
| 289 | fFPCANCELFLAGS(); |
| 290 | }) |
| 291 | |
| 292 | |
| 293 | /* Range: +/- (1.0 .. 1+(63/64)) * 2**(-6 .. +9) */ |
| 294 | /* More immediate bits should probably be used for more precision? */ |
| 295 | |
| 296 | Q6INSN(F2_dfimm_p,"Rdd32=dfmake(#u10):pos",ATTRIBS(), |
| 297 | "Make Floating Point Value", |
| 298 | { |
| 299 | RddV = (1023ULL - 6) << 52; |
| 300 | RddV += (fHIDE((size8u_t))uiV) << 46; |
| 301 | }) |
| 302 | |
| 303 | Q6INSN(F2_dfimm_n,"Rdd32=dfmake(#u10):neg",ATTRIBS(), |
| 304 | "Make Floating Point Value", |
| 305 | { |
| 306 | RddV = (1023ULL - 6) << 52; |
| 307 | RddV += (fHIDE((size8u_t))uiV) << 46; |
| 308 | RddV |= ((1ULL) << 63); |
| 309 | }) |
| 310 | |
| 311 | |
| 312 | /* CONVERSION */ |
| 313 | |
| 314 | #define CONVERT(TAG,DEST,DESTV,SRC,SRCV,OUTCAST,OUTTYPE,INCAST,INTYPE,MODETAG,MODESYN,MODEBEH) \ |
| 315 | Q6INSN(F2_conv_##TAG##MODETAG,#DEST"=convert_"#TAG"("#SRC")"#MODESYN,ATTRIBS(), \ |
| 316 | "Floating point format conversion", \ |
| 317 | { MODEBEH DESTV = OUTCAST(conv_##INTYPE##_to_##OUTTYPE(INCAST(SRCV))); }) |
| 318 | |
| 319 | CONVERT(sf2df,Rdd32,RddV,Rs32,RsV,fUNDOUBLE,df,fFLOAT,sf,,,) |
| 320 | CONVERT(df2sf,Rd32,RdV,Rss32,RssV,fUNFLOAT,sf,fDOUBLE,df,,,) |
| 321 | |
| 322 | #define ALLINTDST(TAGSTART,SRC,SRCV,INCAST,INTYPE,MODETAG,MODESYN,MODEBEH) \ |
| 323 | CONVERT(TAGSTART##uw,Rd32,RdV,SRC,SRCV,fCAST4u,4u,INCAST,INTYPE,MODETAG,MODESYN,MODEBEH) \ |
| 324 | CONVERT(TAGSTART##w,Rd32,RdV,SRC,SRCV,fCAST4s,4s,INCAST,INTYPE,MODETAG,MODESYN,MODEBEH) \ |
| 325 | CONVERT(TAGSTART##ud,Rdd32,RddV,SRC,SRCV,fCAST8u,8u,INCAST,INTYPE,MODETAG,MODESYN,MODEBEH) \ |
| 326 | CONVERT(TAGSTART##d,Rdd32,RddV,SRC,SRCV,fCAST8s,8s,INCAST,INTYPE,MODETAG,MODESYN,MODEBEH) |
| 327 | |
| 328 | #define ALLFPDST(TAGSTART,SRC,SRCV,INCAST,INTYPE,MODETAG,MODESYN,MODEBEH) \ |
| 329 | CONVERT(TAGSTART##sf,Rd32,RdV,SRC,SRCV,fUNFLOAT,sf,INCAST,INTYPE,MODETAG,MODESYN,MODEBEH) \ |
| 330 | CONVERT(TAGSTART##df,Rdd32,RddV,SRC,SRCV,fUNDOUBLE,df,INCAST,INTYPE,MODETAG,MODESYN,MODEBEH) |
| 331 | |
| 332 | #define ALLINTSRC(GEN,MODETAG,MODESYN,MODEBEH) \ |
| 333 | GEN(uw##2,Rs32,RsV,fCAST4u,4u,MODETAG,MODESYN,MODEBEH) \ |
| 334 | GEN(w##2,Rs32,RsV,fCAST4s,4s,MODETAG,MODESYN,MODEBEH) \ |
| 335 | GEN(ud##2,Rss32,RssV,fCAST8u,8u,MODETAG,MODESYN,MODEBEH) \ |
| 336 | GEN(d##2,Rss32,RssV,fCAST8s,8s,MODETAG,MODESYN,MODEBEH) |
| 337 | |
| 338 | #define ALLFPSRC(GEN,MODETAG,MODESYN,MODEBEH) \ |
| 339 | GEN(sf##2,Rs32,RsV,fFLOAT,sf,MODETAG,MODESYN,MODEBEH) \ |
| 340 | GEN(df##2,Rss32,RssV,fDOUBLE,df,MODETAG,MODESYN,MODEBEH) |
| 341 | |
| 342 | ALLINTSRC(ALLFPDST,,,) |
| 343 | ALLFPSRC(ALLINTDST,,,) |
| 344 | ALLFPSRC(ALLINTDST,_chop,:chop,fFPSETROUND_CHOP();) |