diff options
Diffstat (limited to 'gcc/d/dmd/root/longdouble.d')
-rw-r--r-- | gcc/d/dmd/root/longdouble.d | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/gcc/d/dmd/root/longdouble.d b/gcc/d/dmd/root/longdouble.d new file mode 100644 index 00000000000..a845c9768e8 --- /dev/null +++ b/gcc/d/dmd/root/longdouble.d @@ -0,0 +1,140 @@ +/** + * 80-bit floating point value implementation if the C/D compiler does not support them natively. + * Copyright (C) 2021 Free Software Foundation, Inc. + * + * GCC is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GCC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GCC; see the file COPYING3. If not see + * <http://www.gnu.org/licenses/>. + */ + +module dmd.root.longdouble; + +import core.stdc.config; +import core.stdc.stdint; + +extern(C++): +nothrow: +@nogc: + +// Type used by the front-end for compile-time reals +struct longdouble +{ + extern (D) this(T)(T r) + { + this.set(cast(SetType!T)r); + } + + // No constructor to be able to use this class in a union. + extern (D) longdouble opAssign(T)(T r) + if (is (T : longdouble)) + { + this.realvalue = r.realvalue; + return this; + } + + extern (D) longdouble opAssign(T)(T r) + if (!is (T : longdouble)) + { + this.set(cast(SetType!T)r); + return this; + } + + // Arithmetic operators. + extern (D) longdouble opBinary(string op, T)(T r) const + if ((op == "+" || op == "-" || op == "*" || op == "/" || op == "%") + && is (T : longdouble)) + { + static if (op == "+") + return this.add(r); + else static if (op == "-") + return this.sub(r); + else static if (op == "*") + return this.mul(r); + else static if (op == "/") + return this.div(r); + else static if (op == "%") + return this.mod(r); + } + + extern (D) longdouble opUnary(string op)() const + if (op == "-") + { + return this.neg(); + } + + extern (D) int opCmp(longdouble r) const + { + return this.cmp(r); + } + + extern (D) int opEquals(longdouble r) const + { + return this.equals(r); + } + + extern (D) bool opCast(T : bool)() const + { + return this.to_bool(); + } + + extern (D) T opCast(T)() const + { + static if (__traits(isUnsigned, T)) + return cast (T) this.to_uint(); + else + return cast(T) this.to_int(); + } + + void set(int8_t d); + void set(int16_t d); + void set(int32_t d); + void set(int64_t d); + void set(uint8_t d); + void set(uint16_t d); + void set(uint32_t d); + void set(uint64_t d); + void set(bool d); + + int64_t to_int() const; + uint64_t to_uint() const; + bool to_bool() const; + + longdouble add(const ref longdouble r) const; + longdouble sub(const ref longdouble r) const; + longdouble mul(const ref longdouble r) const; + longdouble div(const ref longdouble r) const; + longdouble mod(const ref longdouble r) const; + longdouble neg() const; + int cmp(const ref longdouble t) const; + int equals(const ref longdouble t) const; + +private: + // Statically allocate enough space for REAL_VALUE_TYPE. + enum REALVALUE_SIZE = (2 + (16 + c_long.sizeof) / c_long.sizeof); + c_long [REALVALUE_SIZE] realvalue; +} + +// Pick the corresponding (u)int64_t type for T, as int64_t may be +// a special enum that requires casting to explicitly. +private template SetType(T) +{ + static if (__traits(isIntegral, T) && T.sizeof == 8) + { + static if (__traits(isUnsigned, T)) + alias SetType = uint64_t; + else + alias SetType = int64_t; + } + else + alias SetType = T; +} |