1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved.
  14  */
  15 
  16         .file   "_base_il.s"
  17 
  18 /*
  19  * These files are in assembly because some compilers will mistakenly reorder
  20  * multiplications or divisions wrapped in _putsw() and _getsw().  They are
  21  * proper subroutines for now, but should be considered candidates for
  22  * inlining eventually.
  23  *
  24  * The original C sources are included for readability in the pre-function
  25  * comment blocks.
  26  */
  27 
  28 #include <SYS.h>
  29 
  30 /*
  31  * Multiplies two normal or subnormal doubles, returns result and exceptions.
  32  *
  33 
  34 double
  35 __mul_set(double x, double y, int *pe) {
  36         extern void _putsw(), _getsw();
  37         int sw;
  38         double z;
  39 
  40         _putsw(0);
  41         z = x * y;
  42         _getsw(&sw);
  43         if ((sw & 0x3f) == 0) {
  44                 *pe = 0;
  45         } else {
  46                 *pe = 1;
  47         }
  48         return (z);
  49 }
  50 
  51  */
  52         ENTRY(__mul_set)
  53         subl    $0x8, %esp      /* Give us an extra 8 bytes to play with. */
  54         /* Clear the floating point exception register. */
  55         fnclex                  /* Equivalent of _putsw(0); */
  56         
  57         fldl    0xc(%esp)       /* Load up x */
  58         fmull   0x14(%esp)      /* And multiply! */
  59         
  60         /* Check to see if the multiply caused any exceptions. */
  61         fstsw   (%esp)          /* Equivalent of... */
  62         xorl    %edx, %edx
  63         andl    $0x3f, (%esp)   /* If the status word (low bits) are zero... */
  64         setne   %dl             /* ... set *pe (aka. (%eax)) accordingly. */
  65         movl    0x1c(%esp), %eax/* Get pe. */
  66         movl    %edx, (%eax)    /* And set it.  (True == FP exception). */
  67         addl    $0x8, %esp      /* Release the 8 play bytes. */
  68         ret
  69         SET_SIZE(__mul_set)
  70 
  71 /*
  72  * Divides two normal or subnormal doubles x/y, returns result and exceptions.
  73  *
  74 
  75 double
  76 __div_set(double x, double y, int *pe) {
  77         extern void _putsw(), _getsw();
  78         int sw;
  79         double z;
  80 
  81         _putsw(0);
  82         z = x / y;
  83         _getsw(&sw);
  84         if ((sw & 0x3f) == 0) {
  85                 *pe = 0;
  86         } else {
  87                 *pe = 1;
  88         }
  89         return (z);
  90 }
  91 
  92  */
  93         
  94         ENTRY(__div_set)
  95         subl    $0x8, %esp      /* Give us an extra 8 bytes to play with. */
  96         /* Clear the floating point exception register. */
  97         fnclex                  /* Equivalent of _putsw(0); */
  98         
  99         fldl    0xc(%esp)       /* Load up x */
 100         fdivl   0x14(%esp)      /* And divide! */
 101         
 102         /* Check to see if the divide caused any exceptions. */
 103         fstsw   (%esp)          /* Equivalent of... */
 104         xorl    %edx, %edx
 105         andl    $0x3f, (%esp)   /* If the status word (low bits) are zero... */
 106         setne   %dl             /* ... set *pe (aka. (%eax)) accordingly. */
 107         movl    0x1c(%esp), %eax/* Get pe. */
 108         movl    %edx, (%eax)    /* And set it.  (True == FP exception). */
 109         addl    $0x8, %esp      /* Release the 8 play bytes. */
 110         ret
 111         SET_SIZE(__div_set)
 112 
 113 /* double __dabs(double *d) - Get the abs. value of *d.  Straightforward. */
 114 
 115         ENTRY(__dabs)
 116         movl    0x4(%esp), %eax
 117         fldl    (%eax)
 118         fabs                    /* Just let the FPU do its thing. */
 119         ret
 120         SET_SIZE(__dabs)