1.file "expf.s" 2 3 4// Copyright (c) 2000 - 2005, Intel Corporation 5// All rights reserved. 6// 7// 8// Redistribution and use in source and binary forms, with or without 9// modification, are permitted provided that the following conditions are 10// met: 11// 12// * Redistributions of source code must retain the above copyright 13// notice, this list of conditions and the following disclaimer. 14// 15// * Redistributions in binary form must reproduce the above copyright 16// notice, this list of conditions and the following disclaimer in the 17// documentation and/or other materials provided with the distribution. 18// 19// * The name of Intel Corporation may not be used to endorse or promote 20// products derived from this software without specific prior written 21// permission. 22 23// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR ITS 27// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 28// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 29// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 31// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR TORT (INCLUDING 32// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34// 35// Intel Corporation is the author of this code, and requests that all 36// problem reports or change requests be submitted to it directly at 37// http://www.intel.com/software/products/opensource/libraries/num.htm. 38 39// History 40//********************************************************************* 41// 02/02/00 Original version 42// 04/04/00 Unwind support added 43// 08/15/00 Bundle added after call to __libm_error_support to properly 44// set [the previously overwritten] GR_Parameter_RESULT. 45// 08/21/00 Improvements to save 2 cycles on main path, and shorten x=0 case 46// 12/07/00 Widen main path, shorten x=inf, nan paths 47// 03/15/01 Fix monotonicity problem around x=0 for round to +inf 48// 02/05/02 Corrected uninitialize predicate in POSSIBLE_UNDERFLOW path 49// 05/20/02 Cleaned up namespace and sf0 syntax 50// 07/26/02 Algorithm changed, accuracy improved 51// 09/26/02 support of higher precision inputs added, underflow threshold 52// corrected 53// 11/15/02 Improved performance on Itanium 2, added possible over/under paths 54// 05/30/03 Set inexact flag on unmasked overflow/underflow 55// 03/31/05 Reformatted delimiters between data tables 56// 57// 58// API 59//********************************************************************* 60// float expf(float) 61// 62// Overview of operation 63//********************************************************************* 64// Take the input x. w is "how many log2/128 in x?" 65// w = x * 64/log2 66// NJ = int(w) 67// x = NJ*log2/64 + R 68 69// NJ = 64*n + j 70// x = n*log2 + (log2/64)*j + R 71// 72// So, exp(x) = 2^n * 2^(j/64)* exp(R) 73// 74// T = 2^n * 2^(j/64) 75// Construct 2^n 76// Get 2^(j/64) table 77// actually all the entries of 2^(j/64) table are stored in DP and 78// with exponent bits set to 0 -> multiplication on 2^n can be 79// performed by doing logical "or" operation with bits presenting 2^n 80 81// exp(R) = 1 + (exp(R) - 1) 82// P = exp(R) - 1 approximated by Taylor series of 3rd degree 83// P = A3*R^3 + A2*R^2 + R, A3 = 1/6, A2 = 1/2 84// 85 86// The final result is reconstructed as follows 87// exp(x) = T + T*P 88 89// Special values 90//********************************************************************* 91// expf(+0) = 1.0 92// expf(-0) = 1.0 93 94// expf(+qnan) = +qnan 95// expf(-qnan) = -qnan 96// expf(+snan) = +qnan 97// expf(-snan) = -qnan 98 99// expf(-inf) = +0 100// expf(+inf) = +inf 101 102// Overflow and Underflow 103//********************************************************************* 104// expf(x) = largest single normal when 105// x = 88.72283 = 0x42b17217 106 107// expf(x) = smallest single normal when 108// x = -87.33654 = 0xc2aeac4f 109 110// expf(x) = largest round-to-nearest single zero when 111// x = -103.97208 = 0xc2cff1b5 112 113 114// Registers used 115//********************************************************************* 116// Floating Point registers used: 117// f8, input 118// f6,f7, f9 -> f15, f32 -> f40 119 120// General registers used: 121// r3, r23 -> r38 122 123// Predicate registers used: 124// p10 -> p15 125 126// Assembly macros 127//********************************************************************* 128// integer registers used 129// scratch 130rNJ = r3 131 132rTmp = r23 133rJ = r23 134rN = r24 135rTblAddr = r25 136rA3 = r26 137rExpHalf = r27 138rLn2Div64 = r28 139r17ones_m1 = r29 140rGt_ln = r29 141rRightShifter = r30 142r64DivLn2 = r31 143// stacked 144GR_SAVE_PFS = r32 145GR_SAVE_B0 = r33 146GR_SAVE_GP = r34 147GR_Parameter_X = r35 148GR_Parameter_Y = r36 149GR_Parameter_RESULT = r37 150GR_Parameter_TAG = r38 151 152// floating point registers used 153FR_X = f10 154FR_Y = f1 155FR_RESULT = f8 156// scratch 157fRightShifter = f6 158f64DivLn2 = f7 159fNormX = f9 160fNint = f10 161fN = f11 162fR = f12 163fLn2Div64 = f13 164fA2 = f14 165fA3 = f15 166// stacked 167fP = f32 168fT = f33 169fMIN_SGL_OFLOW_ARG = f34 170fMAX_SGL_ZERO_ARG = f35 171fMAX_SGL_NORM_ARG = f36 172fMIN_SGL_NORM_ARG = f37 173fRSqr = f38 174fTmp = f39 175fGt_pln = f39 176fWre_urm_f8 = f40 177fFtz_urm_f8 = f40 178 179 180RODATA 181.align 16 182 183LOCAL_OBJECT_START(_expf_table) 184data4 0x42b17218 // Smallest sgl arg to overflow sgl result, +88.7228 185data4 0xc2cff1b5 // Largest sgl for rnd-to-nearest 0 result, -103.9720 186data4 0x42b17217 // Largest sgl arg to give normal sgl result, +88.7228 187data4 0xc2aeac4f // Smallest sgl arg to give normal sgl result, -87.3365 188// 189// 2^(j/64) table, j goes from 0 to 63 190data8 0x0000000000000000 // 2^(0/64) 191data8 0x00002C9A3E778061 // 2^(1/64) 192data8 0x000059B0D3158574 // 2^(2/64) 193data8 0x0000874518759BC8 // 2^(3/64) 194data8 0x0000B5586CF9890F // 2^(4/64) 195data8 0x0000E3EC32D3D1A2 // 2^(5/64) 196data8 0x00011301D0125B51 // 2^(6/64) 197data8 0x0001429AAEA92DE0 // 2^(7/64) 198data8 0x000172B83C7D517B // 2^(8/64) 199data8 0x0001A35BEB6FCB75 // 2^(9/64) 200data8 0x0001D4873168B9AA // 2^(10/64) 201data8 0x0002063B88628CD6 // 2^(11/64) 202data8 0x0002387A6E756238 // 2^(12/64) 203data8 0x00026B4565E27CDD // 2^(13/64) 204data8 0x00029E9DF51FDEE1 // 2^(14/64) 205data8 0x0002D285A6E4030B // 2^(15/64) 206data8 0x000306FE0A31B715 // 2^(16/64) 207data8 0x00033C08B26416FF // 2^(17/64) 208data8 0x000371A7373AA9CB // 2^(18/64) 209data8 0x0003A7DB34E59FF7 // 2^(19/64) 210data8 0x0003DEA64C123422 // 2^(20/64) 211data8 0x0004160A21F72E2A // 2^(21/64) 212data8 0x00044E086061892D // 2^(22/64) 213data8 0x000486A2B5C13CD0 // 2^(23/64) 214data8 0x0004BFDAD5362A27 // 2^(24/64) 215data8 0x0004F9B2769D2CA7 // 2^(25/64) 216data8 0x0005342B569D4F82 // 2^(26/64) 217data8 0x00056F4736B527DA // 2^(27/64) 218data8 0x0005AB07DD485429 // 2^(28/64) 219data8 0x0005E76F15AD2148 // 2^(29/64) 220data8 0x0006247EB03A5585 // 2^(30/64) 221data8 0x0006623882552225 // 2^(31/64) 222data8 0x0006A09E667F3BCD // 2^(32/64) 223data8 0x0006DFB23C651A2F // 2^(33/64) 224data8 0x00071F75E8EC5F74 // 2^(34/64) 225data8 0x00075FEB564267C9 // 2^(35/64) 226data8 0x0007A11473EB0187 // 2^(36/64) 227data8 0x0007E2F336CF4E62 // 2^(37/64) 228data8 0x00082589994CCE13 // 2^(38/64) 229data8 0x000868D99B4492ED // 2^(39/64) 230data8 0x0008ACE5422AA0DB // 2^(40/64) 231data8 0x0008F1AE99157736 // 2^(41/64) 232data8 0x00093737B0CDC5E5 // 2^(42/64) 233data8 0x00097D829FDE4E50 // 2^(43/64) 234data8 0x0009C49182A3F090 // 2^(44/64) 235data8 0x000A0C667B5DE565 // 2^(45/64) 236data8 0x000A5503B23E255D // 2^(46/64) 237data8 0x000A9E6B5579FDBF // 2^(47/64) 238data8 0x000AE89F995AD3AD // 2^(48/64) 239data8 0x000B33A2B84F15FB // 2^(49/64) 240data8 0x000B7F76F2FB5E47 // 2^(50/64) 241data8 0x000BCC1E904BC1D2 // 2^(51/64) 242data8 0x000C199BDD85529C // 2^(52/64) 243data8 0x000C67F12E57D14B // 2^(53/64) 244data8 0x000CB720DCEF9069 // 2^(54/64) 245data8 0x000D072D4A07897C // 2^(55/64) 246data8 0x000D5818DCFBA487 // 2^(56/64) 247data8 0x000DA9E603DB3285 // 2^(57/64) 248data8 0x000DFC97337B9B5F // 2^(58/64) 249data8 0x000E502EE78B3FF6 // 2^(59/64) 250data8 0x000EA4AFA2A490DA // 2^(60/64) 251data8 0x000EFA1BEE615A27 // 2^(61/64) 252data8 0x000F50765B6E4540 // 2^(62/64) 253data8 0x000FA7C1819E90D8 // 2^(63/64) 254LOCAL_OBJECT_END(_expf_table) 255 256 257.section .text 258GLOBAL_IEEE754_ENTRY(expf) 259 260{ .mlx 261 addl rTblAddr = @ltoff(_expf_table),gp 262 movl r64DivLn2 = 0x40571547652B82FE // 64/ln(2) 263} 264{ .mlx 265 addl rA3 = 0x3E2AA, r0 // high bits of 1.0/6.0 rounded to SP 266 movl rRightShifter = 0x43E8000000000000 // DP Right Shifter 267} 268;; 269 270{ .mfi 271 // point to the beginning of the table 272 ld8 rTblAddr = [rTblAddr] 273 fclass.m p14, p0 = f8, 0x22 // test for -INF 274 shl rA3 = rA3, 12 // 0x3E2AA000, approx to 1.0/6.0 in SP 275} 276{ .mfi 277 nop.m 0 278 fnorm.s1 fNormX = f8 // normalized x 279 addl rExpHalf = 0xFFFE, r0 // exponent of 1/2 280} 281;; 282 283{ .mfi 284 setf.d f64DivLn2 = r64DivLn2 // load 64/ln(2) to FP reg 285 fclass.m p15, p0 = f8, 0x1e1 // test for NaT,NaN,+Inf 286 nop.i 0 287} 288{ .mlx 289 // load Right Shifter to FP reg 290 setf.d fRightShifter = rRightShifter 291 movl rLn2Div64 = 0x3F862E42FEFA39EF // DP ln(2)/64 in GR 292} 293;; 294 295{ .mfi 296 nop.m 0 297 fcmp.eq.s1 p13, p0 = f0, f8 // test for x = 0.0 298 nop.i 0 299} 300{ .mfb 301 setf.s fA3 = rA3 // load A3 to FP reg 302(p14) fma.s.s0 f8 = f0, f1, f0 // result if x = -inf 303(p14) br.ret.spnt b0 // exit here if x = -inf 304} 305;; 306 307{ .mfi 308 setf.exp fA2 = rExpHalf // load A2 to FP reg 309 fcmp.eq.s0 p6, p0 = f8, f0 // Dummy to flag denorm 310 nop.i 0 311} 312{ .mfb 313 setf.d fLn2Div64 = rLn2Div64 // load ln(2)/64 to FP reg 314(p15) fma.s.s0 f8 = f8, f1, f0 // result if x = NaT,NaN,+Inf 315(p15) br.ret.spnt b0 // exit here if x = NaT,NaN,+Inf 316} 317;; 318 319{ .mfb 320 // overflow and underflow_zero threshold 321 ldfps fMIN_SGL_OFLOW_ARG, fMAX_SGL_ZERO_ARG = [rTblAddr], 8 322(p13) fma.s.s0 f8 = f1, f1, f0 // result if x = 0.0 323(p13) br.ret.spnt b0 // exit here if x =0.0 324} 325;; 326 327 // max normal and underflow_denorm threshold 328{ .mfi 329 ldfps fMAX_SGL_NORM_ARG, fMIN_SGL_NORM_ARG = [rTblAddr], 8 330 nop.f 0 331 nop.i 0 332} 333;; 334 335{ .mfi 336 nop.m 0 337 // x*(64/ln(2)) + Right Shifter 338 fma.s1 fNint = fNormX, f64DivLn2, fRightShifter 339 nop.i 0 340} 341;; 342 343// Divide arguments into the following categories: 344// Certain Underflow p11 - -inf < x <= MAX_SGL_ZERO_ARG 345// Possible Underflow p13 - MAX_SGL_ZERO_ARG < x < MIN_SGL_NORM_ARG 346// Certain Safe - MIN_SGL_NORM_ARG <= x <= MAX_SGL_NORM_ARG 347// Possible Overflow p14 - MAX_SGL_NORM_ARG < x < MIN_SGL_OFLOW_ARG 348// Certain Overflow p15 - MIN_SGL_OFLOW_ARG <= x < +inf 349// 350// If the input is really a single arg, then there will never be 351// "Possible Overflow" arguments. 352// 353 354{ .mfi 355 nop.m 0 356 // check for overflow 357 fcmp.ge.s1 p15, p0 = fNormX, fMIN_SGL_OFLOW_ARG 358 nop.i 0 359} 360;; 361 362{ .mfi 363 nop.m 0 364 // check for underflow and tiny (+0) result 365 fcmp.le.s1 p11, p0 = fNormX, fMAX_SGL_ZERO_ARG 366 nop.i 0 367} 368{ .mfb 369 nop.m 0 370 fms.s1 fN = fNint, f1, fRightShifter // n in FP register 371 // branch out if overflow 372(p15) br.cond.spnt EXP_CERTAIN_OVERFLOW 373} 374;; 375 376{ .mfb 377 getf.sig rNJ = fNint // bits of n, j 378 // check for underflow and deno result 379 fcmp.lt.s1 p13, p0 = fNormX, fMIN_SGL_NORM_ARG 380 // branch out if underflow and tiny (+0) result 381(p11) br.cond.spnt EXP_CERTAIN_UNDERFLOW 382} 383;; 384 385{ .mfi 386 nop.m 0 387 // check for possible overflow 388 fcmp.gt.s1 p14, p0 = fNormX, fMAX_SGL_NORM_ARG 389 extr.u rJ = rNJ, 0, 6 // bits of j 390} 391{ .mfi 392 addl rN = 0xFFFF - 63, rNJ // biased and shifted n 393 fnma.s1 fR = fLn2Div64, fN, fNormX // R = x - N*ln(2)/64 394 nop.i 0 395} 396;; 397 398{ .mfi 399 shladd rJ = rJ, 3, rTblAddr // address in the 2^(j/64) table 400 nop.f 0 401 shr rN = rN, 6 // biased n 402} 403;; 404 405{ .mfi 406 ld8 rJ = [rJ] 407 nop.f 0 408 shl rN = rN, 52 // 2^n bits in DP format 409} 410;; 411 412{ .mfi 413 or rN = rN, rJ // bits of 2^n * 2^(j/64) in DP format 414 nop.f 0 415 nop.i 0 416} 417;; 418 419{ .mfi 420 setf.d fT = rN // 2^n * 2^(j/64) 421 fma.s1 fP = fA3, fR, fA2 // A3*R + A2 422 nop.i 0 423} 424{ .mfi 425 nop.m 0 426 fma.s1 fRSqr = fR, fR, f0 // R^2 427 nop.i 0 428} 429;; 430 431{ .mfi 432 nop.m 0 433 fma.s1 fP = fP, fRSqr, fR // P = (A3*R + A2)*R^2 + R 434 nop.i 0 435} 436;; 437 438{ .mbb 439 nop.m 0 440 // branch out if possible underflow 441(p13) br.cond.spnt EXP_POSSIBLE_UNDERFLOW 442 // branch out if possible overflow result 443(p14) br.cond.spnt EXP_POSSIBLE_OVERFLOW 444} 445;; 446 447{ .mfb 448 nop.m 0 449 // final result in the absence of over- and underflow 450 fma.s.s0 f8 = fP, fT, fT 451 // exit here in the absence of over- and underflow 452 br.ret.sptk b0 453} 454;; 455 456EXP_POSSIBLE_OVERFLOW: 457 458// Here if fMAX_SGL_NORM_ARG < x < fMIN_SGL_OFLOW_ARG 459// This cannot happen if input is a single, only if input higher precision. 460// Overflow is a possibility, not a certainty. 461 462// Recompute result using status field 2 with user's rounding mode, 463// and wre set. If result is larger than largest single, then we have 464// overflow 465 466{ .mfi 467 mov rGt_ln = 0x1007f // Exponent for largest single + 1 ulp 468 fsetc.s2 0x7F,0x42 // Get user's round mode, set wre 469 nop.i 0 470} 471;; 472 473{ .mfi 474 setf.exp fGt_pln = rGt_ln // Create largest single + 1 ulp 475 fma.s.s2 fWre_urm_f8 = fP, fT, fT // Result with wre set 476 nop.i 0 477} 478;; 479 480{ .mfi 481 nop.m 0 482 fsetc.s2 0x7F,0x40 // Turn off wre in sf2 483 nop.i 0 484} 485;; 486 487{ .mfi 488 nop.m 0 489 fcmp.ge.s1 p6, p0 = fWre_urm_f8, fGt_pln // Test for overflow 490 nop.i 0 491} 492;; 493 494{ .mfb 495 nop.m 0 496 nop.f 0 497(p6) br.cond.spnt EXP_CERTAIN_OVERFLOW // Branch if overflow 498} 499;; 500 501{ .mfb 502 nop.m 0 503 fma.s.s0 f8 = fP, fT, fT 504 br.ret.sptk b0 // Exit if really no overflow 505} 506;; 507 508// here if overflow 509EXP_CERTAIN_OVERFLOW: 510{ .mmi 511 addl r17ones_m1 = 0x1FFFE, r0 512;; 513 setf.exp fTmp = r17ones_m1 514 nop.i 0 515} 516;; 517 518{ .mfi 519 alloc r32=ar.pfs,0,3,4,0 520 fmerge.s FR_X = f8,f8 521 nop.i 0 522} 523{ .mfb 524 mov GR_Parameter_TAG = 16 525 fma.s.s0 FR_RESULT = fTmp, fTmp, fTmp // Set I,O and +INF result 526 br.cond.sptk __libm_error_region 527} 528;; 529 530EXP_POSSIBLE_UNDERFLOW: 531 532// Here if fMAX_SGL_ZERO_ARG < x < fMIN_SGL_NORM_ARG 533// Underflow is a possibility, not a certainty 534 535// We define an underflow when the answer with 536// ftz set 537// is zero (tiny numbers become zero) 538 539// Notice (from below) that if we have an unlimited exponent range, 540// then there is an extra machine number E between the largest denormal and 541// the smallest normal. 542 543// So if with unbounded exponent we round to E or below, then we are 544// tiny and underflow has occurred. 545 546// But notice that you can be in a situation where we are tiny, namely 547// rounded to E, but when the exponent is bounded we round to smallest 548// normal. So the answer can be the smallest normal with underflow. 549 550// E 551// -----+--------------------+--------------------+----- 552// | | | 553// 1.1...10 2^-3fff 1.1...11 2^-3fff 1.0...00 2^-3ffe 554// 0.1...11 2^-3ffe (biased, 1) 555// largest dn smallest normal 556 557{ .mfi 558 nop.m 0 559 fsetc.s2 0x7F,0x41 // Get user's round mode, set ftz 560 nop.i 0 561} 562;; 563 564{ .mfi 565 nop.m 0 566 fma.s.s2 fFtz_urm_f8 = fP, fT, fT // Result with ftz set 567 nop.i 0 568} 569;; 570 571{ .mfi 572 nop.m 0 573 fsetc.s2 0x7F,0x40 // Turn off ftz in sf2 574 nop.i 0 575} 576;; 577 578{ .mfi 579 nop.m 0 580 fcmp.eq.s1 p6, p7 = fFtz_urm_f8, f0 // Test for underflow 581 nop.i 0 582} 583{ .mfi 584 nop.m 0 585 fma.s.s0 f8 = fP, fT, fT // Compute result, set I, maybe U 586 nop.i 0 587} 588;; 589 590{ .mbb 591 nop.m 0 592(p6) br.cond.spnt EXP_UNDERFLOW_COMMON // Branch if really underflow 593(p7) br.ret.sptk b0 // Exit if really no underflow 594} 595;; 596 597EXP_CERTAIN_UNDERFLOW: 598// Here if x < fMAX_SGL_ZERO_ARG 599// Result will be zero (or smallest denorm if round to +inf) with I, U set 600{ .mmi 601 mov rTmp = 1 602;; 603 setf.exp fTmp = rTmp // Form small normal 604 nop.i 0 605} 606;; 607 608{ .mfi 609 nop.m 0 610 fmerge.se fTmp = fTmp, f64DivLn2 // Small with non-trial signif 611 nop.i 0 612} 613;; 614 615{ .mfb 616 nop.m 0 617 fma.s.s0 f8 = fTmp, fTmp, f0 // Set I,U, tiny (+0.0) result 618 br.cond.sptk EXP_UNDERFLOW_COMMON 619} 620;; 621 622EXP_UNDERFLOW_COMMON: 623// Determine if underflow result is zero or nonzero 624{ .mfi 625 alloc r32=ar.pfs,0,3,4,0 626 fcmp.eq.s1 p6, p0 = f8, f0 627 nop.i 0 628} 629;; 630 631{ .mfb 632 nop.m 0 633 fmerge.s FR_X = fNormX,fNormX 634(p6) br.cond.spnt EXP_UNDERFLOW_ZERO 635} 636;; 637 638EXP_UNDERFLOW_NONZERO: 639// Here if x < fMIN_SGL_NORM_ARG and result nonzero; 640// I, U are set 641{ .mfb 642 mov GR_Parameter_TAG = 17 643 nop.f 0 // FR_RESULT already set 644 br.cond.sptk __libm_error_region 645} 646;; 647 648EXP_UNDERFLOW_ZERO: 649// Here if x < fMIN_SGL_NORM_ARG and result zero; 650// I, U are set 651{ .mfb 652 mov GR_Parameter_TAG = 17 653 nop.f 0 // FR_RESULT already set 654 br.cond.sptk __libm_error_region 655} 656;; 657 658GLOBAL_IEEE754_END(expf) 659libm_alias_float_other (__exp, exp) 660#ifdef SHARED 661.symver expf,expf@@GLIBC_2.27 662.weak __expf_compat 663.set __expf_compat,__expf 664.symver __expf_compat,expf@GLIBC_2.2 665#endif 666 667 668LOCAL_LIBM_ENTRY(__libm_error_region) 669.prologue 670{ .mfi 671 add GR_Parameter_Y=-32,sp // Parameter 2 value 672 nop.f 0 673.save ar.pfs,GR_SAVE_PFS 674 mov GR_SAVE_PFS=ar.pfs // Save ar.pfs 675} 676{ .mfi 677.fframe 64 678 add sp=-64,sp // Create new stack 679 nop.f 0 680 mov GR_SAVE_GP=gp // Save gp 681};; 682{ .mmi 683 stfs [GR_Parameter_Y] = FR_Y,16 // Store Parameter 2 on stack 684 add GR_Parameter_X = 16,sp // Parameter 1 address 685.save b0, GR_SAVE_B0 686 mov GR_SAVE_B0=b0 // Save b0 687};; 688.body 689{ .mfi 690 stfs [GR_Parameter_X] = FR_X // Store Parameter 1 on stack 691 nop.f 0 692 add GR_Parameter_RESULT = 0,GR_Parameter_Y // Parameter 3 address 693} 694{ .mib 695 stfs [GR_Parameter_Y] = FR_RESULT // Store Parameter 3 on stack 696 add GR_Parameter_Y = -16,GR_Parameter_Y 697 br.call.sptk b0=__libm_error_support# // Call error handling function 698};; 699 700{ .mmi 701 add GR_Parameter_RESULT = 48,sp 702 nop.m 0 703 nop.i 0 704};; 705 706{ .mmi 707 ldfs f8 = [GR_Parameter_RESULT] // Get return result off stack 708.restore sp 709 add sp = 64,sp // Restore stack pointer 710 mov b0 = GR_SAVE_B0 // Restore return address 711};; 712{ .mib 713 mov gp = GR_SAVE_GP // Restore gp 714 mov ar.pfs = GR_SAVE_PFS // Restore ar.pfs 715 br.ret.sptk b0 // Return 716};; 717 718LOCAL_LIBM_END(__libm_error_region) 719 720 721.type __libm_error_support#,@function 722.global __libm_error_support# 723