-(progn
-
-;;; Let's use some of the 80387 special functions.
-;;;
-;;; These defs will not take effect unless code/irrat.lisp is modified
-;;; to remove the inlined alien routine def.
-
-(macrolet ((frob (func trans op)
- `(define-vop (,func)
- (:args (x :scs (double-reg) :target fr0))
- (:temporary (:sc double-reg :offset fr0-offset
- :from :argument :to :result) fr0)
- (:ignore fr0)
- (:results (y :scs (double-reg)))
- (:arg-types double-float)
- (:result-types double-float)
- (:translate ,trans)
- (:policy :fast-safe)
- (:note "inline NPX function")
- (:vop-var vop)
- (:save-p :compute-only)
- (:node-var node)
- (:generator 5
- (note-this-location vop :internal-error)
- (unless (zerop (tn-offset x))
- (inst fxch x) ; x to top of stack
- (unless (location= x y)
- (inst fst x))) ; maybe save it
- (inst ,op) ; clobber st0
- (cond ((zerop (tn-offset y))
- (maybe-fp-wait node))
- (t
- (inst fst y)))))))
-
- ;; Quick versions of fsin and fcos that require the argument to be
- ;; within range 2^63.
- (frob fsin-quick %sin-quick fsin)
- (frob fcos-quick %cos-quick fcos)
- (frob fsqrt %sqrt fsqrt))
-
-;;; Quick version of ftan that requires the argument to be within
-;;; range 2^63.
-(define-vop (ftan-quick)
- (:translate %tan-quick)
- (:args (x :scs (double-reg) :target fr0))
- (:temporary (:sc double-reg :offset fr0-offset
- :from :argument :to :result) fr0)
- (:temporary (:sc double-reg :offset fr1-offset
- :from :argument :to :result) fr1)
- (:results (y :scs (double-reg)))
- (:arg-types double-float)
- (:result-types double-float)
- (:policy :fast-safe)
- (:note "inline tan function")
- (:vop-var vop)
- (:save-p :compute-only)
- (:generator 5
- (note-this-location vop :internal-error)
- (case (tn-offset x)
- (0
- (inst fstp fr1))
- (1
- (inst fstp fr0))
- (t
- (inst fstp fr0)
- (inst fstp fr0)
- (inst fldd (make-random-tn :kind :normal
- :sc (sc-or-lose 'double-reg)
- :offset (- (tn-offset x) 2)))))
- (inst fptan)
- ;; Result is in fr1
- (case (tn-offset y)
- (0
- (inst fxch fr1))
- (1)
- (t
- (inst fxch fr1)
- (inst fstd y)))))
-
-;;; These versions of fsin, fcos, and ftan try to use argument
-;;; reduction but to do this accurately requires greater precision and
-;;; it is hopelessly inaccurate.
-#+nil
-(macrolet ((frob (func trans op)
- `(define-vop (,func)
- (:translate ,trans)
- (:args (x :scs (double-reg) :target fr0))
- (:temporary (:sc unsigned-reg :offset eax-offset
- :from :eval :to :result) eax)
- (:temporary (:sc unsigned-reg :offset fr0-offset
- :from :argument :to :result) fr0)
- (:temporary (:sc unsigned-reg :offset fr1-offset
- :from :argument :to :result) fr1)
- (:results (y :scs (double-reg)))
- (:arg-types double-float)
- (:result-types double-float)
- (:policy :fast-safe)
- (:note "inline sin/cos function")
- (:vop-var vop)
- (:save-p :compute-only)
- (:ignore eax)
- (:generator 5
- (note-this-location vop :internal-error)
- (unless (zerop (tn-offset x))
- (inst fxch x) ; x to top of stack
- (unless (location= x y)
- (inst fst x))) ; maybe save it
- (inst ,op)
- (inst fnstsw) ; status word to ax
- (inst and ah-tn #x04) ; C2
- (inst jmp :z DONE)
- ;; Else x was out of range so reduce it; ST0 is unchanged.
- (inst fstp fr1) ; Load 2*PI
- (inst fldpi)
- (inst fadd fr0)
- (inst fxch fr1)
- LOOP
- (inst fprem1)
- (inst fnstsw) ; status word to ax
- (inst and ah-tn #x04) ; C2
- (inst jmp :nz LOOP)
- (inst ,op)
- DONE
- (unless (zerop (tn-offset y))
- (inst fstd y))))))
- (frob fsin %sin fsin)
- (frob fcos %cos fcos))
-
-
-
-;;; These versions of fsin, fcos, and ftan simply load a 0.0 result if
-;;; the argument is out of range 2^63 and would thus be hopelessly
-;;; inaccurate.
-(macrolet ((frob (func trans op)
- `(define-vop (,func)
- (:translate ,trans)
- (:args (x :scs (double-reg) :target fr0))
- (:temporary (:sc double-reg :offset fr0-offset
- :from :argument :to :result) fr0)
- (:temporary (:sc unsigned-reg :offset eax-offset
- :from :argument :to :result) eax)
- (:results (y :scs (double-reg)))
- (:arg-types double-float)
- (:result-types double-float)
- (:policy :fast-safe)
- (:note "inline sin/cos function")
- (:vop-var vop)
- (:save-p :compute-only)
- (:ignore eax)
- (:generator 5
- (note-this-location vop :internal-error)
- (unless (zerop (tn-offset x))
- (inst fxch x) ; x to top of stack
- (unless (location= x y)
- (inst fst x))) ; maybe save it
- (inst ,op)
- (inst fnstsw) ; status word to ax
- (inst and ah-tn #x04) ; C2
- (inst jmp :z DONE)
- ;; Else x was out of range so reduce it; ST0 is unchanged.
- (inst fstp fr0) ; Load 0.0
- (inst fldz)
- DONE
- (unless (zerop (tn-offset y))
- (inst fstd y))))))
- (frob fsin %sin fsin)
- (frob fcos %cos fcos))
-
-(define-vop (ftan)
- (:translate %tan)
- (:args (x :scs (double-reg) :target fr0))
- (:temporary (:sc double-reg :offset fr0-offset
- :from :argument :to :result) fr0)
- (:temporary (:sc double-reg :offset fr1-offset
- :from :argument :to :result) fr1)
- (:temporary (:sc unsigned-reg :offset eax-offset
- :from :argument :to :result) eax)
- (:results (y :scs (double-reg)))
- (:arg-types double-float)
- (:result-types double-float)
- (:ignore eax)
- (:policy :fast-safe)
- (:note "inline tan function")
- (:vop-var vop)
- (:save-p :compute-only)
- (:ignore eax)
- (:generator 5
- (note-this-location vop :internal-error)
- (case (tn-offset x)
- (0
- (inst fstp fr1))
- (1
- (inst fstp fr0))
- (t
- (inst fstp fr0)
- (inst fstp fr0)
- (inst fldd (make-random-tn :kind :normal
- :sc (sc-or-lose 'double-reg)
- :offset (- (tn-offset x) 2)))))
- (inst fptan)
- (inst fnstsw) ; status word to ax
- (inst and ah-tn #x04) ; C2
- (inst jmp :z DONE)
- ;; Else x was out of range so reduce it; ST0 is unchanged.
- (inst fldz) ; Load 0.0
- (inst fxch fr1)
- DONE
- ;; Result is in fr1
- (case (tn-offset y)
- (0
- (inst fxch fr1))
- (1)
- (t
- (inst fxch fr1)
- (inst fstd y)))))
-
-#+nil
-(define-vop (fexp)
- (:translate %exp)
- (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
- (:temporary (:sc double-reg :offset fr0-offset
- :from :argument :to :result) fr0)
- (:temporary (:sc double-reg :offset fr1-offset
- :from :argument :to :result) fr1)
- (:temporary (:sc double-reg :offset fr2-offset
- :from :argument :to :result) fr2)
- (:results (y :scs (double-reg)))
- (:arg-types double-float)
- (:result-types double-float)
- (:policy :fast-safe)
- (:note "inline exp function")
- (:vop-var vop)
- (:save-p :compute-only)
- (:generator 5
- (note-this-location vop :internal-error)
- (sc-case x
- (double-reg
- (cond ((zerop (tn-offset x))
- ;; x is in fr0
- (inst fstp fr1)
- (inst fldl2e)
- (inst fmul fr1))
- (t
- ;; x is in a FP reg, not fr0
- (inst fstp fr0)
- (inst fldl2e)
- (inst fmul x))))
- ((double-stack descriptor-reg)
- (inst fstp fr0)
- (inst fldl2e)
- (if (sc-is x double-stack)
- (inst fmuld (ea-for-df-stack x))
- (inst fmuld (ea-for-df-desc x)))))
- ;; Now fr0=x log2(e)
- (inst fst fr1)
- (inst frndint)
- (inst fst fr2)
- (inst fsubp-sti fr1)
- (inst f2xm1)
- (inst fld1)
- (inst faddp-sti fr1)
- (inst fscale)
- (inst fld fr0)
- (case (tn-offset y)
- ((0 1))
- (t (inst fstd y)))))
-
-;;; Modified exp that handles the following special cases:
-;;; exp(+Inf) is +Inf; exp(-Inf) is 0; exp(NaN) is NaN.
-(define-vop (fexp)
- (:translate %exp)
- (:args (x :scs (double-reg) :target fr0))
- (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
- (:temporary (:sc double-reg :offset fr0-offset
- :from :argument :to :result) fr0)
- (:temporary (:sc double-reg :offset fr1-offset
- :from :argument :to :result) fr1)
- (:temporary (:sc double-reg :offset fr2-offset
- :from :argument :to :result) fr2)
- (:results (y :scs (double-reg)))
- (:arg-types double-float)
- (:result-types double-float)
- (:policy :fast-safe)
- (:note "inline exp function")
- (:vop-var vop)
- (:save-p :compute-only)
- (:ignore temp)
- (:generator 5
- (note-this-location vop :internal-error)
- (unless (zerop (tn-offset x))
- (inst fxch x) ; x to top of stack
- (unless (location= x y)
- (inst fst x))) ; maybe save it
- ;; Check for Inf or NaN
- (inst fxam)
- (inst fnstsw)
- (inst sahf)
- (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
- (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
- (inst and ah-tn #x02) ; Test sign of Inf.
- (inst jmp :z DONE) ; +Inf gives +Inf.
- (inst fstp fr0) ; -Inf gives 0
- (inst fldz)
- (inst jmp-short DONE)
- NOINFNAN
- (inst fstp fr1)
- (inst fldl2e)
- (inst fmul fr1)
- ;; Now fr0=x log2(e)
- (inst fst fr1)
- (inst frndint)
- (inst fst fr2)
- (inst fsubp-sti fr1)
- (inst f2xm1)
- (inst fld1)
- (inst faddp-sti fr1)
- (inst fscale)
- (inst fld fr0)
- DONE
- (unless (zerop (tn-offset y))
- (inst fstd y))))
-
-;;; Expm1 = exp(x) - 1.
-;;; Handles the following special cases:
-;;; expm1(+Inf) is +Inf; expm1(-Inf) is -1.0; expm1(NaN) is NaN.
-(define-vop (fexpm1)
- (:translate %expm1)
- (:args (x :scs (double-reg) :target fr0))
- (:temporary (:sc word-reg :offset eax-offset :from :eval :to :result) temp)
- (:temporary (:sc double-reg :offset fr0-offset
- :from :argument :to :result) fr0)
- (:temporary (:sc double-reg :offset fr1-offset
- :from :argument :to :result) fr1)
- (:temporary (:sc double-reg :offset fr2-offset
- :from :argument :to :result) fr2)
- (:results (y :scs (double-reg)))
- (:arg-types double-float)
- (:result-types double-float)
- (:policy :fast-safe)
- (:note "inline expm1 function")
- (:vop-var vop)
- (:save-p :compute-only)
- (:ignore temp)
- (:generator 5
- (note-this-location vop :internal-error)
- (unless (zerop (tn-offset x))
- (inst fxch x) ; x to top of stack
- (unless (location= x y)
- (inst fst x))) ; maybe save it
- ;; Check for Inf or NaN
- (inst fxam)
- (inst fnstsw)
- (inst sahf)
- (inst jmp :nc NOINFNAN) ; Neither Inf or NaN.
- (inst jmp :np NOINFNAN) ; NaN gives NaN? Continue.
- (inst and ah-tn #x02) ; Test sign of Inf.
- (inst jmp :z DONE) ; +Inf gives +Inf.
- (inst fstp fr0) ; -Inf gives -1.0
- (inst fld1)
- (inst fchs)
- (inst jmp-short DONE)
- NOINFNAN
- ;; Free two stack slots leaving the argument on top.
- (inst fstp fr2)
- (inst fstp fr0)
- (inst fldl2e)
- (inst fmul fr1) ; Now fr0 = x log2(e)
- (inst fst fr1)
- (inst frndint)
- (inst fsub-sti fr1)
- (inst fxch fr1)
- (inst f2xm1)
- (inst fscale)
- (inst fxch fr1)
- (inst fld1)
- (inst fscale)
- (inst fstp fr1)
- (inst fld1)
- (inst fsub fr1)
- (inst fsubr fr2)
- DONE
- (unless (zerop (tn-offset y))
- (inst fstd y))))
-
-(define-vop (flog)
- (:translate %log)
- (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
- (:temporary (:sc double-reg :offset fr0-offset
- :from :argument :to :result) fr0)
- (:temporary (:sc double-reg :offset fr1-offset
- :from :argument :to :result) fr1)
- (:results (y :scs (double-reg)))
- (:arg-types double-float)
- (:result-types double-float)
- (:policy :fast-safe)
- (:note "inline log function")
- (:vop-var vop)
- (:save-p :compute-only)
- (:generator 5
- (note-this-location vop :internal-error)
- (sc-case x
- (double-reg
- (case (tn-offset x)
- (0
- ;; x is in fr0
- (inst fstp fr1)
- (inst fldln2)
- (inst fxch fr1))
- (1
- ;; x is in fr1
- (inst fstp fr0)
- (inst fldln2)
- (inst fxch fr1))
- (t
- ;; x is in a FP reg, not fr0 or fr1
- (inst fstp fr0)
- (inst fstp fr0)
- (inst fldln2)
- (inst fldd (make-random-tn :kind :normal
- :sc (sc-or-lose 'double-reg)
- :offset (1- (tn-offset x))))))
- (inst fyl2x))
- ((double-stack descriptor-reg)
- (inst fstp fr0)
- (inst fstp fr0)
- (inst fldln2)
- (if (sc-is x double-stack)
- (inst fldd (ea-for-df-stack x))
- (inst fldd (ea-for-df-desc x)))
- (inst fyl2x)))
- (inst fld fr0)
- (case (tn-offset y)
- ((0 1))
- (t (inst fstd y)))))
-
-(define-vop (flog10)
- (:translate %log10)
- (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
- (:temporary (:sc double-reg :offset fr0-offset
- :from :argument :to :result) fr0)
- (:temporary (:sc double-reg :offset fr1-offset
- :from :argument :to :result) fr1)
- (:results (y :scs (double-reg)))
- (:arg-types double-float)
- (:result-types double-float)
- (:policy :fast-safe)
- (:note "inline log10 function")
- (:vop-var vop)
- (:save-p :compute-only)
- (:generator 5
- (note-this-location vop :internal-error)
- (sc-case x
- (double-reg
- (case (tn-offset x)
- (0
- ;; x is in fr0
- (inst fstp fr1)
- (inst fldlg2)
- (inst fxch fr1))
- (1
- ;; x is in fr1
- (inst fstp fr0)
- (inst fldlg2)
- (inst fxch fr1))
- (t
- ;; x is in a FP reg, not fr0 or fr1
- (inst fstp fr0)
- (inst fstp fr0)
- (inst fldlg2)
- (inst fldd (make-random-tn :kind :normal
- :sc (sc-or-lose 'double-reg)
- :offset (1- (tn-offset x))))))
- (inst fyl2x))
- ((double-stack descriptor-reg)
- (inst fstp fr0)
- (inst fstp fr0)
- (inst fldlg2)
- (if (sc-is x double-stack)
- (inst fldd (ea-for-df-stack x))
- (inst fldd (ea-for-df-desc x)))
- (inst fyl2x)))
- (inst fld fr0)
- (case (tn-offset y)
- ((0 1))
- (t (inst fstd y)))))
-
-(define-vop (fpow)
- (:translate %pow)
- (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
- (y :scs (double-reg double-stack descriptor-reg) :target fr1))
- (:temporary (:sc double-reg :offset fr0-offset
- :from (:argument 0) :to :result) fr0)
- (:temporary (:sc double-reg :offset fr1-offset
- :from (:argument 1) :to :result) fr1)
- (:temporary (:sc double-reg :offset fr2-offset
- :from :load :to :result) fr2)
- (:results (r :scs (double-reg)))
- (:arg-types double-float double-float)
- (:result-types double-float)
- (:policy :fast-safe)
- (:note "inline pow function")
- (:vop-var vop)
- (:save-p :compute-only)
- (:generator 5
- (note-this-location vop :internal-error)
- ;; Setup x in fr0 and y in fr1
- (cond
- ;; x in fr0; y in fr1
- ((and (sc-is x double-reg) (zerop (tn-offset x))
- (sc-is y double-reg) (= 1 (tn-offset y))))
- ;; y in fr1; x not in fr0
- ((and (sc-is y double-reg) (= 1 (tn-offset y)))
- ;; Load x to fr0
- (sc-case x
- (double-reg
- (copy-fp-reg-to-fr0 x))
- (double-stack
- (inst fstp fr0)
- (inst fldd (ea-for-df-stack x)))
- (descriptor-reg
- (inst fstp fr0)
- (inst fldd (ea-for-df-desc x)))))
- ;; x in fr0; y not in fr1
- ((and (sc-is x double-reg) (zerop (tn-offset x)))
- (inst fxch fr1)
- ;; Now load y to fr0
- (sc-case y
- (double-reg
- (copy-fp-reg-to-fr0 y))
- (double-stack
- (inst fstp fr0)
- (inst fldd (ea-for-df-stack y)))
- (descriptor-reg
- (inst fstp fr0)
- (inst fldd (ea-for-df-desc y))))
- (inst fxch fr1))
- ;; x in fr1; y not in fr1
- ((and (sc-is x double-reg) (= 1 (tn-offset x)))
- ;; Load y to fr0
- (sc-case y
- (double-reg
- (copy-fp-reg-to-fr0 y))
- (double-stack
- (inst fstp fr0)
- (inst fldd (ea-for-df-stack y)))
- (descriptor-reg
- (inst fstp fr0)
- (inst fldd (ea-for-df-desc y))))
- (inst fxch fr1))
- ;; y in fr0;
- ((and (sc-is y double-reg) (zerop (tn-offset y)))
- (inst fxch fr1)
- ;; Now load x to fr0
- (sc-case x
- (double-reg
- (copy-fp-reg-to-fr0 x))
- (double-stack
- (inst fstp fr0)
- (inst fldd (ea-for-df-stack x)))
- (descriptor-reg
- (inst fstp fr0)
- (inst fldd (ea-for-df-desc x)))))
- ;; Neither x or y are in either fr0 or fr1
- (t
- ;; Load y then x
- (inst fstp fr0)
- (inst fstp fr0)
- (sc-case y
- (double-reg
- (inst fldd (make-random-tn :kind :normal
- :sc (sc-or-lose 'double-reg)
- :offset (- (tn-offset y) 2))))
- (double-stack
- (inst fldd (ea-for-df-stack y)))
- (descriptor-reg
- (inst fldd (ea-for-df-desc y))))
- ;; Load x to fr0
- (sc-case x
- (double-reg
- (inst fldd (make-random-tn :kind :normal
- :sc (sc-or-lose 'double-reg)
- :offset (1- (tn-offset x)))))
- (double-stack
- (inst fldd (ea-for-df-stack x)))
- (descriptor-reg
- (inst fldd (ea-for-df-desc x))))))
-
- ;; Now have x at fr0; and y at fr1
- (inst fyl2x)
- ;; Now fr0=y log2(x)
- (inst fld fr0)
- (inst frndint)
- (inst fst fr2)
- (inst fsubp-sti fr1)
- (inst f2xm1)
- (inst fld1)
- (inst faddp-sti fr1)
- (inst fscale)
- (inst fld fr0)
- (case (tn-offset r)
- ((0 1))
- (t (inst fstd r)))))
-
-(define-vop (fscalen)
- (:translate %scalbn)
- (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
- (y :scs (signed-stack signed-reg) :target temp))
- (:temporary (:sc double-reg :offset fr0-offset
- :from (:argument 0) :to :result) fr0)
- (:temporary (:sc double-reg :offset fr1-offset :from :eval :to :result) fr1)
- (:temporary (:sc signed-stack :from (:argument 1) :to :result) temp)
- (:results (r :scs (double-reg)))
- (:arg-types double-float signed-num)
- (:result-types double-float)
- (:policy :fast-safe)
- (:note "inline scalbn function")
- (:generator 5
- ;; Setup x in fr0 and y in fr1
- (sc-case x
- (double-reg
- (case (tn-offset x)
- (0
- (inst fstp fr1)
- (sc-case y
- (signed-reg
- (inst mov temp y)
- (inst fild temp))
- (signed-stack
- (inst fild y)))
- (inst fxch fr1))
- (1
- (inst fstp fr0)
- (sc-case y
- (signed-reg
- (inst mov temp y)
- (inst fild temp))
- (signed-stack
- (inst fild y)))
- (inst fxch fr1))
- (t
- (inst fstp fr0)
- (inst fstp fr0)
- (sc-case y
- (signed-reg
- (inst mov temp y)
- (inst fild temp))
- (signed-stack
- (inst fild y)))
- (inst fld (make-random-tn :kind :normal
- :sc (sc-or-lose 'double-reg)
- :offset (1- (tn-offset x)))))))
- ((double-stack descriptor-reg)
- (inst fstp fr0)
- (inst fstp fr0)
- (sc-case y
- (signed-reg
- (inst mov temp y)
- (inst fild temp))
- (signed-stack
- (inst fild y)))
- (if (sc-is x double-stack)
- (inst fldd (ea-for-df-stack x))
- (inst fldd (ea-for-df-desc x)))))
- (inst fscale)
- (unless (zerop (tn-offset r))
- (inst fstd r))))
-
-(define-vop (fscale)
- (:translate %scalb)
- (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0)
- (y :scs (double-reg double-stack descriptor-reg) :target fr1))
- (:temporary (:sc double-reg :offset fr0-offset
- :from (:argument 0) :to :result) fr0)
- (:temporary (:sc double-reg :offset fr1-offset
- :from (:argument 1) :to :result) fr1)
- (:results (r :scs (double-reg)))
- (:arg-types double-float double-float)
- (:result-types double-float)
- (:policy :fast-safe)
- (:note "inline scalb function")
- (:vop-var vop)
- (:save-p :compute-only)
- (:generator 5
- (note-this-location vop :internal-error)
- ;; Setup x in fr0 and y in fr1
- (cond
- ;; x in fr0; y in fr1
- ((and (sc-is x double-reg) (zerop (tn-offset x))
- (sc-is y double-reg) (= 1 (tn-offset y))))
- ;; y in fr1; x not in fr0
- ((and (sc-is y double-reg) (= 1 (tn-offset y)))
- ;; Load x to fr0
- (sc-case x
- (double-reg
- (copy-fp-reg-to-fr0 x))
- (double-stack
- (inst fstp fr0)
- (inst fldd (ea-for-df-stack x)))
- (descriptor-reg
- (inst fstp fr0)
- (inst fldd (ea-for-df-desc x)))))
- ;; x in fr0; y not in fr1
- ((and (sc-is x double-reg) (zerop (tn-offset x)))
- (inst fxch fr1)
- ;; Now load y to fr0
- (sc-case y
- (double-reg
- (copy-fp-reg-to-fr0 y))
- (double-stack
- (inst fstp fr0)
- (inst fldd (ea-for-df-stack y)))
- (descriptor-reg
- (inst fstp fr0)
- (inst fldd (ea-for-df-desc y))))
- (inst fxch fr1))
- ;; x in fr1; y not in fr1
- ((and (sc-is x double-reg) (= 1 (tn-offset x)))
- ;; Load y to fr0
- (sc-case y
- (double-reg
- (copy-fp-reg-to-fr0 y))
- (double-stack
- (inst fstp fr0)
- (inst fldd (ea-for-df-stack y)))
- (descriptor-reg
- (inst fstp fr0)
- (inst fldd (ea-for-df-desc y))))
- (inst fxch fr1))
- ;; y in fr0;
- ((and (sc-is y double-reg) (zerop (tn-offset y)))
- (inst fxch fr1)
- ;; Now load x to fr0
- (sc-case x
- (double-reg
- (copy-fp-reg-to-fr0 x))
- (double-stack
- (inst fstp fr0)
- (inst fldd (ea-for-df-stack x)))
- (descriptor-reg
- (inst fstp fr0)
- (inst fldd (ea-for-df-desc x)))))
- ;; Neither x or y are in either fr0 or fr1
- (t
- ;; Load y then x
- (inst fstp fr0)
- (inst fstp fr0)
- (sc-case y
- (double-reg
- (inst fldd (make-random-tn :kind :normal
- :sc (sc-or-lose 'double-reg)
- :offset (- (tn-offset y) 2))))
- (double-stack
- (inst fldd (ea-for-df-stack y)))
- (descriptor-reg
- (inst fldd (ea-for-df-desc y))))
- ;; Load x to fr0
- (sc-case x
- (double-reg
- (inst fldd (make-random-tn :kind :normal
- :sc (sc-or-lose 'double-reg)
- :offset (1- (tn-offset x)))))
- (double-stack
- (inst fldd (ea-for-df-stack x)))
- (descriptor-reg
- (inst fldd (ea-for-df-desc x))))))
-
- ;; Now have x at fr0; and y at fr1
- (inst fscale)
- (unless (zerop (tn-offset r))
- (inst fstd r))))
-
-(define-vop (flog1p)
- (:translate %log1p)
- (:args (x :scs (double-reg) :to :result))
- (:temporary (:sc double-reg :offset fr0-offset
- :from :argument :to :result) fr0)
- (:temporary (:sc double-reg :offset fr1-offset
- :from :argument :to :result) fr1)
- (:temporary (:sc word-reg :offset eax-offset :from :eval) temp)
- (:results (y :scs (double-reg)))
- (:arg-types double-float)
- (:result-types double-float)
- (:policy :fast-safe)
- (:note "inline log1p function")
- (:ignore temp)
- (:generator 5
- ;; x is in a FP reg, not fr0, fr1.
- (inst fstp fr0)
- (inst fstp fr0)
- (inst fldd (make-random-tn :kind :normal
- :sc (sc-or-lose 'double-reg)
- :offset (- (tn-offset x) 2)))
- ;; Check the range
- (inst push #x3e947ae1) ; Constant 0.29
- (inst fabs)
- (inst fld (make-ea :dword :base rsp-tn))
- (inst fcompp)
- (inst add rsp-tn 4)
- (inst fnstsw) ; status word to ax
- (inst and ah-tn #x45)
- (inst jmp :z WITHIN-RANGE)
- ;; Out of range for fyl2xp1.
- (inst fld1)
- (inst faddd (make-random-tn :kind :normal
- :sc (sc-or-lose 'double-reg)
- :offset (- (tn-offset x) 1)))
- (inst fldln2)
- (inst fxch fr1)
- (inst fyl2x)
- (inst jmp DONE)
-
- WITHIN-RANGE
- (inst fldln2)
- (inst fldd (make-random-tn :kind :normal
- :sc (sc-or-lose 'double-reg)
- :offset (- (tn-offset x) 1)))
- (inst fyl2xp1)
- DONE
- (inst fld fr0)
- (case (tn-offset y)
- ((0 1))
- (t (inst fstd y)))))
-
-;;; The Pentium has a less restricted implementation of the fyl2xp1
-;;; instruction and a range check can be avoided.
-(define-vop (flog1p-pentium)
- (:translate %log1p)
- (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
- (:temporary (:sc double-reg :offset fr0-offset
- :from :argument :to :result) fr0)
- (:temporary (:sc double-reg :offset fr1-offset
- :from :argument :to :result) fr1)
- (:results (y :scs (double-reg)))
- (:arg-types double-float)
- (:result-types double-float)
- (:policy :fast-safe)
- (:guard (member :pentium-style-fyl2xp1 *backend-subfeatures*))
- (:note "inline log1p with limited x range function")
- (:vop-var vop)
- (:save-p :compute-only)
- (:generator 4
- (note-this-location vop :internal-error)
- (sc-case x
- (double-reg
- (case (tn-offset x)
- (0
- ;; x is in fr0
- (inst fstp fr1)
- (inst fldln2)
- (inst fxch fr1))
- (1
- ;; x is in fr1
- (inst fstp fr0)
- (inst fldln2)
- (inst fxch fr1))
- (t
- ;; x is in a FP reg, not fr0 or fr1
- (inst fstp fr0)
- (inst fstp fr0)
- (inst fldln2)
- (inst fldd (make-random-tn :kind :normal
- :sc (sc-or-lose 'double-reg)
- :offset (1- (tn-offset x)))))))
- ((double-stack descriptor-reg)
- (inst fstp fr0)
- (inst fstp fr0)
- (inst fldln2)
- (if (sc-is x double-stack)
- (inst fldd (ea-for-df-stack x))
- (inst fldd (ea-for-df-desc x)))))
- (inst fyl2xp1)
- (inst fld fr0)
- (case (tn-offset y)
- ((0 1))
- (t (inst fstd y)))))
-
-(define-vop (flogb)
- (:translate %logb)
- (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
- (:temporary (:sc double-reg :offset fr0-offset
- :from :argument :to :result) fr0)
- (:temporary (:sc double-reg :offset fr1-offset
- :from :argument :to :result) fr1)
- (:results (y :scs (double-reg)))
- (:arg-types double-float)
- (:result-types double-float)
- (:policy :fast-safe)
- (:note "inline logb function")
- (:vop-var vop)
- (:save-p :compute-only)
- (:generator 5
- (note-this-location vop :internal-error)
- (sc-case x
- (double-reg
- (case (tn-offset x)
- (0
- ;; x is in fr0
- (inst fstp fr1))
- (1
- ;; x is in fr1
- (inst fstp fr0))
- (t
- ;; x is in a FP reg, not fr0 or fr1
- (inst fstp fr0)
- (inst fstp fr0)
- (inst fldd (make-random-tn :kind :normal
- :sc (sc-or-lose 'double-reg)
- :offset (- (tn-offset x) 2))))))
- ((double-stack descriptor-reg)
- (inst fstp fr0)
- (inst fstp fr0)
- (if (sc-is x double-stack)
- (inst fldd (ea-for-df-stack x))
- (inst fldd (ea-for-df-desc x)))))
- (inst fxtract)
- (case (tn-offset y)
- (0
- (inst fxch fr1))
- (1)
- (t (inst fxch fr1)
- (inst fstd y)))))
-
-(define-vop (fatan)
- (:translate %atan)
- (:args (x :scs (double-reg double-stack descriptor-reg) :target fr0))
- (:temporary (:sc double-reg :offset fr0-offset
- :from (:argument 0) :to :result) fr0)
- (:temporary (:sc double-reg :offset fr1-offset
- :from (:argument 0) :to :result) fr1)
- (:results (r :scs (double-reg)))
- (:arg-types double-float)
- (:result-types double-float)
- (:policy :fast-safe)
- (:note "inline atan function")
- (:vop-var vop)
- (:save-p :compute-only)
- (:generator 5
- (note-this-location vop :internal-error)
- ;; Setup x in fr1 and 1.0 in fr0
- (cond
- ;; x in fr0
- ((and (sc-is x double-reg) (zerop (tn-offset x)))
- (inst fstp fr1))
- ;; x in fr1
- ((and (sc-is x double-reg) (= 1 (tn-offset x)))
- (inst fstp fr0))
- ;; x not in fr0 or fr1
- (t
- ;; Load x then 1.0
- (inst fstp fr0)
- (inst fstp fr0)
- (sc-case x
- (double-reg
- (inst fldd (make-random-tn :kind :normal
- :sc (sc-or-lose 'double-reg)
- :offset (- (tn-offset x) 2))))
- (double-stack
- (inst fldd (ea-for-df-stack x)))
- (descriptor-reg
- (inst fldd (ea-for-df-desc x))))))
- (inst fld1)
- ;; Now have x at fr1; and 1.0 at fr0
- (inst fpatan)
- (inst fld fr0)
- (case (tn-offset r)
- ((0 1))
- (t (inst fstd r)))))
-
-(define-vop (fatan2)
- (:translate %atan2)
- (:args (x :scs (double-reg double-stack descriptor-reg) :target fr1)
- (y :scs (double-reg double-stack descriptor-reg) :target fr0))
- (:temporary (:sc double-reg :offset fr0-offset
- :from (:argument 1) :to :result) fr0)
- (:temporary (:sc double-reg :offset fr1-offset
- :from (:argument 0) :to :result) fr1)
- (:results (r :scs (double-reg)))
- (:arg-types double-float double-float)
- (:result-types double-float)
- (:policy :fast-safe)
- (:note "inline atan2 function")
- (:vop-var vop)
- (:save-p :compute-only)
- (:generator 5
- (note-this-location vop :internal-error)
- ;; Setup x in fr1 and y in fr0
- (cond
- ;; y in fr0; x in fr1
- ((and (sc-is y double-reg) (zerop (tn-offset y))
- (sc-is x double-reg) (= 1 (tn-offset x))))
- ;; x in fr1; y not in fr0
- ((and (sc-is x double-reg) (= 1 (tn-offset x)))
- ;; Load y to fr0
- (sc-case y
- (double-reg
- (copy-fp-reg-to-fr0 y))
- (double-stack
- (inst fstp fr0)
- (inst fldd (ea-for-df-stack y)))
- (descriptor-reg
- (inst fstp fr0)
- (inst fldd (ea-for-df-desc y)))))
- ((and (sc-is x double-reg) (zerop (tn-offset x))
- (sc-is y double-reg) (zerop (tn-offset x)))
- ;; copy x to fr1
- (inst fst fr1))
- ;; y in fr0; x not in fr1
- ((and (sc-is y double-reg) (zerop (tn-offset y)))
- (inst fxch fr1)
- ;; Now load x to fr0
- (sc-case x
- (double-reg
- (copy-fp-reg-to-fr0 x))
- (double-stack
- (inst fstp fr0)
- (inst fldd (ea-for-df-stack x)))
- (descriptor-reg
- (inst fstp fr0)
- (inst fldd (ea-for-df-desc x))))
- (inst fxch fr1))
- ;; y in fr1; x not in fr1
- ((and (sc-is y double-reg) (= 1 (tn-offset y)))
- ;; Load x to fr0
- (sc-case x
- (double-reg
- (copy-fp-reg-to-fr0 x))
- (double-stack
- (inst fstp fr0)
- (inst fldd (ea-for-df-stack x)))
- (descriptor-reg
- (inst fstp fr0)
- (inst fldd (ea-for-df-desc x))))
- (inst fxch fr1))
- ;; x in fr0;
- ((and (sc-is x double-reg) (zerop (tn-offset x)))
- (inst fxch fr1)
- ;; Now load y to fr0
- (sc-case y
- (double-reg
- (copy-fp-reg-to-fr0 y))
- (double-stack
- (inst fstp fr0)
- (inst fldd (ea-for-df-stack y)))
- (descriptor-reg
- (inst fstp fr0)
- (inst fldd (ea-for-df-desc y)))))
- ;; Neither y or x are in either fr0 or fr1
- (t
- ;; Load x then y
- (inst fstp fr0)
- (inst fstp fr0)
- (sc-case x
- (double-reg
- (inst fldd (make-random-tn :kind :normal
- :sc (sc-or-lose 'double-reg)
- :offset (- (tn-offset x) 2))))
- (double-stack
- (inst fldd (ea-for-df-stack x)))
- (descriptor-reg
- (inst fldd (ea-for-df-desc x))))
- ;; Load y to fr0
- (sc-case y
- (double-reg
- (inst fldd (make-random-tn :kind :normal
- :sc (sc-or-lose 'double-reg)
- :offset (1- (tn-offset y)))))
- (double-stack
- (inst fldd (ea-for-df-stack y)))
- (descriptor-reg
- (inst fldd (ea-for-df-desc y))))))
-
- ;; Now have y at fr0; and x at fr1
- (inst fpatan)
- (inst fld fr0)
- (case (tn-offset r)
- ((0 1))
- (t (inst fstd r)))))
-) ; PROGN #!-LONG-FLOAT
-\f
-