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 _putmxcsr(), _getmxcsr();
  37         int csr;
  38         double z;
  39 
  40         _putmxcsr(CSR_DEFAULT);
  41         z = x * y;
  42         _getmxcsr(&csr);
  43         if ((csr & 0x3f) == 0) {
  44                 *pe = 0;
  45         } else {
  46                 *pe = 1;
  47         }
  48         return (z);
  49 }
  50 
  51  */
  52         ENTRY(__mul_set)
  53         xorl    %eax, %eax      /* Zero-out eax for later... */
  54         subq    $0x4, %rsp
  55         movl    $0x1f80, (%rsp) /* 0x1f80 == CSR_DEFAULT. */
  56         /* Set the MXCSR to its default (i.e. No FP exceptions). */
  57         ldmxcsr (%rsp)  /* Essentially _putmxcsr(CSR_DEFAULT); */
  58         
  59         mulsd   %xmm1, %xmm0    /* Do the multiply. */
  60         
  61         /* Check to see if the multiply caused any exceptions. */
  62         stmxcsr (%rsp)  /* Essentially do _getmxcsr(). */
  63         andl    $0x3f, (%rsp)   /* Check it. */
  64         setne   %al             /* Boolean FP exception indicator for *pe. */
  65         movl    %eax, (%rdi)
  66         addq    $0x4, %rsp
  67         ret
  68         SET_SIZE(__mul_set)
  69 
  70 /*
  71  * Divides two normal or subnormal doubles x/y, returns result and exceptions.
  72  *
  73 
  74 double
  75 __div_set(double x, double y, int *pe) {
  76         extern void _putmxcsr(), _getmxcsr();
  77         int csr;
  78         double z;
  79 
  80         _putmxcsr(CSR_DEFAULT);
  81         z = x / y;
  82         _getmxcsr(&csr);
  83         if ((csr & 0x3f) == 0) {
  84                 *pe = 0;
  85         } else {
  86                 *pe = 1;
  87         }
  88         return (z);
  89 }
  90 
  91  */
  92         
  93         ENTRY(__div_set)
  94         xorl    %eax, %eax      /* Zero-out eax for later... */
  95         subq    $0x4, %rsp
  96         movl    $0x1f80, (%rsp) /* 0x1f80 == CSR_DEFAULT. */
  97         /* Set the MXCSR to its default (i.e. No FP exceptions). */
  98         ldmxcsr (%rsp)  /* Essentially _putmxcsr(CSR_DEFAULT); */
  99         
 100         divsd   %xmm1, %xmm0    /* Do the divide. */
 101         
 102         /* Check to see if the divide caused any exceptions. */
 103         stmxcsr (%rsp)  /* Essentially do _getmxcsr(). */
 104         andl    $0x3f, (%rsp)   /* Check it. */
 105         setne   %al             /* Boolean FP exception indicator for *pe. */
 106         movl    %eax, (%rdi)
 107         addq    $0x4, %rsp
 108         ret
 109         SET_SIZE(__div_set)
 110 
 111 /* double __dabs(double *d) - Get the abs. value of *d.  Straightforward. */
 112 
 113         ENTRY(__dabs)
 114         subq    $0x8, %rsp
 115         movq    (%rdi), %rax    /* Zero the sign bit of the 64-bit double. */
 116         btrq    $63, %rax
 117         movq    %rax, (%rsp)    /* Get it into %xmm0... */
 118         movsd   (%rsp), %xmm0   /* ....for an amd64 "double" return. */
 119         addq    $0x8, %rsp
 120         ret
 121         SET_SIZE(__dabs)