diff --git a/Makefile b/Makefile index 6e13322d..8379e073 100644 --- a/Makefile +++ b/Makefile @@ -61,11 +61,8 @@ else LDFLAGS += -Wl,--export-dynamic endif -MPFR_CFLAGS := $(shell pkg-config --cflags mpfr) -MPFR_LDFLAGS := $(shell pkg-config --libs mpfr) - -CXXFLAGS += $(MPFR_CFLAGS) $(LIBFFI_CFLAGS) -LDFLAGS += $(MPFR_LDFLAGS) $(LIBFFI_LDFLAGS) +CXXFLAGS += $(LIBFFI_CFLAGS) +LDFLAGS += $(LIBFFI_LDFLAGS) ENABLE_CODE_COVERAGE ?= "yes" @@ -147,12 +144,11 @@ copylibs: $(FLXSRC) $(OUTPUT): $(PRECOMP_GCH) $(CXXOBJ) $(COBJ) $(UTF8REWIND_AR) @printf "# linking\n" @mkdir -p $(dir $(OUTPUT)) - @$(CXX) -o $@ $(CXXOBJ) $(COBJ) $(LDFLAGS) -Lexternal -L$(shell $(LLVM_CONFIG) --prefix)/lib $(shell $(LLVM_CONFIG) --system-libs --libs core engine native linker bitwriter lto vectorize all-targets object orcjit) -lmpfr -lgmp -lpthread -ldl -lffi -lutf8rewind + @$(CXX) -o $@ $(CXXOBJ) $(COBJ) $(LDFLAGS) -Lexternal -L$(shell $(LLVM_CONFIG) --prefix)/lib $(shell $(LLVM_CONFIG) --system-libs --libs core engine native linker bitwriter lto vectorize all-targets object orcjit) -lpthread -ldl -lffi -lutf8rewind %.cpp.o: %.cpp - @$(eval DONEFILES += "CPP") - @printf "# compiling [$(words $(DONEFILES))/$(NUMFILES)] $<\n" + @printf "# $<\n" @$(CXX) $(CXXFLAGS) $(WARNINGS) -include source/include/precompile.h -Isource/include -Iexternal -I$(shell $(LLVM_CONFIG) --includedir) -MMD -MP -o $@ $< %.h.gch: %.h diff --git a/build/tests/defertest.flx b/build/tests/defertest.flx index 234a005c..0717704e 100644 --- a/build/tests/defertest.flx +++ b/build/tests/defertest.flx @@ -9,6 +9,17 @@ import libc as _ public fn doDeferTest() { bar() + + var i = 0 + while true + { + defer i += 1 + + if i > 15 => break + + printf("%d ", i) + } + printf("\n") } diff --git a/build/tiniest.flx b/build/tiniest.flx index bc82d0fb..773a7c80 100644 --- a/build/tiniest.flx +++ b/build/tiniest.flx @@ -4,21 +4,31 @@ import libc -class wrapper -{ - init() - { - } +// class wrapper +// { +// init() +// { +// } + +// static fn method(a: T, b: U) +// { +// libc::printf("t = %d, u = %d\n", typeid(a), typeid(b)); +// } +// } - static fn method(a: T, b: U) +struct Cat +{ + fn greet() { - libc::printf("t = %d, u = %d\n", typeid(a), typeid(b)); + libc::printf("uwu\n") } } - @entry fn main() { - wrapper::method(1, "asdf") - libc::printf("hello, world\n") + // wrapper::method(1, "asdf") + // wrapper!::method("bsdf", [ 1 ]) + + let c: Cat! = Cat() + c.greet() } diff --git a/build/tmp2/a.flx b/build/tmp2/a.flx index 4a49ef45..60edfdae 100644 --- a/build/tmp2/a.flx +++ b/build/tmp2/a.flx @@ -4,17 +4,38 @@ import libc as _ -@entry fn main() + +// class Foo +struct Foo { - // let x = bazzle() * 2 - // foozle(3) - var i = 0 - while true - { - defer { i += 1 } - if i < -30 => break - else if i > 10 => break + x: T - printf("i = %d\n", i) + fn a(x: U) -> U + { + return x } } + +// class Bar +// { +// init(x: T) { } +// } + +fn bar() -> int +{ + return 3 +} + +fn b(x: X) -> str +{ + return "nein" +} + +@entry fn main() +{ + // let f: Foo! = Foo() + // let b = bar!() + // let b1 = Bar(x: 3) + + let f = Foo(x: 3).a(b(9)) +} diff --git a/external/mpreal/mpreal.h b/external/mpreal/mpreal.h deleted file mode 100644 index 101a0b94..00000000 --- a/external/mpreal/mpreal.h +++ /dev/null @@ -1,3136 +0,0 @@ -/* - MPFR C++: Multi-precision floating point number class for C++. - Based on MPFR library: http://mpfr.org - - Project homepage: http://www.holoborodko.com/pavel/mpfr - Contact e-mail: pavel@holoborodko.com - - Copyright (c) 2008-2015 Pavel Holoborodko - - Contributors: - Dmitriy Gubanov, Konstantin Holoborodko, Brian Gladman, - Helmut Jarausch, Fokko Beekhof, Ulrich Mutze, Heinz van Saanen, - Pere Constans, Peter van Hoof, Gael Guennebaud, Tsai Chia Cheng, - Alexei Zubanov, Jauhien Piatlicki, Victor Berger, John Westwood, - Petr Aleksandrov, Orion Poplawski, Charles Karney, Arash Partow, - Rodney James, Jorge Leitao. - - Licensing: - (A) MPFR C++ is under GNU General Public License ("GPL"). - - (B) Non-free licenses may also be purchased from the author, for users who - do not want their programs protected by the GPL. - - The non-free licenses are for users that wish to use MPFR C++ in - their products but are unwilling to release their software - under the GPL (which would require them to release source code - and allow free redistribution). - - Such users can purchase an unlimited-use license from the author. - Contact us for more details. - - GNU General Public License ("GPL") copyright permissions statement: - ************************************************************************** - This program 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 of the License, or - (at your option) any later version. - - This program 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 this program. If not, see . -*/ - -#ifndef __MPREAL_H__ -#define __MPREAL_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Options -#define MPREAL_HAVE_MSVC_DEBUGVIEW // Enable Debugger Visualizer for "Debug" builds in MSVC. -#define MPREAL_HAVE_DYNAMIC_STD_NUMERIC_LIMITS // Enable extended std::numeric_limits specialization. - // Meaning that "digits", "round_style" and similar members are defined as functions, not constants. - // See std::numeric_limits at the end of the file for more information. - -// Library version -#define MPREAL_VERSION_MAJOR 3 -#define MPREAL_VERSION_MINOR 6 -#define MPREAL_VERSION_PATCHLEVEL 2 -#define MPREAL_VERSION_STRING "3.6.2" - - -// disable deprecated warnings for mpfr. -#ifdef _MSC_VER - #pragma warning(push, 0) - #pragma warning(disable: 4996) -#else - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - #pragma GCC diagnostic ignored "-Wold-style-cast" -#endif - - - -// Detect compiler using signatures from http://predef.sourceforge.net/ -#if defined(__GNUC__) && defined(__INTEL_COMPILER) - #define IsInf(x) isinf(x) // Intel ICC compiler on Linux - -#elif defined(_MSC_VER) // Microsoft Visual C++ - #define IsInf(x) (!_finite(x)) - -#else - #define IsInf(x) std::isinf(x) // GNU C/C++ (and/or other compilers), just hope for C99 conformance -#endif - -// A Clang feature extension to determine compiler features. -#ifndef __has_feature - #define __has_feature(x) 0 -#endif - -// Detect support for r-value references (move semantic). Borrowed from Eigen. -#if (__has_feature(cxx_rvalue_references) || \ - defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L || \ - (defined(_MSC_VER) && _MSC_VER >= 1600)) - - #define MPREAL_HAVE_MOVE_SUPPORT - - // Use fields in mpfr_t structure to check if it was initialized / set dummy initialization - #define mpfr_is_initialized(x) (0 != (x)->_mpfr_d) - #define mpfr_set_uninitialized(x) ((x)->_mpfr_d = 0 ) -#endif - -// Detect support for explicit converters. -#if (__has_feature(cxx_explicit_conversions) || \ - (defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC_MINOR >= 5) || __cplusplus >= 201103L || \ - (defined(_MSC_VER) && _MSC_VER >= 1800)) - - #define MPREAL_HAVE_EXPLICIT_CONVERTERS -#endif - -#define MPFR_USE_INTMAX_T // Enable 64-bit integer types - should be defined before mpfr.h - -#if defined(MPREAL_HAVE_MSVC_DEBUGVIEW) && defined(_MSC_VER) && defined(_DEBUG) - #define MPREAL_MSVC_DEBUGVIEW_CODE DebugView = toString(); - #define MPREAL_MSVC_DEBUGVIEW_DATA std::string DebugView; -#else - #define MPREAL_MSVC_DEBUGVIEW_CODE - #define MPREAL_MSVC_DEBUGVIEW_DATA -#endif - - -#include - - - - -#if (MPFR_VERSION < MPFR_VERSION_NUM(3,0,0)) - #include // Needed for random() -#endif - -// Less important options -#define MPREAL_DOUBLE_BITS_OVERFLOW (-1) // Triggers overflow exception during conversion to double if mpreal - // cannot fit in MPREAL_DOUBLE_BITS_OVERFLOW bits - // = -1 disables overflow checks (default) - -// Fast replacement for mpfr_set_zero(x, +1): -// (a) uses low-level data members, might not be compatible with new versions of MPFR -// (b) sign is not set, add (x)->_mpfr_sign = 1; -#define mpfr_set_zero_fast(x) ((x)->_mpfr_exp = __MPFR_EXP_ZERO) - -#if defined(__GNUC__) - #define MPREAL_PERMISSIVE_EXPR __extension__ -#else - #define MPREAL_PERMISSIVE_EXPR -#endif - -namespace mpfr { - -class mpreal { -private: - mpfr_t mp; - -public: - - // Get default rounding mode & precision - inline static mp_rnd_t get_default_rnd() { return (mp_rnd_t)(mpfr_get_default_rounding_mode()); } - inline static mp_prec_t get_default_prec() { return mpfr_get_default_prec(); } - - // Constructors && type conversions - mpreal(); - mpreal(const mpreal& u); - mpreal(const mpf_t u); - mpreal(const mpz_t u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); - mpreal(const mpq_t u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); - mpreal(const double u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); - mpreal(const long double u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); - mpreal(const unsigned long long int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); - mpreal(const long long int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); - mpreal(const unsigned long int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); - mpreal(const unsigned int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); - mpreal(const long int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); - mpreal(const int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); - - // Construct mpreal from mpfr_t structure. - // shared = true allows to avoid deep copy, so that mpreal and 'u' share the same data & pointers. - mpreal(const mpfr_t u, bool shared = false); - - mpreal(const char* s, mp_prec_t prec = mpreal::get_default_prec(), int base = 10, mp_rnd_t mode = mpreal::get_default_rnd()); - mpreal(const std::string& s, mp_prec_t prec = mpreal::get_default_prec(), int base = 10, mp_rnd_t mode = mpreal::get_default_rnd()); - - ~mpreal(); - -#ifdef MPREAL_HAVE_MOVE_SUPPORT - mpreal& operator=(mpreal&& v) noexcept; - mpreal(mpreal&& u) noexcept; -#endif - - // Operations - // = - // +, -, *, /, ++, --, <<, >> - // *=, +=, -=, /=, - // <, >, ==, <=, >= - - // = - mpreal& operator=(const mpreal& v); - mpreal& operator=(const mpf_t v); - mpreal& operator=(const mpz_t v); - mpreal& operator=(const mpq_t v); - mpreal& operator=(const long double v); - mpreal& operator=(const double v); - mpreal& operator=(const unsigned long int v); - mpreal& operator=(const unsigned long long int v); - mpreal& operator=(const long long int v); - mpreal& operator=(const unsigned int v); - mpreal& operator=(const long int v); - mpreal& operator=(const int v); - mpreal& operator=(const char* s); - mpreal& operator=(const std::string& s); - template mpreal& operator= (const std::complex& z); - - // + - mpreal& operator+=(const mpreal& v); - mpreal& operator+=(const mpf_t v); - mpreal& operator+=(const mpz_t v); - mpreal& operator+=(const mpq_t v); - mpreal& operator+=(const long double u); - mpreal& operator+=(const double u); - mpreal& operator+=(const unsigned long int u); - mpreal& operator+=(const unsigned int u); - mpreal& operator+=(const long int u); - mpreal& operator+=(const int u); - - mpreal& operator+=(const long long int u); - mpreal& operator+=(const unsigned long long int u); - mpreal& operator-=(const long long int u); - mpreal& operator-=(const unsigned long long int u); - mpreal& operator*=(const long long int u); - mpreal& operator*=(const unsigned long long int u); - mpreal& operator/=(const long long int u); - mpreal& operator/=(const unsigned long long int u); - - const mpreal operator+() const; - mpreal& operator++ (); - const mpreal operator++ (int); - - // - - mpreal& operator-=(const mpreal& v); - mpreal& operator-=(const mpz_t v); - mpreal& operator-=(const mpq_t v); - mpreal& operator-=(const long double u); - mpreal& operator-=(const double u); - mpreal& operator-=(const unsigned long int u); - mpreal& operator-=(const unsigned int u); - mpreal& operator-=(const long int u); - mpreal& operator-=(const int u); - const mpreal operator-() const; - friend const mpreal operator-(const unsigned long int b, const mpreal& a); - friend const mpreal operator-(const unsigned int b, const mpreal& a); - friend const mpreal operator-(const long int b, const mpreal& a); - friend const mpreal operator-(const int b, const mpreal& a); - friend const mpreal operator-(const double b, const mpreal& a); - mpreal& operator-- (); - const mpreal operator-- (int); - - // * - mpreal& operator*=(const mpreal& v); - mpreal& operator*=(const mpz_t v); - mpreal& operator*=(const mpq_t v); - mpreal& operator*=(const long double v); - mpreal& operator*=(const double v); - mpreal& operator*=(const unsigned long int v); - mpreal& operator*=(const unsigned int v); - mpreal& operator*=(const long int v); - mpreal& operator*=(const int v); - - // / - mpreal& operator/=(const mpreal& v); - mpreal& operator/=(const mpz_t v); - mpreal& operator/=(const mpq_t v); - mpreal& operator/=(const long double v); - mpreal& operator/=(const double v); - mpreal& operator/=(const unsigned long int v); - mpreal& operator/=(const unsigned int v); - mpreal& operator/=(const long int v); - mpreal& operator/=(const int v); - friend const mpreal operator/(const unsigned long int b, const mpreal& a); - friend const mpreal operator/(const unsigned int b, const mpreal& a); - friend const mpreal operator/(const long int b, const mpreal& a); - friend const mpreal operator/(const int b, const mpreal& a); - friend const mpreal operator/(const double b, const mpreal& a); - - //<<= Fast Multiplication by 2^u - mpreal& operator<<=(const unsigned long int u); - mpreal& operator<<=(const unsigned int u); - mpreal& operator<<=(const long int u); - mpreal& operator<<=(const int u); - - //>>= Fast Division by 2^u - mpreal& operator>>=(const unsigned long int u); - mpreal& operator>>=(const unsigned int u); - mpreal& operator>>=(const long int u); - mpreal& operator>>=(const int u); - - // Type Conversion operators - bool toBool ( ) const; - long toLong (mp_rnd_t mode = GMP_RNDZ) const; - unsigned long toULong (mp_rnd_t mode = GMP_RNDZ) const; - long long toLLong (mp_rnd_t mode = GMP_RNDZ) const; - unsigned long long toULLong (mp_rnd_t mode = GMP_RNDZ) const; - float toFloat (mp_rnd_t mode = GMP_RNDN) const; - double toDouble (mp_rnd_t mode = GMP_RNDN) const; - long double toLDouble (mp_rnd_t mode = GMP_RNDN) const; - -#if defined (MPREAL_HAVE_EXPLICIT_CONVERTERS) - explicit operator bool () const { return toBool(); } - explicit operator int () const { return int(toLong()); } - explicit operator long () const { return toLong(); } - explicit operator long long () const { return toLLong(); } - explicit operator unsigned () const { return unsigned(toULong()); } - explicit operator unsigned long () const { return toULong(); } - explicit operator unsigned long long () const { return toULLong(); } - explicit operator float () const { return toFloat(); } - explicit operator double () const { return toDouble(); } - explicit operator long double () const { return toLDouble(); } -#endif - - // Get raw pointers so that mpreal can be directly used in raw mpfr_* functions - ::mpfr_ptr mpfr_ptr(); - ::mpfr_srcptr mpfr_ptr() const; - ::mpfr_srcptr mpfr_srcptr() const; - - // Convert mpreal to string with n significant digits in base b - // n = -1 -> convert with the maximum available digits - std::string toString(int n = -1, int b = 10, mp_rnd_t mode = mpreal::get_default_rnd()) const; - -#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) - std::string toString(const std::string& format) const; -#endif - - std::ostream& output(std::ostream& os) const; - - // Math Functions - friend const mpreal sqr (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal sqrt(const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal sqrt(const unsigned long int v, mp_rnd_t rnd_mode); - friend const mpreal cbrt(const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal root(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode); - friend const mpreal pow (const mpreal& a, const mpreal& b, mp_rnd_t rnd_mode); - friend const mpreal pow (const mpreal& a, const mpz_t b, mp_rnd_t rnd_mode); - friend const mpreal pow (const mpreal& a, const unsigned long int b, mp_rnd_t rnd_mode); - friend const mpreal pow (const mpreal& a, const long int b, mp_rnd_t rnd_mode); - friend const mpreal pow (const unsigned long int a, const mpreal& b, mp_rnd_t rnd_mode); - friend const mpreal pow (const unsigned long int a, const unsigned long int b, mp_rnd_t rnd_mode); - friend const mpreal fabs(const mpreal& v, mp_rnd_t rnd_mode); - - friend const mpreal abs(const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal dim(const mpreal& a, const mpreal& b, mp_rnd_t rnd_mode); - friend inline const mpreal mul_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode); - friend inline const mpreal mul_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode); - friend inline const mpreal div_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode); - friend inline const mpreal div_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode); - friend int cmpabs(const mpreal& a,const mpreal& b); - - friend const mpreal log (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal log2 (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal logb (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal log10(const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal exp (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal exp2 (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal exp10(const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal log1p(const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal expm1(const mpreal& v, mp_rnd_t rnd_mode); - - friend const mpreal cos(const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal sin(const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal tan(const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal sec(const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal csc(const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal cot(const mpreal& v, mp_rnd_t rnd_mode); - friend int sin_cos(mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode); - - friend const mpreal acos (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal asin (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal atan (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal atan2 (const mpreal& y, const mpreal& x, mp_rnd_t rnd_mode); - friend const mpreal acot (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal asec (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal acsc (const mpreal& v, mp_rnd_t rnd_mode); - - friend const mpreal cosh (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal sinh (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal tanh (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal sech (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal csch (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal coth (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal acosh (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal asinh (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal atanh (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal acoth (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal asech (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal acsch (const mpreal& v, mp_rnd_t rnd_mode); - - friend const mpreal hypot (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); - - friend const mpreal fac_ui (unsigned long int v, mp_prec_t prec, mp_rnd_t rnd_mode); - friend const mpreal eint (const mpreal& v, mp_rnd_t rnd_mode); - - friend const mpreal gamma (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal tgamma (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal lngamma (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal lgamma (const mpreal& v, int *signp, mp_rnd_t rnd_mode); - friend const mpreal zeta (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal erf (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal erfc (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal besselj0 (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal besselj1 (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal besseljn (long n, const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal bessely0 (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal bessely1 (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal besselyn (long n, const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal fma (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode); - friend const mpreal fms (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode); - friend const mpreal agm (const mpreal& v1, const mpreal& v2, mp_rnd_t rnd_mode); - friend const mpreal sum (const mpreal tab[], const unsigned long int n, int& status, mp_rnd_t rnd_mode); - friend int sgn(const mpreal& v); // returns -1 or +1 - -// MPFR 2.4.0 Specifics -#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) - friend int sinh_cosh (mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal li2 (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal fmod (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); - friend const mpreal rec_sqrt (const mpreal& v, mp_rnd_t rnd_mode); - - // MATLAB's semantic equivalents - friend const mpreal rem (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); // Remainder after division - friend const mpreal mod (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); // Modulus after division -#endif - -#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) - friend const mpreal digamma (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal ai (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal urandom (gmp_randstate_t& state, mp_rnd_t rnd_mode); // use gmp_randinit_default() to init state, gmp_randclear() to clear -#endif - -#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,1,0)) - friend const mpreal grandom (gmp_randstate_t& state, mp_rnd_t rnd_mode); // use gmp_randinit_default() to init state, gmp_randclear() to clear - friend const mpreal grandom (unsigned int seed); -#endif - - // Uniformly distributed random number generation in [0,1] using - // Mersenne-Twister algorithm by default. - // Use parameter to setup seed, e.g.: random((unsigned)time(NULL)) - // Check urandom() for more precise control. - friend const mpreal random(unsigned int seed); - - // Exponent and mantissa manipulation - friend const mpreal frexp (const mpreal& v, mp_exp_t* exp); - friend const mpreal ldexp (const mpreal& v, mp_exp_t exp); - friend const mpreal scalbn(const mpreal& v, mp_exp_t exp); - - // Splits mpreal value into fractional and integer parts. - // Returns fractional part and stores integer part in n. - friend const mpreal modf(const mpreal& v, mpreal& n); - - // Constants - // don't forget to call mpfr_free_cache() for every thread where you are using const-functions - friend const mpreal const_log2 (mp_prec_t prec, mp_rnd_t rnd_mode); - friend const mpreal const_pi (mp_prec_t prec, mp_rnd_t rnd_mode); - friend const mpreal const_euler (mp_prec_t prec, mp_rnd_t rnd_mode); - friend const mpreal const_catalan (mp_prec_t prec, mp_rnd_t rnd_mode); - - // returns +inf iff sign>=0 otherwise -inf - friend const mpreal const_infinity(int sign, mp_prec_t prec); - - // Output/ Input - friend std::ostream& operator<<(std::ostream& os, const mpreal& v); - friend std::istream& operator>>(std::istream& is, mpreal& v); - - // Integer Related Functions - friend const mpreal rint (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal ceil (const mpreal& v); - friend const mpreal floor(const mpreal& v); - friend const mpreal round(const mpreal& v); - friend const mpreal trunc(const mpreal& v); - friend const mpreal rint_ceil (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal rint_floor (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal rint_round (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal rint_trunc (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal frac (const mpreal& v, mp_rnd_t rnd_mode); - friend const mpreal remainder ( const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); - friend const mpreal remquo (long* q, const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); - - // Miscellaneous Functions - friend const mpreal nexttoward (const mpreal& x, const mpreal& y); - friend const mpreal nextabove (const mpreal& x); - friend const mpreal nextbelow (const mpreal& x); - - // use gmp_randinit_default() to init state, gmp_randclear() to clear - friend const mpreal urandomb (gmp_randstate_t& state); - -// MPFR < 2.4.2 Specifics -#if (MPFR_VERSION <= MPFR_VERSION_NUM(2,4,2)) - friend const mpreal random2 (mp_size_t size, mp_exp_t exp); -#endif - - // Instance Checkers - friend bool isnan (const mpreal& v); - friend bool isinf (const mpreal& v); - friend bool isfinite (const mpreal& v); - - friend bool isnum (const mpreal& v); - friend bool iszero (const mpreal& v); - friend bool isint (const mpreal& v); - -#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) - friend bool isregular(const mpreal& v); -#endif - - // Set/Get instance properties - inline mp_prec_t get_prec() const; - inline void set_prec(mp_prec_t prec, mp_rnd_t rnd_mode = get_default_rnd()); // Change precision with rounding mode - - // Aliases for get_prec(), set_prec() - needed for compatibility with std::complex interface - inline mpreal& setPrecision(int Precision, mp_rnd_t RoundingMode = get_default_rnd()); - inline int getPrecision() const; - - // Set mpreal to +/- inf, NaN, +/-0 - mpreal& setInf (int Sign = +1); - mpreal& setNan (); - mpreal& setZero (int Sign = +1); - mpreal& setSign (int Sign, mp_rnd_t RoundingMode = get_default_rnd()); - - //Exponent - mp_exp_t get_exp(); - int set_exp(mp_exp_t e); - int check_range (int t, mp_rnd_t rnd_mode = get_default_rnd()); - int subnormalize (int t, mp_rnd_t rnd_mode = get_default_rnd()); - - // Inexact conversion from float - inline bool fits_in_bits(double x, int n); - - // Set/Get global properties - static void set_default_prec(mp_prec_t prec); - static void set_default_rnd(mp_rnd_t rnd_mode); - - static mp_exp_t get_emin (void); - static mp_exp_t get_emax (void); - static mp_exp_t get_emin_min (void); - static mp_exp_t get_emin_max (void); - static mp_exp_t get_emax_min (void); - static mp_exp_t get_emax_max (void); - static int set_emin (mp_exp_t exp); - static int set_emax (mp_exp_t exp); - - // Efficient swapping of two mpreal values - needed for std algorithms - friend void swap(mpreal& x, mpreal& y); - - friend const mpreal fmax(const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); - friend const mpreal fmin(const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); - -private: - // Human friendly Debug Preview in Visual Studio. - // Put one of these lines: - // - // mpfr::mpreal= ; Show value only - // mpfr::mpreal=, bits ; Show value & precision - // - // at the beginning of - // [Visual Studio Installation Folder]\Common7\Packages\Debugger\autoexp.dat - MPREAL_MSVC_DEBUGVIEW_DATA - - // "Smart" resources deallocation. Checks if instance initialized before deletion. - void clear(::mpfr_ptr); -}; - -////////////////////////////////////////////////////////////////////////// -// Exceptions -class conversion_overflow : public std::exception { -public: - std::string why() { return "inexact conversion from floating point"; } -}; - -////////////////////////////////////////////////////////////////////////// -// Constructors & converters -// Default constructor: creates mp number and initializes it to 0. -inline mpreal::mpreal() -{ - mpfr_init2(mpfr_ptr(), mpreal::get_default_prec()); - mpfr_set_zero_fast(mpfr_ptr()); - - MPREAL_MSVC_DEBUGVIEW_CODE; -} - -inline mpreal::mpreal(const mpreal& u) -{ - mpfr_init2(mpfr_ptr(),mpfr_get_prec(u.mpfr_srcptr())); - mpfr_set (mpfr_ptr(),u.mpfr_srcptr(),mpreal::get_default_rnd()); - - MPREAL_MSVC_DEBUGVIEW_CODE; -} - -#ifdef MPREAL_HAVE_MOVE_SUPPORT -inline mpreal::mpreal(mpreal&& other) noexcept -{ - mpfr_set_uninitialized(mpfr_ptr()); // make sure "other" holds no pointer to actual data - mpfr_swap(mpfr_ptr(), other.mpfr_ptr()); - - MPREAL_MSVC_DEBUGVIEW_CODE; -} - -inline mpreal& mpreal::operator=(mpreal&& other) noexcept -{ - mpfr_swap(mpfr_ptr(), other.mpfr_ptr()); - - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} -#endif - -inline mpreal::mpreal(const mpfr_t u, bool shared) -{ - if(shared) - { - std::memcpy(mpfr_ptr(), u, sizeof(mpfr_t)); - } - else - { - mpfr_init2(mpfr_ptr(), mpfr_get_prec(u)); - mpfr_set (mpfr_ptr(), u, mpreal::get_default_rnd()); - } - - MPREAL_MSVC_DEBUGVIEW_CODE; -} - -inline mpreal::mpreal(const mpf_t u) -{ - mpfr_init2(mpfr_ptr(),(mp_prec_t) mpf_get_prec(u)); // (gmp: mp_bitcnt_t) unsigned long -> long (mpfr: mp_prec_t) - mpfr_set_f(mpfr_ptr(),u,mpreal::get_default_rnd()); - - MPREAL_MSVC_DEBUGVIEW_CODE; -} - -inline mpreal::mpreal(const mpz_t u, mp_prec_t prec, mp_rnd_t mode) -{ - mpfr_init2(mpfr_ptr(), prec); - mpfr_set_z(mpfr_ptr(), u, mode); - - MPREAL_MSVC_DEBUGVIEW_CODE; -} - -inline mpreal::mpreal(const mpq_t u, mp_prec_t prec, mp_rnd_t mode) -{ - mpfr_init2(mpfr_ptr(), prec); - mpfr_set_q(mpfr_ptr(), u, mode); - - MPREAL_MSVC_DEBUGVIEW_CODE; -} - -inline mpreal::mpreal(const double u, mp_prec_t prec, mp_rnd_t mode) -{ - mpfr_init2(mpfr_ptr(), prec); - -#if (MPREAL_DOUBLE_BITS_OVERFLOW > -1) - if(fits_in_bits(u, MPREAL_DOUBLE_BITS_OVERFLOW)) - { - mpfr_set_d(mpfr_ptr(), u, mode); - }else - throw conversion_overflow(); -#else - mpfr_set_d(mpfr_ptr(), u, mode); -#endif - - MPREAL_MSVC_DEBUGVIEW_CODE; -} - -inline mpreal::mpreal(const long double u, mp_prec_t prec, mp_rnd_t mode) -{ - mpfr_init2 (mpfr_ptr(), prec); - mpfr_set_ld(mpfr_ptr(), u, mode); - - MPREAL_MSVC_DEBUGVIEW_CODE; -} - -inline mpreal::mpreal(const unsigned long long int u, mp_prec_t prec, mp_rnd_t mode) -{ - mpfr_init2 (mpfr_ptr(), prec); - mpfr_set_uj(mpfr_ptr(), u, mode); - - MPREAL_MSVC_DEBUGVIEW_CODE; -} - -inline mpreal::mpreal(const long long int u, mp_prec_t prec, mp_rnd_t mode) -{ - mpfr_init2 (mpfr_ptr(), prec); - mpfr_set_sj(mpfr_ptr(), u, mode); - - MPREAL_MSVC_DEBUGVIEW_CODE; -} - -inline mpreal::mpreal(const unsigned long int u, mp_prec_t prec, mp_rnd_t mode) -{ - mpfr_init2 (mpfr_ptr(), prec); - mpfr_set_ui(mpfr_ptr(), u, mode); - - MPREAL_MSVC_DEBUGVIEW_CODE; -} - -inline mpreal::mpreal(const unsigned int u, mp_prec_t prec, mp_rnd_t mode) -{ - mpfr_init2 (mpfr_ptr(), prec); - mpfr_set_ui(mpfr_ptr(), u, mode); - - MPREAL_MSVC_DEBUGVIEW_CODE; -} - -inline mpreal::mpreal(const long int u, mp_prec_t prec, mp_rnd_t mode) -{ - mpfr_init2 (mpfr_ptr(), prec); - mpfr_set_si(mpfr_ptr(), u, mode); - - MPREAL_MSVC_DEBUGVIEW_CODE; -} - -inline mpreal::mpreal(const int u, mp_prec_t prec, mp_rnd_t mode) -{ - mpfr_init2 (mpfr_ptr(), prec); - mpfr_set_si(mpfr_ptr(), u, mode); - - MPREAL_MSVC_DEBUGVIEW_CODE; -} - -inline mpreal::mpreal(const char* s, mp_prec_t prec, int base, mp_rnd_t mode) -{ - mpfr_init2 (mpfr_ptr(), prec); - mpfr_set_str(mpfr_ptr(), s, base, mode); - - MPREAL_MSVC_DEBUGVIEW_CODE; -} - -inline mpreal::mpreal(const std::string& s, mp_prec_t prec, int base, mp_rnd_t mode) -{ - mpfr_init2 (mpfr_ptr(), prec); - mpfr_set_str(mpfr_ptr(), s.c_str(), base, mode); - - MPREAL_MSVC_DEBUGVIEW_CODE; -} - -inline void mpreal::clear(::mpfr_ptr x) -{ -#ifdef MPREAL_HAVE_MOVE_SUPPORT - if(mpfr_is_initialized(x)) -#endif - mpfr_clear(x); -} - -inline mpreal::~mpreal() -{ - clear(mpfr_ptr()); -} - -// internal namespace needed for template magic -namespace internal{ - - // Use SFINAE to restrict arithmetic operations instantiation only for numeric types - // This is needed for smooth integration with libraries based on expression templates, like Eigen. - // TODO: Do the same for boolean operators. - template struct result_type {}; - - template <> struct result_type {typedef mpreal type;}; - template <> struct result_type {typedef mpreal type;}; - template <> struct result_type {typedef mpreal type;}; - template <> struct result_type {typedef mpreal type;}; - template <> struct result_type {typedef mpreal type;}; - template <> struct result_type {typedef mpreal type;}; - template <> struct result_type {typedef mpreal type;}; - template <> struct result_type {typedef mpreal type;}; - template <> struct result_type {typedef mpreal type;}; - template <> struct result_type {typedef mpreal type;}; - template <> struct result_type {typedef mpreal type;}; -} - -// + Addition -template -inline const typename internal::result_type::type - operator+(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) += rhs; } - -template -inline const typename internal::result_type::type - operator+(const Lhs& lhs, const mpreal& rhs){ return mpreal(rhs) += lhs; } - -// - Subtraction -template -inline const typename internal::result_type::type - operator-(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) -= rhs; } - -template -inline const typename internal::result_type::type - operator-(const Lhs& lhs, const mpreal& rhs){ return mpreal(lhs) -= rhs; } - -// * Multiplication -template -inline const typename internal::result_type::type - operator*(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) *= rhs; } - -template -inline const typename internal::result_type::type - operator*(const Lhs& lhs, const mpreal& rhs){ return mpreal(rhs) *= lhs; } - -// / Division -template -inline const typename internal::result_type::type - operator/(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) /= rhs; } - -template -inline const typename internal::result_type::type - operator/(const Lhs& lhs, const mpreal& rhs){ return mpreal(lhs) /= rhs; } - -////////////////////////////////////////////////////////////////////////// -// sqrt -const mpreal sqrt(const unsigned int v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal sqrt(const long int v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal sqrt(const int v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal sqrt(const long double v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal sqrt(const double v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); - -// abs -inline const mpreal abs(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()); - -////////////////////////////////////////////////////////////////////////// -// pow -const mpreal pow(const mpreal& a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const mpreal& a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const mpreal& a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const mpreal& a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); - -const mpreal pow(const unsigned int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const long int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const long double a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const double a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); - -const mpreal pow(const unsigned long int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const unsigned long int a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const unsigned long int a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const unsigned long int a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const unsigned long int a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); - -const mpreal pow(const unsigned int a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const unsigned int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const unsigned int a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const unsigned int a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const unsigned int a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const unsigned int a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); - -const mpreal pow(const long int a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const long int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const long int a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const long int a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const long int a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const long int a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); - -const mpreal pow(const int a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const int a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const int a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const int a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const int a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); - -const mpreal pow(const long double a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const long double a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const long double a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const long double a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const long double a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); - -const mpreal pow(const double a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const double a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const double a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const double a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -const mpreal pow(const double a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); - -inline const mpreal mul_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -inline const mpreal mul_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -inline const mpreal div_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); -inline const mpreal div_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); - -////////////////////////////////////////////////////////////////////////// -// Estimate machine epsilon for the given precision -// Returns smallest eps such that 1.0 + eps != 1.0 -inline mpreal machine_epsilon(mp_prec_t prec = mpreal::get_default_prec()); - -// Returns smallest eps such that x + eps != x (relative machine epsilon) -inline mpreal machine_epsilon(const mpreal& x); - -// Gives max & min values for the required precision, -// minval is 'safe' meaning 1 / minval does not overflow -// maxval is 'safe' meaning 1 / maxval does not underflow -inline mpreal minval(mp_prec_t prec = mpreal::get_default_prec()); -inline mpreal maxval(mp_prec_t prec = mpreal::get_default_prec()); - -// 'Dirty' equality check 1: |a-b| < min{|a|,|b|} * eps -inline bool isEqualFuzzy(const mpreal& a, const mpreal& b, const mpreal& eps); - -// 'Dirty' equality check 2: |a-b| < min{|a|,|b|} * eps( min{|a|,|b|} ) -inline bool isEqualFuzzy(const mpreal& a, const mpreal& b); - -// 'Bitwise' equality check -// maxUlps - a and b can be apart by maxUlps binary numbers. -inline bool isEqualUlps(const mpreal& a, const mpreal& b, int maxUlps); - -////////////////////////////////////////////////////////////////////////// -// Convert precision in 'bits' to decimal digits and vice versa. -// bits = ceil(digits*log[2](10)) -// digits = floor(bits*log[10](2)) - -inline mp_prec_t digits2bits(int d); -inline int bits2digits(mp_prec_t b); - -////////////////////////////////////////////////////////////////////////// -// min, max -const mpreal (max)(const mpreal& x, const mpreal& y); -const mpreal (min)(const mpreal& x, const mpreal& y); - -////////////////////////////////////////////////////////////////////////// -// Implementation -////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////// -// Operators - Assignment -inline mpreal& mpreal::operator=(const mpreal& v) -{ - if (this != &v) - { - mp_prec_t tp = mpfr_get_prec( mpfr_srcptr()); - mp_prec_t vp = mpfr_get_prec(v.mpfr_srcptr()); - - if(tp != vp){ - clear(mpfr_ptr()); - mpfr_init2(mpfr_ptr(), vp); - } - - mpfr_set(mpfr_ptr(), v.mpfr_srcptr(), mpreal::get_default_rnd()); - - MPREAL_MSVC_DEBUGVIEW_CODE; - } - return *this; -} - -inline mpreal& mpreal::operator=(const mpf_t v) -{ - mpfr_set_f(mpfr_ptr(), v, mpreal::get_default_rnd()); - - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator=(const mpz_t v) -{ - mpfr_set_z(mpfr_ptr(), v, mpreal::get_default_rnd()); - - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator=(const mpq_t v) -{ - mpfr_set_q(mpfr_ptr(), v, mpreal::get_default_rnd()); - - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator=(const long double v) -{ - mpfr_set_ld(mpfr_ptr(), v, mpreal::get_default_rnd()); - - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator=(const double v) -{ -#if (MPREAL_DOUBLE_BITS_OVERFLOW > -1) - if(fits_in_bits(v, MPREAL_DOUBLE_BITS_OVERFLOW)) - { - mpfr_set_d(mpfr_ptr(),v,mpreal::get_default_rnd()); - }else - throw conversion_overflow(); -#else - mpfr_set_d(mpfr_ptr(),v,mpreal::get_default_rnd()); -#endif - - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator=(const unsigned long int v) -{ - mpfr_set_ui(mpfr_ptr(), v, mpreal::get_default_rnd()); - - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator=(const unsigned int v) -{ - mpfr_set_ui(mpfr_ptr(), v, mpreal::get_default_rnd()); - - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator=(const unsigned long long int v) -{ - mpfr_set_uj(mpfr_ptr(), v, mpreal::get_default_rnd()); - - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator=(const long long int v) -{ - mpfr_set_sj(mpfr_ptr(), v, mpreal::get_default_rnd()); - - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator=(const long int v) -{ - mpfr_set_si(mpfr_ptr(), v, mpreal::get_default_rnd()); - - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator=(const int v) -{ - mpfr_set_si(mpfr_ptr(), v, mpreal::get_default_rnd()); - - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator=(const char* s) -{ - // Use other converters for more precise control on base & precision & rounding: - // - // mpreal(const char* s, mp_prec_t prec, int base, mp_rnd_t mode) - // mpreal(const std::string& s,mp_prec_t prec, int base, mp_rnd_t mode) - // - // Here we assume base = 10 and we use precision of target variable. - - mpfr_t t; - - mpfr_init2(t, mpfr_get_prec(mpfr_srcptr())); - - if(0 == mpfr_set_str(t, s, 10, mpreal::get_default_rnd())) - { - mpfr_set(mpfr_ptr(), t, mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - } - - clear(t); - return *this; -} - -inline mpreal& mpreal::operator=(const std::string& s) -{ - // Use other converters for more precise control on base & precision & rounding: - // - // mpreal(const char* s, mp_prec_t prec, int base, mp_rnd_t mode) - // mpreal(const std::string& s,mp_prec_t prec, int base, mp_rnd_t mode) - // - // Here we assume base = 10 and we use precision of target variable. - - mpfr_t t; - - mpfr_init2(t, mpfr_get_prec(mpfr_srcptr())); - - if(0 == mpfr_set_str(t, s.c_str(), 10, mpreal::get_default_rnd())) - { - mpfr_set(mpfr_ptr(), t, mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - } - - clear(t); - return *this; -} - -template -inline mpreal& mpreal::operator= (const std::complex& z) -{ - *this = z.real(); - return *this; -} - -////////////////////////////////////////////////////////////////////////// -// + Addition -inline mpreal& mpreal::operator+=(const mpreal& v) -{ - mpfr_add(mpfr_ptr(), mpfr_srcptr(), v.mpfr_srcptr(), mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator+=(const mpf_t u) -{ - *this += mpreal(u); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator+=(const mpz_t u) -{ - mpfr_add_z(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator+=(const mpq_t u) -{ - mpfr_add_q(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator+= (const long double u) -{ - *this += mpreal(u); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator+= (const double u) -{ -#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) - mpfr_add_d(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); -#else - *this += mpreal(u); -#endif - - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator+=(const unsigned long int u) -{ - mpfr_add_ui(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator+=(const unsigned int u) -{ - mpfr_add_ui(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator+=(const long int u) -{ - mpfr_add_si(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator+=(const int u) -{ - mpfr_add_si(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator+=(const long long int u) { *this += mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } -inline mpreal& mpreal::operator+=(const unsigned long long int u){ *this += mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } -inline mpreal& mpreal::operator-=(const long long int u) { *this -= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } -inline mpreal& mpreal::operator-=(const unsigned long long int u){ *this -= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } -inline mpreal& mpreal::operator*=(const long long int u) { *this *= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } -inline mpreal& mpreal::operator*=(const unsigned long long int u){ *this *= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } -inline mpreal& mpreal::operator/=(const long long int u) { *this /= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } -inline mpreal& mpreal::operator/=(const unsigned long long int u){ *this /= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } - -inline const mpreal mpreal::operator+()const { return mpreal(*this); } - -inline const mpreal operator+(const mpreal& a, const mpreal& b) -{ - mpreal c(0, (std::max)(mpfr_get_prec(a.mpfr_ptr()), mpfr_get_prec(b.mpfr_ptr()))); - mpfr_add(c.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), mpreal::get_default_rnd()); - return c; -} - -inline mpreal& mpreal::operator++() -{ - return *this += 1; -} - -inline const mpreal mpreal::operator++ (int) -{ - mpreal x(*this); - *this += 1; - return x; -} - -inline mpreal& mpreal::operator--() -{ - return *this -= 1; -} - -inline const mpreal mpreal::operator-- (int) -{ - mpreal x(*this); - *this -= 1; - return x; -} - -////////////////////////////////////////////////////////////////////////// -// - Subtraction -inline mpreal& mpreal::operator-=(const mpreal& v) -{ - mpfr_sub(mpfr_ptr(),mpfr_srcptr(),v.mpfr_srcptr(),mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator-=(const mpz_t v) -{ - mpfr_sub_z(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator-=(const mpq_t v) -{ - mpfr_sub_q(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator-=(const long double v) -{ - *this -= mpreal(v); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator-=(const double v) -{ -#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) - mpfr_sub_d(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); -#else - *this -= mpreal(v); -#endif - - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator-=(const unsigned long int v) -{ - mpfr_sub_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator-=(const unsigned int v) -{ - mpfr_sub_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator-=(const long int v) -{ - mpfr_sub_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator-=(const int v) -{ - mpfr_sub_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline const mpreal mpreal::operator-()const -{ - mpreal u(*this); - mpfr_neg(u.mpfr_ptr(),u.mpfr_srcptr(),mpreal::get_default_rnd()); - return u; -} - -inline const mpreal operator-(const mpreal& a, const mpreal& b) -{ - mpreal c(0, (std::max)(mpfr_get_prec(a.mpfr_ptr()), mpfr_get_prec(b.mpfr_ptr()))); - mpfr_sub(c.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), mpreal::get_default_rnd()); - return c; -} - -inline const mpreal operator-(const double b, const mpreal& a) -{ -#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) - mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); - mpfr_d_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); - return x; -#else - mpreal x(b, mpfr_get_prec(a.mpfr_ptr())); - x -= a; - return x; -#endif -} - -inline const mpreal operator-(const unsigned long int b, const mpreal& a) -{ - mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); - mpfr_ui_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); - return x; -} - -inline const mpreal operator-(const unsigned int b, const mpreal& a) -{ - mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); - mpfr_ui_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); - return x; -} - -inline const mpreal operator-(const long int b, const mpreal& a) -{ - mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); - mpfr_si_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); - return x; -} - -inline const mpreal operator-(const int b, const mpreal& a) -{ - mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); - mpfr_si_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); - return x; -} - -////////////////////////////////////////////////////////////////////////// -// * Multiplication -inline mpreal& mpreal::operator*= (const mpreal& v) -{ - mpfr_mul(mpfr_ptr(),mpfr_srcptr(),v.mpfr_srcptr(),mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator*=(const mpz_t v) -{ - mpfr_mul_z(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator*=(const mpq_t v) -{ - mpfr_mul_q(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator*=(const long double v) -{ - *this *= mpreal(v); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator*=(const double v) -{ -#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) - mpfr_mul_d(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); -#else - *this *= mpreal(v); -#endif - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator*=(const unsigned long int v) -{ - mpfr_mul_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator*=(const unsigned int v) -{ - mpfr_mul_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator*=(const long int v) -{ - mpfr_mul_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator*=(const int v) -{ - mpfr_mul_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline const mpreal operator*(const mpreal& a, const mpreal& b) -{ - mpreal c(0, (std::max)(mpfr_get_prec(a.mpfr_ptr()), mpfr_get_prec(b.mpfr_ptr()))); - mpfr_mul(c.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), mpreal::get_default_rnd()); - return c; -} - -////////////////////////////////////////////////////////////////////////// -// / Division -inline mpreal& mpreal::operator/=(const mpreal& v) -{ - mpfr_div(mpfr_ptr(),mpfr_srcptr(),v.mpfr_srcptr(),mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator/=(const mpz_t v) -{ - mpfr_div_z(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator/=(const mpq_t v) -{ - mpfr_div_q(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator/=(const long double v) -{ - *this /= mpreal(v); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator/=(const double v) -{ -#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) - mpfr_div_d(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); -#else - *this /= mpreal(v); -#endif - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator/=(const unsigned long int v) -{ - mpfr_div_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator/=(const unsigned int v) -{ - mpfr_div_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator/=(const long int v) -{ - mpfr_div_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator/=(const int v) -{ - mpfr_div_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline const mpreal operator/(const mpreal& a, const mpreal& b) -{ - mpreal c(0, (std::max)(mpfr_get_prec(a.mpfr_srcptr()), mpfr_get_prec(b.mpfr_srcptr()))); - mpfr_div(c.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), mpreal::get_default_rnd()); - return c; -} - -inline const mpreal operator/(const unsigned long int b, const mpreal& a) -{ - mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); - mpfr_ui_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); - return x; -} - -inline const mpreal operator/(const unsigned int b, const mpreal& a) -{ - mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); - mpfr_ui_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); - return x; -} - -inline const mpreal operator/(const long int b, const mpreal& a) -{ - mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); - mpfr_si_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); - return x; -} - -inline const mpreal operator/(const int b, const mpreal& a) -{ - mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); - mpfr_si_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); - return x; -} - -inline const mpreal operator/(const double b, const mpreal& a) -{ -#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) - mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); - mpfr_d_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); - return x; -#else - mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); - x /= a; - return x; -#endif -} - -////////////////////////////////////////////////////////////////////////// -// Shifts operators - Multiplication/Division by power of 2 -inline mpreal& mpreal::operator<<=(const unsigned long int u) -{ - mpfr_mul_2ui(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator<<=(const unsigned int u) -{ - mpfr_mul_2ui(mpfr_ptr(),mpfr_srcptr(),static_cast(u),mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator<<=(const long int u) -{ - mpfr_mul_2si(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator<<=(const int u) -{ - mpfr_mul_2si(mpfr_ptr(),mpfr_srcptr(),static_cast(u),mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator>>=(const unsigned long int u) -{ - mpfr_div_2ui(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator>>=(const unsigned int u) -{ - mpfr_div_2ui(mpfr_ptr(),mpfr_srcptr(),static_cast(u),mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator>>=(const long int u) -{ - mpfr_div_2si(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::operator>>=(const int u) -{ - mpfr_div_2si(mpfr_ptr(),mpfr_srcptr(),static_cast(u),mpreal::get_default_rnd()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline const mpreal operator<<(const mpreal& v, const unsigned long int k) -{ - return mul_2ui(v,k); -} - -inline const mpreal operator<<(const mpreal& v, const unsigned int k) -{ - return mul_2ui(v,static_cast(k)); -} - -inline const mpreal operator<<(const mpreal& v, const long int k) -{ - return mul_2si(v,k); -} - -inline const mpreal operator<<(const mpreal& v, const int k) -{ - return mul_2si(v,static_cast(k)); -} - -inline const mpreal operator>>(const mpreal& v, const unsigned long int k) -{ - return div_2ui(v,k); -} - -inline const mpreal operator>>(const mpreal& v, const long int k) -{ - return div_2si(v,k); -} - -inline const mpreal operator>>(const mpreal& v, const unsigned int k) -{ - return div_2ui(v,static_cast(k)); -} - -inline const mpreal operator>>(const mpreal& v, const int k) -{ - return div_2si(v,static_cast(k)); -} - -// mul_2ui -inline const mpreal mul_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode) -{ - mpreal x(v); - mpfr_mul_2ui(x.mpfr_ptr(),v.mpfr_srcptr(),k,rnd_mode); - return x; -} - -// mul_2si -inline const mpreal mul_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode) -{ - mpreal x(v); - mpfr_mul_2si(x.mpfr_ptr(),v.mpfr_srcptr(),k,rnd_mode); - return x; -} - -inline const mpreal div_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode) -{ - mpreal x(v); - mpfr_div_2ui(x.mpfr_ptr(),v.mpfr_srcptr(),k,rnd_mode); - return x; -} - -inline const mpreal div_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode) -{ - mpreal x(v); - mpfr_div_2si(x.mpfr_ptr(),v.mpfr_srcptr(),k,rnd_mode); - return x; -} - -////////////////////////////////////////////////////////////////////////// -//Relational operators - -// WARNING: -// -// Please note that following checks for double-NaN are guaranteed to work only in IEEE math mode: -// -// isnan(b) = (b != b) -// isnan(b) = !(b == b) (we use in code below) -// -// Be cautions if you use compiler options which break strict IEEE compliance (e.g. -ffast-math in GCC). -// Use std::isnan instead (C++11). - -inline bool operator > (const mpreal& a, const mpreal& b ){ return (mpfr_greater_p(a.mpfr_srcptr(),b.mpfr_srcptr()) != 0 ); } -inline bool operator > (const mpreal& a, const unsigned long int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) > 0 ); } -inline bool operator > (const mpreal& a, const unsigned int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) > 0 ); } -inline bool operator > (const mpreal& a, const long int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) > 0 ); } -inline bool operator > (const mpreal& a, const int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) > 0 ); } -inline bool operator > (const mpreal& a, const long double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_ld(a.mpfr_srcptr(),b) > 0 ); } -inline bool operator > (const mpreal& a, const double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_d (a.mpfr_srcptr(),b) > 0 ); } - -inline bool operator >= (const mpreal& a, const mpreal& b ){ return (mpfr_greaterequal_p(a.mpfr_srcptr(),b.mpfr_srcptr()) != 0 ); } -inline bool operator >= (const mpreal& a, const unsigned long int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) >= 0 ); } -inline bool operator >= (const mpreal& a, const unsigned int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) >= 0 ); } -inline bool operator >= (const mpreal& a, const long int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) >= 0 ); } -inline bool operator >= (const mpreal& a, const int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) >= 0 ); } -inline bool operator >= (const mpreal& a, const long double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_ld(a.mpfr_srcptr(),b) >= 0 ); } -inline bool operator >= (const mpreal& a, const double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_d (a.mpfr_srcptr(),b) >= 0 ); } - -inline bool operator < (const mpreal& a, const mpreal& b ){ return (mpfr_less_p(a.mpfr_srcptr(),b.mpfr_srcptr()) != 0 ); } -inline bool operator < (const mpreal& a, const unsigned long int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) < 0 ); } -inline bool operator < (const mpreal& a, const unsigned int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) < 0 ); } -inline bool operator < (const mpreal& a, const long int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) < 0 ); } -inline bool operator < (const mpreal& a, const int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) < 0 ); } -inline bool operator < (const mpreal& a, const long double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_ld(a.mpfr_srcptr(),b) < 0 ); } -inline bool operator < (const mpreal& a, const double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_d (a.mpfr_srcptr(),b) < 0 ); } - -inline bool operator <= (const mpreal& a, const mpreal& b ){ return (mpfr_lessequal_p(a.mpfr_srcptr(),b.mpfr_srcptr()) != 0 ); } -inline bool operator <= (const mpreal& a, const unsigned long int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) <= 0 ); } -inline bool operator <= (const mpreal& a, const unsigned int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) <= 0 ); } -inline bool operator <= (const mpreal& a, const long int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) <= 0 ); } -inline bool operator <= (const mpreal& a, const int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) <= 0 ); } -inline bool operator <= (const mpreal& a, const long double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_ld(a.mpfr_srcptr(),b) <= 0 ); } -inline bool operator <= (const mpreal& a, const double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_d (a.mpfr_srcptr(),b) <= 0 ); } - -inline bool operator == (const mpreal& a, const mpreal& b ){ return (mpfr_equal_p(a.mpfr_srcptr(),b.mpfr_srcptr()) != 0 ); } -inline bool operator == (const mpreal& a, const unsigned long int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) == 0 ); } -inline bool operator == (const mpreal& a, const unsigned int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) == 0 ); } -inline bool operator == (const mpreal& a, const long int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) == 0 ); } -inline bool operator == (const mpreal& a, const int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) == 0 ); } -inline bool operator == (const mpreal& a, const long double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_ld(a.mpfr_srcptr(),b) == 0 ); } -inline bool operator == (const mpreal& a, const double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_d (a.mpfr_srcptr(),b) == 0 ); } - -inline bool operator != (const mpreal& a, const mpreal& b ){ return !(a == b); } -inline bool operator != (const mpreal& a, const unsigned long int b ){ return !(a == b); } -inline bool operator != (const mpreal& a, const unsigned int b ){ return !(a == b); } -inline bool operator != (const mpreal& a, const long int b ){ return !(a == b); } -inline bool operator != (const mpreal& a, const int b ){ return !(a == b); } -inline bool operator != (const mpreal& a, const long double b ){ return !(a == b); } -inline bool operator != (const mpreal& a, const double b ){ return !(a == b); } - -inline bool isnan (const mpreal& op){ return (mpfr_nan_p (op.mpfr_srcptr()) != 0 ); } -inline bool isinf (const mpreal& op){ return (mpfr_inf_p (op.mpfr_srcptr()) != 0 ); } -inline bool isfinite (const mpreal& op){ return (mpfr_number_p (op.mpfr_srcptr()) != 0 ); } -inline bool iszero (const mpreal& op){ return (mpfr_zero_p (op.mpfr_srcptr()) != 0 ); } -inline bool isint (const mpreal& op){ return (mpfr_integer_p(op.mpfr_srcptr()) != 0 ); } - -#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) -inline bool isregular(const mpreal& op){ return (mpfr_regular_p(op.mpfr_srcptr()));} -#endif - -////////////////////////////////////////////////////////////////////////// -// Type Converters -inline bool mpreal::toBool ( ) const { return mpfr_zero_p (mpfr_srcptr()) == 0; } -inline long mpreal::toLong (mp_rnd_t mode) const { return mpfr_get_si (mpfr_srcptr(), mode); } -inline unsigned long mpreal::toULong (mp_rnd_t mode) const { return mpfr_get_ui (mpfr_srcptr(), mode); } -inline float mpreal::toFloat (mp_rnd_t mode) const { return mpfr_get_flt(mpfr_srcptr(), mode); } -inline double mpreal::toDouble (mp_rnd_t mode) const { return mpfr_get_d (mpfr_srcptr(), mode); } -inline long double mpreal::toLDouble(mp_rnd_t mode) const { return mpfr_get_ld (mpfr_srcptr(), mode); } -inline long long mpreal::toLLong (mp_rnd_t mode) const { return mpfr_get_sj (mpfr_srcptr(), mode); } -inline unsigned long long mpreal::toULLong (mp_rnd_t mode) const { return mpfr_get_uj (mpfr_srcptr(), mode); } - -inline ::mpfr_ptr mpreal::mpfr_ptr() { return mp; } -inline ::mpfr_srcptr mpreal::mpfr_ptr() const { return mp; } -inline ::mpfr_srcptr mpreal::mpfr_srcptr() const { return mp; } - -template -inline std::string toString(T t, std::ios_base & (*f)(std::ios_base&)) -{ - std::ostringstream oss; - oss << f << t; - return oss.str(); -} - -#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) - -inline std::string mpreal::toString(const std::string& format) const -{ - char *s = NULL; - std::string out; - - if( !format.empty() ) - { - if(!(mpfr_asprintf(&s, format.c_str(), mpfr_srcptr()) < 0)) - { - out = std::string(s); - - mpfr_free_str(s); - } - } - - return out; -} - -#endif - -inline std::string mpreal::toString(int n, int b, mp_rnd_t mode) const -{ - // TODO: Add extended format specification (f, e, rounding mode) as it done in output operator - (void)b; - (void)mode; - -#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) - - std::ostringstream format; - - int digits = (n >= 0) ? n : 1 + bits2digits(mpfr_get_prec(mpfr_srcptr())); - - format << "%." << digits << "RNg"; - - return toString(format.str()); - -#else - - char *s, *ns = NULL; - size_t slen, nslen; - mp_exp_t exp; - std::string out; - - if(mpfr_inf_p(mp)) - { - if(mpfr_sgn(mp)>0) return "+Inf"; - else return "-Inf"; - } - - if(mpfr_zero_p(mp)) return "0"; - if(mpfr_nan_p(mp)) return "NaN"; - - s = mpfr_get_str(NULL, &exp, b, 0, mp, mode); - ns = mpfr_get_str(NULL, &exp, b, (std::max)(0,n), mp, mode); - - if(s!=NULL && ns!=NULL) - { - slen = strlen(s); - nslen = strlen(ns); - if(nslen<=slen) - { - mpfr_free_str(s); - s = ns; - slen = nslen; - } - else { - mpfr_free_str(ns); - } - - // Make human eye-friendly formatting if possible - if (exp>0 && static_cast(exp)s+exp) ptr--; - - if(ptr==s+exp) out = std::string(s,exp+1); - else out = std::string(s,exp+1)+'.'+std::string(s+exp+1,ptr-(s+exp+1)+1); - - //out = string(s,exp+1)+'.'+string(s+exp+1); - } - else - { - // Remove zeros starting from right end - char* ptr = s+slen-1; - while (*ptr=='0' && ptr>s+exp-1) ptr--; - - if(ptr==s+exp-1) out = std::string(s,exp); - else out = std::string(s,exp)+'.'+std::string(s+exp,ptr-(s+exp)+1); - - //out = string(s,exp)+'.'+string(s+exp); - } - - }else{ // exp<0 || exp>slen - if(s[0]=='-') - { - // Remove zeros starting from right end - char* ptr = s+slen-1; - while (*ptr=='0' && ptr>s+1) ptr--; - - if(ptr==s+1) out = std::string(s,2); - else out = std::string(s,2)+'.'+std::string(s+2,ptr-(s+2)+1); - - //out = string(s,2)+'.'+string(s+2); - } - else - { - // Remove zeros starting from right end - char* ptr = s+slen-1; - while (*ptr=='0' && ptr>s) ptr--; - - if(ptr==s) out = std::string(s,1); - else out = std::string(s,1)+'.'+std::string(s+1,ptr-(s+1)+1); - - //out = string(s,1)+'.'+string(s+1); - } - - // Make final string - if(--exp) - { - if(exp>0) out += "e+"+mpfr::toString(exp,std::dec); - else out += "e"+mpfr::toString(exp,std::dec); - } - } - - mpfr_free_str(s); - return out; - }else{ - return "conversion error!"; - } -#endif -} - - -////////////////////////////////////////////////////////////////////////// -// I/O -inline std::ostream& mpreal::output(std::ostream& os) const -{ - std::ostringstream format; - const std::ios::fmtflags flags = os.flags(); - - format << ((flags & std::ios::showpos) ? "%+" : "%"); - if (os.precision() >= 0) - format << '.' << os.precision() << "R*" - << ((flags & std::ios::floatfield) == std::ios::fixed ? 'f' : - (flags & std::ios::floatfield) == std::ios::scientific ? 'e' : - 'g'); - else - format << "R*e"; - - char *s = NULL; - if(!(mpfr_asprintf(&s, format.str().c_str(), - mpfr::mpreal::get_default_rnd(), - mpfr_srcptr()) - < 0)) - { - os << std::string(s); - mpfr_free_str(s); - } - return os; -} - -inline std::ostream& operator<<(std::ostream& os, const mpreal& v) -{ - return v.output(os); -} - -inline std::istream& operator>>(std::istream &is, mpreal& v) -{ - // TODO: use cout::hexfloat and other flags to setup base - std::string tmp; - is >> tmp; - mpfr_set_str(v.mpfr_ptr(), tmp.c_str(), 10, mpreal::get_default_rnd()); - return is; -} - -////////////////////////////////////////////////////////////////////////// -// Bits - decimal digits relation -// bits = ceil(digits*log[2](10)) -// digits = floor(bits*log[10](2)) - -inline mp_prec_t digits2bits(int d) -{ - const double LOG2_10 = 3.3219280948873624; - - return mp_prec_t(std::ceil( d * LOG2_10 )); -} - -inline int bits2digits(mp_prec_t b) -{ - const double LOG10_2 = 0.30102999566398119; - - return int(std::floor( b * LOG10_2 )); -} - -////////////////////////////////////////////////////////////////////////// -// Set/Get number properties -inline int sgn(const mpreal& op) -{ - return mpfr_sgn(op.mpfr_srcptr()); -} - -inline mpreal& mpreal::setSign(int sign, mp_rnd_t RoundingMode) -{ - mpfr_setsign(mpfr_ptr(), mpfr_srcptr(), (sign < 0 ? 1 : 0), RoundingMode); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline int mpreal::getPrecision() const -{ - return int(mpfr_get_prec(mpfr_srcptr())); -} - -inline mpreal& mpreal::setPrecision(int Precision, mp_rnd_t RoundingMode) -{ - mpfr_prec_round(mpfr_ptr(), Precision, RoundingMode); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::setInf(int sign) -{ - mpfr_set_inf(mpfr_ptr(), sign); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::setNan() -{ - mpfr_set_nan(mpfr_ptr()); - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mpreal& mpreal::setZero(int sign) -{ -#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) - mpfr_set_zero(mpfr_ptr(), sign); -#else - mpfr_set_si(mpfr_ptr(), 0, (mpfr_get_default_rounding_mode)()); - setSign(sign); -#endif - - MPREAL_MSVC_DEBUGVIEW_CODE; - return *this; -} - -inline mp_prec_t mpreal::get_prec() const -{ - return mpfr_get_prec(mpfr_srcptr()); -} - -inline void mpreal::set_prec(mp_prec_t prec, mp_rnd_t rnd_mode) -{ - mpfr_prec_round(mpfr_ptr(),prec,rnd_mode); - MPREAL_MSVC_DEBUGVIEW_CODE; -} - -inline mp_exp_t mpreal::get_exp () -{ - return mpfr_get_exp(mpfr_srcptr()); -} - -inline int mpreal::set_exp (mp_exp_t e) -{ - int x = mpfr_set_exp(mpfr_ptr(), e); - MPREAL_MSVC_DEBUGVIEW_CODE; - return x; -} - -inline const mpreal frexp(const mpreal& v, mp_exp_t* exp) -{ - mpreal x(v); - *exp = x.get_exp(); - x.set_exp(0); - return x; -} - -inline const mpreal ldexp(const mpreal& v, mp_exp_t exp) -{ - mpreal x(v); - - // rounding is not important since we are just increasing the exponent (= exact operation) - mpfr_mul_2si(x.mpfr_ptr(), x.mpfr_srcptr(), exp, mpreal::get_default_rnd()); - return x; -} - -inline const mpreal scalbn(const mpreal& v, mp_exp_t exp) -{ - return ldexp(v, exp); -} - -inline mpreal machine_epsilon(mp_prec_t prec) -{ - /* the smallest eps such that 1 + eps != 1 */ - return machine_epsilon(mpreal(1, prec)); -} - -inline mpreal machine_epsilon(const mpreal& x) -{ - /* the smallest eps such that x + eps != x */ - if( x < 0) - { - return nextabove(-x) + x; - }else{ - return nextabove( x) - x; - } -} - -// minval is 'safe' meaning 1 / minval does not overflow -inline mpreal minval(mp_prec_t prec) -{ - /* min = 1/2 * 2^emin = 2^(emin - 1) */ - return mpreal(1, prec) << mpreal::get_emin()-1; -} - -// maxval is 'safe' meaning 1 / maxval does not underflow -inline mpreal maxval(mp_prec_t prec) -{ - /* max = (1 - eps) * 2^emax, eps is machine epsilon */ - return (mpreal(1, prec) - machine_epsilon(prec)) << mpreal::get_emax(); -} - -inline bool isEqualUlps(const mpreal& a, const mpreal& b, int maxUlps) -{ - return abs(a - b) <= machine_epsilon((max)(abs(a), abs(b))) * maxUlps; -} - -inline bool isEqualFuzzy(const mpreal& a, const mpreal& b, const mpreal& eps) -{ - return abs(a - b) <= eps; -} - -inline bool isEqualFuzzy(const mpreal& a, const mpreal& b) -{ - return isEqualFuzzy(a, b, machine_epsilon((max)(1, (min)(abs(a), abs(b))))); -} - -////////////////////////////////////////////////////////////////////////// -// C++11 sign functions. -inline mpreal copysign(const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal rop(0, mpfr_get_prec(x.mpfr_ptr())); - mpfr_setsign(rop.mpfr_ptr(), x.mpfr_srcptr(), mpfr_signbit(y.mpfr_srcptr()), rnd_mode); - return rop; -} - -inline bool signbit(const mpreal& x) -{ - return mpfr_signbit(x.mpfr_srcptr()); -} - -inline const mpreal modf(const mpreal& v, mpreal& n) -{ - mpreal f(v); - - // rounding is not important since we are using the same number - mpfr_frac (f.mpfr_ptr(),f.mpfr_srcptr(),mpreal::get_default_rnd()); - mpfr_trunc(n.mpfr_ptr(),v.mpfr_srcptr()); - return f; -} - -inline int mpreal::check_range (int t, mp_rnd_t rnd_mode) -{ - return mpfr_check_range(mpfr_ptr(),t,rnd_mode); -} - -inline int mpreal::subnormalize (int t,mp_rnd_t rnd_mode) -{ - int r = mpfr_subnormalize(mpfr_ptr(),t,rnd_mode); - MPREAL_MSVC_DEBUGVIEW_CODE; - return r; -} - -inline mp_exp_t mpreal::get_emin (void) -{ - return mpfr_get_emin(); -} - -inline int mpreal::set_emin (mp_exp_t exp) -{ - return mpfr_set_emin(exp); -} - -inline mp_exp_t mpreal::get_emax (void) -{ - return mpfr_get_emax(); -} - -inline int mpreal::set_emax (mp_exp_t exp) -{ - return mpfr_set_emax(exp); -} - -inline mp_exp_t mpreal::get_emin_min (void) -{ - return mpfr_get_emin_min(); -} - -inline mp_exp_t mpreal::get_emin_max (void) -{ - return mpfr_get_emin_max(); -} - -inline mp_exp_t mpreal::get_emax_min (void) -{ - return mpfr_get_emax_min(); -} - -inline mp_exp_t mpreal::get_emax_max (void) -{ - return mpfr_get_emax_max(); -} - -////////////////////////////////////////////////////////////////////////// -// Mathematical Functions -////////////////////////////////////////////////////////////////////////// -#define MPREAL_UNARY_MATH_FUNCTION_BODY(f) \ - mpreal y(0, mpfr_get_prec(x.mpfr_srcptr())); \ - mpfr_##f(y.mpfr_ptr(), x.mpfr_srcptr(), r); \ - return y; - -inline const mpreal sqr (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) -{ MPREAL_UNARY_MATH_FUNCTION_BODY(sqr ); } - -inline const mpreal sqrt (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) -{ MPREAL_UNARY_MATH_FUNCTION_BODY(sqrt); } - -inline const mpreal sqrt(const unsigned long int x, mp_rnd_t r) -{ - mpreal y; - mpfr_sqrt_ui(y.mpfr_ptr(), x, r); - return y; -} - -inline const mpreal sqrt(const unsigned int v, mp_rnd_t rnd_mode) -{ - return sqrt(static_cast(v),rnd_mode); -} - -inline const mpreal sqrt(const long int v, mp_rnd_t rnd_mode) -{ - if (v>=0) return sqrt(static_cast(v),rnd_mode); - else return mpreal().setNan(); // NaN -} - -inline const mpreal sqrt(const int v, mp_rnd_t rnd_mode) -{ - if (v>=0) return sqrt(static_cast(v),rnd_mode); - else return mpreal().setNan(); // NaN -} - -inline const mpreal root(const mpreal& x, unsigned long int k, mp_rnd_t r = mpreal::get_default_rnd()) -{ - mpreal y(0, mpfr_get_prec(x.mpfr_srcptr())); - mpfr_root(y.mpfr_ptr(), x.mpfr_srcptr(), k, r); - return y; -} - -inline const mpreal dim(const mpreal& a, const mpreal& b, mp_rnd_t r = mpreal::get_default_rnd()) -{ - mpreal y(0, mpfr_get_prec(a.mpfr_srcptr())); - mpfr_dim(y.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), r); - return y; -} - -inline int cmpabs(const mpreal& a,const mpreal& b) -{ - return mpfr_cmpabs(a.mpfr_ptr(), b.mpfr_srcptr()); -} - -inline int sin_cos(mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - return mpfr_sin_cos(s.mpfr_ptr(), c.mpfr_ptr(), v.mpfr_srcptr(), rnd_mode); -} - -inline const mpreal sqrt (const long double v, mp_rnd_t rnd_mode) { return sqrt(mpreal(v),rnd_mode); } -inline const mpreal sqrt (const double v, mp_rnd_t rnd_mode) { return sqrt(mpreal(v),rnd_mode); } - -inline const mpreal cbrt (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(cbrt ); } -inline const mpreal fabs (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(abs ); } -inline const mpreal abs (const mpreal& x, mp_rnd_t r) { MPREAL_UNARY_MATH_FUNCTION_BODY(abs ); } -inline const mpreal log (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(log ); } -inline const mpreal log2 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(log2 ); } -inline const mpreal log10 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(log10); } -inline const mpreal exp (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(exp ); } -inline const mpreal exp2 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(exp2 ); } -inline const mpreal exp10 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(exp10); } -inline const mpreal cos (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(cos ); } -inline const mpreal sin (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sin ); } -inline const mpreal tan (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(tan ); } -inline const mpreal sec (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sec ); } -inline const mpreal csc (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(csc ); } -inline const mpreal cot (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(cot ); } -inline const mpreal acos (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(acos ); } -inline const mpreal asin (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(asin ); } -inline const mpreal atan (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(atan ); } - -inline const mpreal logb (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { return log2 (abs(x),r); } - -inline const mpreal acot (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return atan (1/v, r); } -inline const mpreal asec (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return acos (1/v, r); } -inline const mpreal acsc (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return asin (1/v, r); } -inline const mpreal acoth (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return atanh(1/v, r); } -inline const mpreal asech (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return acosh(1/v, r); } -inline const mpreal acsch (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return asinh(1/v, r); } - -inline const mpreal cosh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(cosh ); } -inline const mpreal sinh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sinh ); } -inline const mpreal tanh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(tanh ); } -inline const mpreal sech (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sech ); } -inline const mpreal csch (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(csch ); } -inline const mpreal coth (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(coth ); } -inline const mpreal acosh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(acosh); } -inline const mpreal asinh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(asinh); } -inline const mpreal atanh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(atanh); } - -inline const mpreal log1p (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(log1p ); } -inline const mpreal expm1 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(expm1 ); } -inline const mpreal eint (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(eint ); } -inline const mpreal gamma (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(gamma ); } -inline const mpreal tgamma (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(gamma ); } -inline const mpreal lngamma (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(lngamma); } -inline const mpreal zeta (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(zeta ); } -inline const mpreal erf (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(erf ); } -inline const mpreal erfc (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(erfc ); } -inline const mpreal besselj0(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(j0 ); } -inline const mpreal besselj1(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(j1 ); } -inline const mpreal bessely0(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(y0 ); } -inline const mpreal bessely1(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(y1 ); } - -inline const mpreal atan2 (const mpreal& y, const mpreal& x, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal a(0,(std::max)(y.getPrecision(), x.getPrecision())); - mpfr_atan2(a.mpfr_ptr(), y.mpfr_srcptr(), x.mpfr_srcptr(), rnd_mode); - return a; -} - -inline const mpreal hypot (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal a(0,(std::max)(y.getPrecision(), x.getPrecision())); - mpfr_hypot(a.mpfr_ptr(), x.mpfr_srcptr(), y.mpfr_srcptr(), rnd_mode); - return a; -} - -inline const mpreal remainder (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal a(0,(std::max)(y.getPrecision(), x.getPrecision())); - mpfr_remainder(a.mpfr_ptr(), x.mpfr_srcptr(), y.mpfr_srcptr(), rnd_mode); - return a; -} - -inline const mpreal remquo (long* q, const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal a(0,(std::max)(y.getPrecision(), x.getPrecision())); - mpfr_remquo(a.mpfr_ptr(),q, x.mpfr_srcptr(), y.mpfr_srcptr(), rnd_mode); - return a; -} - -inline const mpreal fac_ui (unsigned long int v, mp_prec_t prec = mpreal::get_default_prec(), - mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal x(0, prec); - mpfr_fac_ui(x.mpfr_ptr(),v,rnd_mode); - return x; -} - - -inline const mpreal lgamma (const mpreal& v, int *signp = 0, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal x(v); - int tsignp; - - if(signp) mpfr_lgamma(x.mpfr_ptr(), signp,v.mpfr_srcptr(),rnd_mode); - else mpfr_lgamma(x.mpfr_ptr(),&tsignp,v.mpfr_srcptr(),rnd_mode); - - return x; -} - - -inline const mpreal besseljn (long n, const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) -{ - mpreal y(0, x.getPrecision()); - mpfr_jn(y.mpfr_ptr(), n, x.mpfr_srcptr(), r); - return y; -} - -inline const mpreal besselyn (long n, const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) -{ - mpreal y(0, x.getPrecision()); - mpfr_yn(y.mpfr_ptr(), n, x.mpfr_srcptr(), r); - return y; -} - -inline const mpreal fma (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal a; - mp_prec_t p1, p2, p3; - - p1 = v1.get_prec(); - p2 = v2.get_prec(); - p3 = v3.get_prec(); - - a.set_prec(p3>p2?(p3>p1?p3:p1):(p2>p1?p2:p1)); - - mpfr_fma(a.mp,v1.mp,v2.mp,v3.mp,rnd_mode); - return a; -} - -inline const mpreal fms (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal a; - mp_prec_t p1, p2, p3; - - p1 = v1.get_prec(); - p2 = v2.get_prec(); - p3 = v3.get_prec(); - - a.set_prec(p3>p2?(p3>p1?p3:p1):(p2>p1?p2:p1)); - - mpfr_fms(a.mp,v1.mp,v2.mp,v3.mp,rnd_mode); - return a; -} - -inline const mpreal agm (const mpreal& v1, const mpreal& v2, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal a; - mp_prec_t p1, p2; - - p1 = v1.get_prec(); - p2 = v2.get_prec(); - - a.set_prec(p1>p2?p1:p2); - - mpfr_agm(a.mp, v1.mp, v2.mp, rnd_mode); - - return a; -} - -inline const mpreal sum (const mpreal tab[], const unsigned long int n, int& status, mp_rnd_t mode = mpreal::get_default_rnd()) -{ - mpfr_srcptr *p = new mpfr_srcptr[n]; - - for (unsigned long int i = 0; i < n; i++) - p[i] = tab[i].mpfr_srcptr(); - - mpreal x; - status = mpfr_sum(x.mpfr_ptr(), (mpfr_ptr*)p, n, mode); - - delete [] p; - return x; -} - -////////////////////////////////////////////////////////////////////////// -// MPFR 2.4.0 Specifics -#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) - -inline int sinh_cosh(mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - return mpfr_sinh_cosh(s.mp,c.mp,v.mp,rnd_mode); -} - -inline const mpreal li2 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) -{ - MPREAL_UNARY_MATH_FUNCTION_BODY(li2); -} - -inline const mpreal rem (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - /* R = rem(X,Y) if Y != 0, returns X - n * Y where n = trunc(X/Y). */ - return fmod(x, y, rnd_mode); -} - -inline const mpreal mod (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - (void)rnd_mode; - - /* - - m = mod(x,y) if y != 0, returns x - n*y where n = floor(x/y) - - The following are true by convention: - - mod(x,0) is x - - mod(x,x) is 0 - - mod(x,y) for x != y and y != 0 has the same sign as y. - - */ - - if(iszero(y)) return x; - if(x == y) return 0; - - mpreal m = x - floor(x / y) * y; - - m.setSign(sgn(y)); // make sure result has the same sign as Y - - return m; -} - -inline const mpreal fmod (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal a; - mp_prec_t yp, xp; - - yp = y.get_prec(); - xp = x.get_prec(); - - a.set_prec(yp>xp?yp:xp); - - mpfr_fmod(a.mp, x.mp, y.mp, rnd_mode); - - return a; -} - -inline const mpreal rec_sqrt(const mpreal& v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal x(v); - mpfr_rec_sqrt(x.mp,v.mp,rnd_mode); - return x; -} -#endif // MPFR 2.4.0 Specifics - -////////////////////////////////////////////////////////////////////////// -// MPFR 3.0.0 Specifics -#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) -inline const mpreal digamma (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(digamma); } -inline const mpreal ai (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(ai); } -#endif // MPFR 3.0.0 Specifics - -////////////////////////////////////////////////////////////////////////// -// Constants -inline const mpreal const_log2 (mp_prec_t p = mpreal::get_default_prec(), mp_rnd_t r = mpreal::get_default_rnd()) -{ - mpreal x(0, p); - mpfr_const_log2(x.mpfr_ptr(), r); - return x; -} - -inline const mpreal const_pi (mp_prec_t p = mpreal::get_default_prec(), mp_rnd_t r = mpreal::get_default_rnd()) -{ - mpreal x(0, p); - mpfr_const_pi(x.mpfr_ptr(), r); - return x; -} - -inline const mpreal const_euler (mp_prec_t p = mpreal::get_default_prec(), mp_rnd_t r = mpreal::get_default_rnd()) -{ - mpreal x(0, p); - mpfr_const_euler(x.mpfr_ptr(), r); - return x; -} - -inline const mpreal const_catalan (mp_prec_t p = mpreal::get_default_prec(), mp_rnd_t r = mpreal::get_default_rnd()) -{ - mpreal x(0, p); - mpfr_const_catalan(x.mpfr_ptr(), r); - return x; -} - -inline const mpreal const_infinity (int sign = 1, mp_prec_t p = mpreal::get_default_prec()) -{ - mpreal x(0, p); - mpfr_set_inf(x.mpfr_ptr(), sign); - return x; -} - -////////////////////////////////////////////////////////////////////////// -// Integer Related Functions -inline const mpreal ceil(const mpreal& v) -{ - mpreal x(v); - mpfr_ceil(x.mp,v.mp); - return x; -} - -inline const mpreal floor(const mpreal& v) -{ - mpreal x(v); - mpfr_floor(x.mp,v.mp); - return x; -} - -inline const mpreal round(const mpreal& v) -{ - mpreal x(v); - mpfr_round(x.mp,v.mp); - return x; -} - -inline const mpreal trunc(const mpreal& v) -{ - mpreal x(v); - mpfr_trunc(x.mp,v.mp); - return x; -} - -inline const mpreal rint (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint ); } -inline const mpreal rint_ceil (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint_ceil ); } -inline const mpreal rint_floor (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint_floor); } -inline const mpreal rint_round (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint_round); } -inline const mpreal rint_trunc (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint_trunc); } -inline const mpreal frac (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(frac ); } - -////////////////////////////////////////////////////////////////////////// -// Miscellaneous Functions -inline void swap (mpreal& a, mpreal& b) { mpfr_swap(a.mp,b.mp); } -inline const mpreal (max)(const mpreal& x, const mpreal& y){ return (x>y?x:y); } -inline const mpreal (min)(const mpreal& x, const mpreal& y){ return (x= MPFR_VERSION_NUM(3,0,0)) -inline const mpreal urandom (gmp_randstate_t& state, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal x; - mpfr_urandom(x.mpfr_ptr(), state, rnd_mode); - return x; -} -#endif - -#if (MPFR_VERSION <= MPFR_VERSION_NUM(2,4,2)) -inline const mpreal random2 (mp_size_t size, mp_exp_t exp) -{ - mpreal x; - mpfr_random2(x.mpfr_ptr(),size,exp); - return x; -} -#endif - -// Uniformly distributed random number generation -// a = random(seed); <- initialization & first random number generation -// a = random(); <- next random numbers generation -// seed != 0 -inline const mpreal random(unsigned int seed = 0) -{ -#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) - static gmp_randstate_t state; - static bool initialize = true; - - if(initialize) - { - gmp_randinit_default(state); - gmp_randseed_ui(state,0); - initialize = false; - } - - if(seed != 0) gmp_randseed_ui(state,seed); - - return mpfr::urandom(state); -#else - if(seed != 0) std::srand(seed); - return mpfr::mpreal(std::rand()/(double)RAND_MAX); -#endif - -} - -#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,1,0)) - -inline const mpreal grandom (gmp_randstate_t& state, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal x; - mpfr_grandom(x.mpfr_ptr(), NULL, state, rnd_mode); - return x; -} - -inline const mpreal grandom(unsigned int seed = 0) -{ - static gmp_randstate_t state; - static bool initialize = true; - - if(initialize) - { - gmp_randinit_default(state); - gmp_randseed_ui(state,0); - initialize = false; - } - - if(seed != 0) gmp_randseed_ui(state,seed); - - return mpfr::grandom(state); -} -#endif - -////////////////////////////////////////////////////////////////////////// -// Set/Get global properties -inline void mpreal::set_default_prec(mp_prec_t prec) -{ - mpfr_set_default_prec(prec); -} - -inline void mpreal::set_default_rnd(mp_rnd_t rnd_mode) -{ - mpfr_set_default_rounding_mode(rnd_mode); -} - -inline bool mpreal::fits_in_bits(double x, int n) -{ - int i; - double t; - return IsInf(x) || (std::modf ( std::ldexp ( std::frexp ( x, &i ), n ), &t ) == 0.0); -} - -inline const mpreal pow(const mpreal& a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal x(a); - mpfr_pow(x.mp,x.mp,b.mp,rnd_mode); - return x; -} - -inline const mpreal pow(const mpreal& a, const mpz_t b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal x(a); - mpfr_pow_z(x.mp,x.mp,b,rnd_mode); - return x; -} - -inline const mpreal pow(const mpreal& a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal x(a); - mpfr_pow_ui(x.mp,x.mp,b,rnd_mode); - return x; -} - -inline const mpreal pow(const mpreal& a, const unsigned int b, mp_rnd_t rnd_mode) -{ - return pow(a,static_cast(b),rnd_mode); -} - -inline const mpreal pow(const mpreal& a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal x(a); - mpfr_pow_si(x.mp,x.mp,b,rnd_mode); - return x; -} - -inline const mpreal pow(const mpreal& a, const int b, mp_rnd_t rnd_mode) -{ - return pow(a,static_cast(b),rnd_mode); -} - -inline const mpreal pow(const mpreal& a, const long double b, mp_rnd_t rnd_mode) -{ - return pow(a,mpreal(b),rnd_mode); -} - -inline const mpreal pow(const mpreal& a, const double b, mp_rnd_t rnd_mode) -{ - return pow(a,mpreal(b),rnd_mode); -} - -inline const mpreal pow(const unsigned long int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) -{ - mpreal x(a); - mpfr_ui_pow(x.mp,a,b.mp,rnd_mode); - return x; -} - -inline const mpreal pow(const unsigned int a, const mpreal& b, mp_rnd_t rnd_mode) -{ - return pow(static_cast(a),b,rnd_mode); -} - -inline const mpreal pow(const long int a, const mpreal& b, mp_rnd_t rnd_mode) -{ - if (a>=0) return pow(static_cast(a),b,rnd_mode); - else return pow(mpreal(a),b,rnd_mode); -} - -inline const mpreal pow(const int a, const mpreal& b, mp_rnd_t rnd_mode) -{ - if (a>=0) return pow(static_cast(a),b,rnd_mode); - else return pow(mpreal(a),b,rnd_mode); -} - -inline const mpreal pow(const long double a, const mpreal& b, mp_rnd_t rnd_mode) -{ - return pow(mpreal(a),b,rnd_mode); -} - -inline const mpreal pow(const double a, const mpreal& b, mp_rnd_t rnd_mode) -{ - return pow(mpreal(a),b,rnd_mode); -} - -// pow unsigned long int -inline const mpreal pow(const unsigned long int a, const unsigned long int b, mp_rnd_t rnd_mode) -{ - mpreal x(a); - mpfr_ui_pow_ui(x.mp,a,b,rnd_mode); - return x; -} - -inline const mpreal pow(const unsigned long int a, const unsigned int b, mp_rnd_t rnd_mode) -{ - return pow(a,static_cast(b),rnd_mode); //mpfr_ui_pow_ui -} - -inline const mpreal pow(const unsigned long int a, const long int b, mp_rnd_t rnd_mode) -{ - if(b>0) return pow(a,static_cast(b),rnd_mode); //mpfr_ui_pow_ui - else return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow -} - -inline const mpreal pow(const unsigned long int a, const int b, mp_rnd_t rnd_mode) -{ - if(b>0) return pow(a,static_cast(b),rnd_mode); //mpfr_ui_pow_ui - else return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow -} - -inline const mpreal pow(const unsigned long int a, const long double b, mp_rnd_t rnd_mode) -{ - return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow -} - -inline const mpreal pow(const unsigned long int a, const double b, mp_rnd_t rnd_mode) -{ - return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow -} - -// pow unsigned int -inline const mpreal pow(const unsigned int a, const unsigned long int b, mp_rnd_t rnd_mode) -{ - return pow(static_cast(a),b,rnd_mode); //mpfr_ui_pow_ui -} - -inline const mpreal pow(const unsigned int a, const unsigned int b, mp_rnd_t rnd_mode) -{ - return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui -} - -inline const mpreal pow(const unsigned int a, const long int b, mp_rnd_t rnd_mode) -{ - if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui - else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow -} - -inline const mpreal pow(const unsigned int a, const int b, mp_rnd_t rnd_mode) -{ - if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui - else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow -} - -inline const mpreal pow(const unsigned int a, const long double b, mp_rnd_t rnd_mode) -{ - return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow -} - -inline const mpreal pow(const unsigned int a, const double b, mp_rnd_t rnd_mode) -{ - return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow -} - -// pow long int -inline const mpreal pow(const long int a, const unsigned long int b, mp_rnd_t rnd_mode) -{ - if (a>0) return pow(static_cast(a),b,rnd_mode); //mpfr_ui_pow_ui - else return pow(mpreal(a),b,rnd_mode); //mpfr_pow_ui -} - -inline const mpreal pow(const long int a, const unsigned int b, mp_rnd_t rnd_mode) -{ - if (a>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui - else return pow(mpreal(a),static_cast(b),rnd_mode); //mpfr_pow_ui -} - -inline const mpreal pow(const long int a, const long int b, mp_rnd_t rnd_mode) -{ - if (a>0) - { - if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui - else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow - }else{ - return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si - } -} - -inline const mpreal pow(const long int a, const int b, mp_rnd_t rnd_mode) -{ - if (a>0) - { - if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui - else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow - }else{ - return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_si - } -} - -inline const mpreal pow(const long int a, const long double b, mp_rnd_t rnd_mode) -{ - if (a>=0) return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow - else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow -} - -inline const mpreal pow(const long int a, const double b, mp_rnd_t rnd_mode) -{ - if (a>=0) return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow - else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow -} - -// pow int -inline const mpreal pow(const int a, const unsigned long int b, mp_rnd_t rnd_mode) -{ - if (a>0) return pow(static_cast(a),b,rnd_mode); //mpfr_ui_pow_ui - else return pow(mpreal(a),b,rnd_mode); //mpfr_pow_ui -} - -inline const mpreal pow(const int a, const unsigned int b, mp_rnd_t rnd_mode) -{ - if (a>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui - else return pow(mpreal(a),static_cast(b),rnd_mode); //mpfr_pow_ui -} - -inline const mpreal pow(const int a, const long int b, mp_rnd_t rnd_mode) -{ - if (a>0) - { - if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui - else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow - }else{ - return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si - } -} - -inline const mpreal pow(const int a, const int b, mp_rnd_t rnd_mode) -{ - if (a>0) - { - if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui - else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow - }else{ - return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_si - } -} - -inline const mpreal pow(const int a, const long double b, mp_rnd_t rnd_mode) -{ - if (a>=0) return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow - else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow -} - -inline const mpreal pow(const int a, const double b, mp_rnd_t rnd_mode) -{ - if (a>=0) return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow - else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow -} - -// pow long double -inline const mpreal pow(const long double a, const long double b, mp_rnd_t rnd_mode) -{ - return pow(mpreal(a),mpreal(b),rnd_mode); -} - -inline const mpreal pow(const long double a, const unsigned long int b, mp_rnd_t rnd_mode) -{ - return pow(mpreal(a),b,rnd_mode); //mpfr_pow_ui -} - -inline const mpreal pow(const long double a, const unsigned int b, mp_rnd_t rnd_mode) -{ - return pow(mpreal(a),static_cast(b),rnd_mode); //mpfr_pow_ui -} - -inline const mpreal pow(const long double a, const long int b, mp_rnd_t rnd_mode) -{ - return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si -} - -inline const mpreal pow(const long double a, const int b, mp_rnd_t rnd_mode) -{ - return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_si -} - -inline const mpreal pow(const double a, const double b, mp_rnd_t rnd_mode) -{ - return pow(mpreal(a),mpreal(b),rnd_mode); -} - -inline const mpreal pow(const double a, const unsigned long int b, mp_rnd_t rnd_mode) -{ - return pow(mpreal(a),b,rnd_mode); // mpfr_pow_ui -} - -inline const mpreal pow(const double a, const unsigned int b, mp_rnd_t rnd_mode) -{ - return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_ui -} - -inline const mpreal pow(const double a, const long int b, mp_rnd_t rnd_mode) -{ - return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si -} - -inline const mpreal pow(const double a, const int b, mp_rnd_t rnd_mode) -{ - return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_si -} -} // End of mpfr namespace - -// Explicit specialization of std::swap for mpreal numbers -// Thus standard algorithms will use efficient version of swap (due to Koenig lookup) -// Non-throwing swap C++ idiom: http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-throwing_swap -namespace std -{ - // we are allowed to extend namespace std with specializations only - template <> - inline void swap(mpfr::mpreal& x, mpfr::mpreal& y) noexcept - { - return mpfr::swap(x, y); - } - - template<> - class numeric_limits - { - public: - static const bool is_specialized = true; - static const bool is_signed = true; - static const bool is_integer = false; - static const bool is_exact = false; - static const int radix = 2; - - static const bool has_infinity = true; - static const bool has_quiet_NaN = true; - static const bool has_signaling_NaN = true; - - static const bool is_iec559 = true; // = IEEE 754 - static const bool is_bounded = true; - static const bool is_modulo = false; - static const bool traps = true; - static const bool tinyness_before = true; - - static const float_denorm_style has_denorm = denorm_absent; - - inline static mpfr::mpreal (min) (mp_prec_t precision = mpfr::mpreal::get_default_prec()) { return mpfr::minval(precision); } - inline static mpfr::mpreal (max) (mp_prec_t precision = mpfr::mpreal::get_default_prec()) { return mpfr::maxval(precision); } - inline static mpfr::mpreal lowest (mp_prec_t precision = mpfr::mpreal::get_default_prec()) { return -mpfr::maxval(precision); } - - // Returns smallest eps such that 1 + eps != 1 (classic machine epsilon) - inline static mpfr::mpreal epsilon(mp_prec_t precision = mpfr::mpreal::get_default_prec()) { return mpfr::machine_epsilon(precision); } - - // Returns smallest eps such that x + eps != x (relative machine epsilon) - inline static mpfr::mpreal epsilon(const mpfr::mpreal& x) { return mpfr::machine_epsilon(x); } - - inline static mpfr::mpreal round_error(mp_prec_t precision = mpfr::mpreal::get_default_prec()) - { - mp_rnd_t r = mpfr::mpreal::get_default_rnd(); - - if(r == GMP_RNDN) return mpfr::mpreal(0.5, precision); - else return mpfr::mpreal(1.0, precision); - } - - inline static const mpfr::mpreal infinity() { return mpfr::const_infinity(); } - inline static const mpfr::mpreal quiet_NaN() { return mpfr::mpreal().setNan(); } - inline static const mpfr::mpreal signaling_NaN() { return mpfr::mpreal().setNan(); } - inline static const mpfr::mpreal denorm_min() { return (min)(); } - - // Please note, exponent range is not fixed in MPFR - static const int min_exponent = MPFR_EMIN_DEFAULT; - static const int max_exponent = MPFR_EMAX_DEFAULT; - MPREAL_PERMISSIVE_EXPR static const int min_exponent10 = (int) (MPFR_EMIN_DEFAULT * 0.3010299956639811); - MPREAL_PERMISSIVE_EXPR static const int max_exponent10 = (int) (MPFR_EMAX_DEFAULT * 0.3010299956639811); - -#ifdef MPREAL_HAVE_DYNAMIC_STD_NUMERIC_LIMITS - - // Following members should be constant according to standard, but they can be variable in MPFR - // So we define them as functions here. - // - // This is preferable way for std::numeric_limits specialization. - // But it is incompatible with standard std::numeric_limits and might not work with other libraries, e.g. boost. - // See below for compatible implementation. - inline static float_round_style round_style() - { - mp_rnd_t r = mpfr::mpreal::get_default_rnd(); - - switch (r) - { - case GMP_RNDN: return round_to_nearest; - case GMP_RNDZ: return round_toward_zero; - case GMP_RNDU: return round_toward_infinity; - case GMP_RNDD: return round_toward_neg_infinity; - default: return round_indeterminate; - } - } - - inline static int digits() { return int(mpfr::mpreal::get_default_prec()); } - inline static int digits(const mpfr::mpreal& x) { return x.getPrecision(); } - - inline static int digits10(mp_prec_t precision = mpfr::mpreal::get_default_prec()) - { - return mpfr::bits2digits(precision); - } - - inline static int digits10(const mpfr::mpreal& x) - { - return mpfr::bits2digits(x.getPrecision()); - } - - inline static int max_digits10(mp_prec_t precision = mpfr::mpreal::get_default_prec()) - { - return digits10(precision); - } -#else - // Digits and round_style are NOT constants when it comes to mpreal. - // If possible, please use functions digits() and round_style() defined above. - // - // These (default) values are preserved for compatibility with existing libraries, e.g. boost. - // Change them accordingly to your application. - // - // For example, if you use 256 bits of precision uniformly in your program, then: - // digits = 256 - // digits10 = 77 - // max_digits10 = 78 - // - // Approximate formula for decimal digits is: digits10 = floor(log10(2) * digits). See bits2digits() for more details. - - static const std::float_round_style round_style = round_to_nearest; - static const int digits = 53; - static const int digits10 = 15; - static const int max_digits10 = 16; -#endif - }; - -} - - -#ifdef _MSC_VER - #pragma warning(pop) -#else - #pragma GCC diagnostic pop -#endif - - - - -#endif /* __MPREAL_H__ */ diff --git a/meson.build b/meson.build index fc4943aa..b6beed46 100644 --- a/meson.build +++ b/meson.build @@ -193,11 +193,6 @@ source_files = files([ 'source/misc/identifier.cpp', 'source/misc/destructors.cpp', - 'source/repl/driver.cpp', - 'source/repl/execute.cpp', - 'source/repl/history.cpp', - 'source/repl/commands.cpp', - 'source/frontend/pts.cpp', 'source/frontend/file.cpp', 'source/frontend/lexer.cpp', @@ -231,7 +226,6 @@ source_files = files([ 'source/backend/interp/driver.cpp', - 'source/typecheck/misc.cpp', 'source/typecheck/call.cpp', 'source/typecheck/type.cpp', 'source/typecheck/using.cpp', @@ -297,17 +291,13 @@ source_files = files([ 'source/codegen/arithmetic.cpp', 'source/codegen/directives.cpp', 'source/codegen/destructure.cpp', - 'source/codegen/refcounting.cpp', 'source/codegen/controlflow.cpp', 'source/codegen/constructor.cpp', 'source/codegen/autocasting.cpp', 'source/codegen/codegenstate.cpp', - 'source/codegen/glue/any.cpp', 'source/codegen/glue/misc.cpp', 'source/codegen/glue/arrays.cpp', - 'source/codegen/glue/strings.cpp', - 'source/codegen/glue/saa_common.cpp', 'source/fir/interp/wrappers.cpp', 'source/fir/interp/compiler.cpp', @@ -323,7 +313,6 @@ source_files = files([ 'source/fir/Value.cpp', 'source/fir/Name.cpp', - 'source/fir/Types/DynamicArrayType.cpp', 'source/fir/Types/ArraySliceType.cpp', 'source/fir/Types/PrimitiveType.cpp', 'source/fir/Types/FunctionType.cpp', diff --git a/notes.md b/notes.md index 645d5dcf..faecb8e6 100644 --- a/notes.md +++ b/notes.md @@ -8,18 +8,7 @@ 3. types don't appear before functions for some reason, for typechecking. (ie. order becomes important) -4. enum values are not working correctly (seems to be right-shifted by 8?) - (the values are not assigned) - -5. defer appears to be broken: -``` -var i = 0 -while true { - defer i += 1 - - // doesn't change -} -``` +4. enums need to be fixed, for real. 6. "unsynchronised use of global init function!!!" -- need to figure out a way to serialise access to the global init function diff --git a/programs/fic/main.flx b/programs/fic/main.flx deleted file mode 100644 index b808a243..00000000 --- a/programs/fic/main.flx +++ /dev/null @@ -1,9 +0,0 @@ -// main.flx -// Copyright (c) 2017, zhiayang -// Licensed under the Apache License Version 2.0. - - -// this is supposed to be an irc client, in case i forget. -@entry fn main() -{ -} diff --git a/programs/fic/run.bat b/programs/fic/run.bat deleted file mode 100644 index e16d3a1c..00000000 --- a/programs/fic/run.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off - -robocopy libs build\sysroot\usr\local\lib\flaxlibs /e /nfl /ndl /njh /njs /nc /ns /np -build\meson-rel\flaxc.exe -sysroot build\sysroot -run programs\fic\main.flx \ No newline at end of file diff --git a/source/backend/llvm/translator.cpp b/source/backend/llvm/translator.cpp index 640b8067..9e34da48 100644 --- a/source/backend/llvm/translator.cpp +++ b/source/backend/llvm/translator.cpp @@ -40,15 +40,6 @@ #define SLICE_DATA_INDEX 0 #define SLICE_LENGTH_INDEX 1 -#define SAA_DATA_INDEX 0 -#define SAA_LENGTH_INDEX 1 -#define SAA_CAPACITY_INDEX 2 -#define SAA_REFCOUNTPTR_INDEX 3 - -#define ANY_TYPEID_INDEX 0 -#define ANY_REFCOUNTPTR_INDEX 1 -#define ANY_DATA_ARRAY_INDEX 2 - namespace backend { static util::hash_map createdTypes; @@ -129,27 +120,6 @@ namespace backend createdTypes[st->getTypeName()]->setBody(lmems, st->isPackedStruct()); return createdTypes[st->getTypeName()]; } - else if(type->isClassType()) - { - fir::ClassType* ct = type->toClassType(); - - if(createdTypes.find(ct->getTypeName()) != createdTypes.end()) - return createdTypes[ct->getTypeName()]; - - // to allow recursion, declare the type first. - createdTypes[ct->getTypeName()] = llvm::StructType::create(gc, ct->getTypeName().mangled()); - - std::vector lmems = zfu::map(ct->getAllElementsIncludingBase(), [&mod](auto t) -> auto { - return typeToLlvm(t, mod); - }); - - // insert the vtable at the front. - if(ct->getVirtualMethodCount() > 0) - lmems.insert(lmems.begin(), llvm::Type::getInt8PtrTy(gc)); - - createdTypes[ct->getTypeName()]->setBody(lmems); - return createdTypes[ct->getTypeName()]; - } else if(type->isTupleType()) { fir::TupleType* tt = type->toTupleType(); @@ -192,39 +162,6 @@ namespace backend { return llvm::Type::getVoidTy(gc); } - else if(type->isDynamicArrayType()) - { - fir::DynamicArrayType* llat = type->toDynamicArrayType(); - std::vector mems(4); - - mems[SAA_DATA_INDEX] = typeToLlvm(llat->getElementType()->getPointerTo(), mod); - mems[SAA_LENGTH_INDEX] = getNativeWordTy(); - mems[SAA_CAPACITY_INDEX] = getNativeWordTy(); - mems[SAA_REFCOUNTPTR_INDEX] = getNativeWordTy()->getPointerTo(); - - return llvm::StructType::get(gc, mems, false); - } - else if(type->isStringType()) - { - llvm::Type* i8ptrtype = llvm::Type::getInt8PtrTy(gc); - - auto id = fir::Name::obfuscate("string", fir::NameKind::Type); - if(createdTypes.find(id) != createdTypes.end()) - return createdTypes[id]; - - - std::vector mems(4); - - mems[SAA_DATA_INDEX] = i8ptrtype; - mems[SAA_LENGTH_INDEX] = getNativeWordTy(); - mems[SAA_CAPACITY_INDEX] = getNativeWordTy(); - mems[SAA_REFCOUNTPTR_INDEX] = getNativeWordTy()->getPointerTo(); - - auto str = llvm::StructType::create(gc, id.mangled()); - str->setBody(mems); - - return createdTypes[id] = str; - } else if(type->isArraySliceType()) { fir::ArraySliceType* slct = type->toArraySliceType(); @@ -258,21 +195,6 @@ namespace backend return llvm::StructType::get(gc, mems, false); } - else if(type->isAnyType()) - { - llvm::Type* arrtype = llvm::ArrayType::get(llvm::Type::getInt8Ty(gc), BUILTIN_ANY_DATA_BYTECOUNT); - - auto id = fir::Name::obfuscate("any", fir::NameKind::Type); - if(createdTypes.find(id) != createdTypes.end()) - return createdTypes[id]; - - auto str = llvm::StructType::create(gc, id.mangled()); - - // typeid (+ highest-bit-mask), refcount, data. - str->setBody({ getNativeWordTy(), getNativeWordTy()->getPointerTo(), arrtype }); - - return createdTypes[id] = str; - } else if(type->isUnionType()) { auto ut = type->toUnionType(); @@ -403,10 +325,6 @@ namespace backend llvm::Type* it = typeToLlvm(fc->getType(), mod); return cachedConstants[fc] = llvm::ConstantFP::get(it, cf->getValue()); } - else if(dcast(fir::ConstantNumber, fc)) - { - error("cannot"); - } else if(auto cc = dcast(fir::ConstantBool, fc)) { llvm::Type* ct = typeToLlvm(fc->getType(), mod); @@ -457,18 +375,12 @@ namespace backend return cachedConstants[fc] = llvm::ConstantStruct::get(llvm::cast(ty), constToLlvm(cec->getIndex(), valueMap, mod), constToLlvm(cec->getValue(), valueMap, mod)); } - else if(dcast(fir::ConstantCharSlice, fc) || dcast(fir::ConstantDynamicString, fc)) + else if(dcast(fir::ConstantCharSlice, fc)) { - bool wasDynStr = false; - std::string str; if(auto ccs = dcast(fir::ConstantCharSlice, fc)) str = ccs->getValue(); - else if(auto cds = dcast(fir::ConstantDynamicString, fc)) - wasDynStr = true, str = cds->getValue(); - - llvm::Constant* cstr = llvm::ConstantDataArray::getString(LLVMBackend::getLLVMContext(), str, true); llvm::GlobalVariable* gv = new llvm::GlobalVariable(*mod, cstr->getType(), true, llvm::GlobalValue::LinkageTypes::InternalLinkage, cstr, "_FV_STR_" + std::to_string(fc->id)); @@ -484,14 +396,6 @@ namespace backend fir::Type* ty = fir::Type::getCharSlice(false); std::vector mems = { gepd, len }; - if(wasDynStr) - { - ty = fir::Type::getString(); - - // add -1 for the capacity and 0 for the refcountptr. - mems.push_back(llvm::ConstantInt::get(getNativeWordTy(), static_cast(-1))); - mems.push_back(zconst); - } auto ret = llvm::ConstantStruct::get(llvm::cast(typeToLlvm(ty, mod)), mems); @@ -505,46 +409,6 @@ namespace backend auto ret = llvm::ConstantStruct::get(llvm::cast(typeToLlvm(cas->getType(), mod)), mems); return cachedConstants[fc] = ret; } - else if(auto cda = dcast(fir::ConstantDynamicArray, fc)) - { - if(cda->getArray()) - { - llvm::Constant* constArray = constToLlvm(cda->getArray(), valueMap, mod); - iceAssert(constArray); - - // don't make it immutable. this probably puts the global variable in the .data segment, instead of the - // .rodata/.rdata segment. - - // this allows us to modify it, eg. - // var foo = [ 1, 2, 3 ] - // foo[0] = 4 - - // of course, since capacity == -1, the moment we try to like append or something, - // we get back new heap memory - - llvm::GlobalVariable* tmpglob = new llvm::GlobalVariable(*mod, constArray->getType(), false, - llvm::GlobalValue::LinkageTypes::InternalLinkage, constArray, "_FV_ARR_" + std::to_string(cda->id)); - - auto zconst = llvm::ConstantInt::get(getNativeWordTy(), 0); - std::vector indices = { zconst, zconst }; - llvm::Constant* gepd = llvm::ConstantExpr::getGetElementPtr(tmpglob->getType()->getPointerElementType(), tmpglob, indices); - - auto flen = fir::ConstantInt::getNative(cda->getArray()->getType()->toArrayType()->getArraySize()); - auto fcap = fir::ConstantInt::getNative(-1); - std::vector mems = { gepd, constToLlvm(flen, valueMap, mod), constToLlvm(fcap, valueMap, mod), zconst }; - - auto ret = llvm::ConstantStruct::get(llvm::cast(typeToLlvm(cda->getType(), mod)), mems); - return cachedConstants[fc] = ret; - } - else - { - std::vector mems = { constToLlvm(cda->getData(), valueMap, mod), constToLlvm(cda->getLength(), valueMap, mod), - constToLlvm(cda->getCapacity(), valueMap, mod), llvm::ConstantInt::get(getNativeWordTy(), 0) }; - - auto ret = llvm::ConstantStruct::get(llvm::cast(typeToLlvm(cda->getType(), mod)), mems); - return cachedConstants[fc] = ret; - } - } else if(auto fn = dcast(fir::Function, fc)) { return translateFunctionDecl(fn, valueMap, mod); @@ -905,7 +769,7 @@ namespace backend #define DO_DUMP 0 #if DO_DUMP - #define DUMP_INSTR(fmt, ...) (fprintf(stderr, fmt, ##__VA_ARGS__)) + #define DUMP_INSTR(fmt, ...) (fprintf(stderr, fmt, ##__VA_ARGS__)) #else #define DUMP_INSTR(...) #endif @@ -915,9 +779,6 @@ namespace backend { fir::Function* ffn = fp.second; - // if(isGenericInAnyWay(ffn->getType())) - // continue; - llvm::Function* func = module->getFunction(fp.second->getName().mangled()); iceAssert(func); @@ -1391,12 +1252,12 @@ namespace backend bool sgn = inst->operands[0]->getType()->isSignedIntType() || inst->operands[1]->getType()->isSignedIntType(); llvm::Value* r1 = 0; - if(sgn) r1 = builder.CreateICmpSGE(a, b); - else r1 = builder.CreateICmpUGE(a, b); + if(sgn) r1 = builder.CreateICmpSGE(a, b); + else r1 = builder.CreateICmpUGE(a, b); llvm::Value* r2 = 0; - if(sgn) r2 = builder.CreateICmpSLE(a, b); - else r2 = builder.CreateICmpULE(a, b); + if(sgn) r2 = builder.CreateICmpSLE(a, b); + else r2 = builder.CreateICmpULE(a, b); r1 = builder.CreateIntCast(r1, getNativeWordTy(), false); r2 = builder.CreateIntCast(r2, getNativeWordTy(), false); @@ -1612,37 +1473,6 @@ namespace backend break; } - case fir::OpKind::Value_CallVirtualMethod: - { - // args are: 0. classtype, 1. index, 2. functiontype, 3...N args - auto clsty = inst->operands[0]->getType()->toClassType(); - iceAssert(clsty); - iceAssert(clsty->getVirtualMethodCount() > 0); - - std::vector args; - for(size_t i = 3; i < inst->operands.size(); i++) - args.push_back(decay(inst->operands[i], getValue(inst->operands[i]))); - - llvm::Value* vtable = builder.CreateLoad(builder.CreateStructGEP(typeToLlvm(clsty, module), args[0], 0)); - - vtable = builder.CreateBitOrPointerCast(vtable, - llvm::ArrayType::get(llvm::FunctionType::get(llvm::Type::getVoidTy(gc), false)->getPointerTo(), - clsty->getVirtualMethodCount())->getPointerTo()); - - auto fptr = builder.CreateConstInBoundsGEP2_32(vtable->getType()->getPointerElementType(), vtable, - 0, static_cast(dcast(fir::ConstantInt, inst->operands[1])->getUnsignedValue())); - - auto ffty = inst->operands[2]->getType()->toFunctionType(); - - fptr = builder.CreateBitOrPointerCast(builder.CreateLoad(fptr), typeToLlvm(ffty, module)); - - llvm::FunctionType* ft = llvm::cast(typeToLlvm(ffty, module)->getPointerElementType()); - iceAssert(ft); - llvm::Value* ret = builder.CreateCall(ft, fptr, args); - - addValueToMap(ret, inst->realOutput); - break; - } case fir::OpKind::Value_Return: { @@ -1817,7 +1647,7 @@ namespace backend llvm::Value* a = getOperand(inst, 0); llvm::Value* b = getOperand(inst, 1); - iceAssert(!inst->operands[0]->getType()->isClassType() && !inst->operands[0]->getType()->isStructType()); + iceAssert(!inst->operands[0]->getType()->isStructType()); llvm::Value* ret = builder.CreateGEP(a, b); addValueToMap(ret, inst->realOutput); @@ -1830,7 +1660,7 @@ namespace backend iceAssert(inst->operands.size() == 3); llvm::Value* a = getOperand(inst, 0); - iceAssert(!inst->operands[0]->getType()->isClassType() && !inst->operands[0]->getType()->isStructType()); + iceAssert(!inst->operands[0]->getType()->isStructType()); std::vector indices = { getOperand(inst, 1), getOperand(inst, 2) }; llvm::Value* ret = builder.CreateGEP(a, indices); @@ -1939,92 +1769,6 @@ namespace backend - - - - - - - - - - - - - - - case fir::OpKind::SAA_GetData: - case fir::OpKind::SAA_GetLength: - case fir::OpKind::SAA_GetCapacity: - case fir::OpKind::SAA_GetRefCountPtr: - { - iceAssert(inst->operands.size() == 1); - - llvm::Value* a = getOperand(inst, 0); - iceAssert(a->getType()->isStructTy()); - - int ind = 0; - if(inst->opKind == fir::OpKind::SAA_GetData) - ind = SAA_DATA_INDEX; - - else if(inst->opKind == fir::OpKind::SAA_GetLength) - ind = SAA_LENGTH_INDEX; - - else if(inst->opKind == fir::OpKind::SAA_GetCapacity) - ind = SAA_CAPACITY_INDEX; - - else if(inst->opKind == fir::OpKind::SAA_GetRefCountPtr) - ind = SAA_REFCOUNTPTR_INDEX; - - else - iceAssert(0 && "invalid"); - - llvm::Value* ret = builder.CreateExtractValue(a, ind); - addValueToMap(ret, inst->realOutput); - break; - } - - case fir::OpKind::SAA_SetData: - case fir::OpKind::SAA_SetLength: - case fir::OpKind::SAA_SetCapacity: - case fir::OpKind::SAA_SetRefCountPtr: - { - iceAssert(inst->operands.size() == 2); - - llvm::Value* a = getOperand(inst, 0); - llvm::Value* b = getOperand(inst, 1); - - iceAssert(a->getType()->isStructTy()); - - int ind = 0; - if(inst->opKind == fir::OpKind::SAA_SetData) - ind = SAA_DATA_INDEX; - - else if(inst->opKind == fir::OpKind::SAA_SetLength) - ind = SAA_LENGTH_INDEX; - - else if(inst->opKind == fir::OpKind::SAA_SetCapacity) - ind = SAA_CAPACITY_INDEX; - - else if(inst->opKind == fir::OpKind::SAA_SetRefCountPtr) - ind = SAA_REFCOUNTPTR_INDEX; - - else - iceAssert(0 && "invalid"); - - llvm::Value* ret = builder.CreateInsertValue(a, b, ind); - addValueToMap(ret, inst->realOutput); - break; - } - - - - - - - - - case fir::OpKind::ArraySlice_GetData: case fir::OpKind::ArraySlice_GetLength: { @@ -2073,61 +1817,6 @@ namespace backend - case fir::OpKind::Any_GetData: - case fir::OpKind::Any_GetTypeID: - case fir::OpKind::Any_GetRefCountPtr: - { - iceAssert(inst->operands.size() == 1); - - llvm::Value* a = getOperand(inst, 0); - iceAssert(a->getType()->isStructTy()); - - int ind = 0; - if(inst->opKind == fir::OpKind::Any_GetTypeID) - ind = ANY_TYPEID_INDEX; - - else if(inst->opKind == fir::OpKind::Any_GetRefCountPtr) - ind = ANY_REFCOUNTPTR_INDEX; - - else if(inst->opKind == fir::OpKind::Any_GetData) - ind = ANY_DATA_ARRAY_INDEX; - - else - iceAssert(0 && "invalid"); - - llvm::Value* ret = builder.CreateExtractValue(a, ind); - addValueToMap(ret, inst->realOutput); - break; - } - - case fir::OpKind::Any_SetData: - case fir::OpKind::Any_SetTypeID: - case fir::OpKind::Any_SetRefCountPtr: - { - iceAssert(inst->operands.size() == 2); - - llvm::Value* a = getOperand(inst, 0); - llvm::Value* b = getOperand(inst, 1); - - iceAssert(a->getType()->isStructTy()); - - int ind = 0; - if(inst->opKind == fir::OpKind::Any_SetTypeID) - ind = ANY_TYPEID_INDEX; - - else if(inst->opKind == fir::OpKind::Any_SetRefCountPtr) - ind = ANY_REFCOUNTPTR_INDEX; - - else if(inst->opKind == fir::OpKind::Any_SetData) - ind = ANY_DATA_ARRAY_INDEX; - - else - iceAssert(0 && "invalid"); - - llvm::Value* ret = builder.CreateInsertValue(a, b, ind); - addValueToMap(ret, inst->realOutput); - break; - } @@ -2205,7 +1894,8 @@ namespace backend llvm::Value* b = getOperand(inst, 1); iceAssert(a->getType()->isStructTy()); - if(pos == 0) iceAssert(b->getType()->isIntegerTy()); + if(pos == 0) + iceAssert(b->getType()->isIntegerTy()); llvm::Value* ret = builder.CreateInsertValue(a, b, { pos }); addValueToMap(ret, inst->realOutput); diff --git a/source/codegen/alloc.cpp b/source/codegen/alloc.cpp index c56be3a6..1c908732 100644 --- a/source/codegen/alloc.cpp +++ b/source/codegen/alloc.cpp @@ -7,189 +7,13 @@ #include "platform.h" #include "gluecode.h" -static fir::Function* getCheckNegativeLengthFunction(cgn::CodegenState* cs) -{ - auto fname = fir::Name::obfuscate("alloc_checkneg"); - fir::Function* checkf = cs->module->getFunction(fname); - - if(!checkf) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ fir::Type::getNativeWord(), fir::Type::getCharSlice(false) }, fir::Type::getVoid()), - fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - fir::Value* s1 = func->getArguments()[0]; - fir::Value* s2 = func->getArguments()[1]; - - fir::IRBlock* failb = cs->irb.addNewBlockInFunction("fail", func); - fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); - - // make the thing - auto isNeg = cs->irb.ICmpLT(s1, fir::ConstantInt::getNative(0)); - cs->irb.CondBranch(isNeg, failb, merge); - - - cs->irb.setCurrentBlock(failb); - { - cgn::glue::printRuntimeError(cs, s2, "tried to allocate a negative ('%ld') amount of memory\n", { s1 }); - } - - cs->irb.setCurrentBlock(merge); - cs->irb.ReturnVoid(); - - cs->irb.setCurrentBlock(restore); - checkf = func; - } - - iceAssert(checkf); - return checkf; -} - - -static fir::Value* performAllocation(cgn::CodegenState* cs, sst::AllocOp* alloc, fir::Type* type, std::vector counts, bool isRaw) -{ - auto callSetFunction = [cs](fir::Type* type, sst::AllocOp* alloc, fir::Value* ptr, fir::Value* count) -> void { - - auto callUserCode = [cs, alloc](fir::Value* elmp, fir::Value* idxp) { - iceAssert(alloc->initBlockIdx); - iceAssert(alloc->initBlockVar); - - // ok, then. create the variables: - cs->addVariableUsingStorage(alloc->initBlockIdx, idxp); - cs->addVariableUsingStorage(alloc->initBlockVar, elmp); - - alloc->initBlock->codegen(cs); - }; - - - - - auto arrp = ptr; - auto ctrp = cs->irb.CreateLValue(fir::Type::getNativeWord()); - - auto actuallyStore = [cs, type, alloc](fir::Value* ptr) -> void { - - if(type->isClassType()) - { - auto constr = dcast(sst::FunctionDefn, alloc->constructor); - iceAssert(constr); - - //! here, the arguments are called once per element. - auto value = cs->constructClassWithArguments(type->toClassType(), constr, alloc->arguments); - cs->autoAssignRefCountedValue(cs->irb.Dereference(ptr), value, true); - } - else if(type->isStructType()) - { - auto value = cs->getConstructedStructValue(type->toStructType(), alloc->arguments); - cs->autoAssignRefCountedValue(cs->irb.Dereference(ptr), value, true); - } - else - { - auto value = cs->getDefaultValue(type); - cs->autoAssignRefCountedValue(cs->irb.Dereference(ptr), value, true); - } - }; - - - if(alloc->counts.empty()) - { - actuallyStore(arrp); - } - else - { - cs->createWhileLoop([cs, ctrp, count](auto pass, auto fail) { - auto cond = cs->irb.ICmpLT(ctrp, count); - cs->irb.CondBranch(cond, pass, fail); - }, - [cs, callUserCode, actuallyStore, alloc, ctrp, arrp]() { - - auto ptr = cs->irb.GetPointer(arrp, ctrp); - - actuallyStore(ptr); - - if(alloc->initBlock) - callUserCode(cs->irb.Dereference(ptr), ctrp); - - cs->irb.Store(cs->irb.Add(ctrp, fir::ConstantInt::getNative(1)), ctrp); - }); - } - }; - - - - if(counts.empty() || isRaw) - { - fir::Value* cnt = (counts.empty() ? fir::ConstantInt::getNative(1) - : cs->oneWayAutocast(counts[0]->codegen(cs, fir::Type::getNativeWord()).value, fir::Type::getNativeWord())); - - //* if we don't have a count, then we just return a T* -- no arrays, nothing. - - auto sz = cs->irb.Multiply(cs->irb.Sizeof(type), cnt); - auto mem = cs->irb.Call(cgn::glue::misc::getMallocWrapperFunction(cs), sz, fir::ConstantCharSlice::get(alloc->loc.shortString())); - mem = cs->irb.PointerTypeCast(mem, type->getMutablePointerTo()); - - callSetFunction(type, alloc, mem, cnt); - - // check if we were supposed to be immutable - if(!alloc->isMutable) - mem = cs->irb.PointerTypeCast(mem, mem->getType()->getImmutablePointerVersion()); - - return mem; - } - else - { - auto ecount = counts[0]; - - auto count = cs->oneWayAutocast(ecount->codegen(cs, fir::Type::getNativeWord()).value, fir::Type::getNativeWord()); - if(!count || !count->getType()->isIntegerType()) - error(ecount, "expected integer type for length, found '%s' instead", (count ? count->getType()->str() : "null")); - - // make sure the length isn't negative - auto checkf = getCheckNegativeLengthFunction(cs); - iceAssert(checkf); - cs->irb.Call(checkf, count, fir::ConstantCharSlice::get(ecount->loc.toString())); - - auto arr = cs->irb.CreateValue(fir::DynamicArrayType::get(type)); - auto expandfn = cgn::glue::saa_common::generateReserveAtLeastFunction(cs, arr->getType()); - iceAssert(expandfn); - - arr = cs->irb.Call(expandfn, arr, count); - arr = cs->irb.SetSAALength(arr, count); - - callSetFunction(type, alloc, cs->irb.GetSAAData(arr), count); - cs->addRefCountedValue(arr); - - return arr; - } -} - - - - - - - - - - - CGResult sst::AllocOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); defer(cs->popLoc()); - if(this->counts.size() > 1) - error(this, "multi-dimensional arrays are not supported yet."); - - return CGResult(performAllocation(cs, this, this->elmType, this->counts, this->attrs.has(attr::RAW))); + error("no"); } @@ -199,19 +23,7 @@ CGResult sst::DeallocOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) cs->pushLoc(this); defer(cs->popLoc()); - - auto freef = cs->getOrDeclareLibCFunction(FREE_MEMORY_FUNC); - iceAssert(freef); - - auto value = this->expr->codegen(cs).value; - auto ty = value->getType(); - - iceAssert(ty->isPointerType()); - - fir::Value* ptr = cs->irb.PointerTypeCast(value, fir::Type::getMutInt8Ptr()); - - cs->irb.Call(freef, ptr); - return CGResult(0); + error("no"); } diff --git a/source/codegen/arithmetic.cpp b/source/codegen/arithmetic.cpp index 83e79c2a..93c3efb8 100644 --- a/source/codegen/arithmetic.cpp +++ b/source/codegen/arithmetic.cpp @@ -19,14 +19,7 @@ namespace sst auto value = this->left->codegen(cs).value; auto vt = value->getType(); - if(vt->isConstantNumberType() && (target->isFloatingPointType() || target->isIntegerType())) - { - auto cn = dcast(fir::ConstantNumber, value); - if(!cn) error(this->left, "what"); - - return CGResult(cs->unwrapConstantNumber(cn, target)); - } - else if(vt->isEnumType()) + if(vt->isEnumType()) { auto res = cs->irb.AppropriateCast(cs->irb.GetEnumCaseValue(value), target); @@ -37,13 +30,6 @@ namespace sst return CGResult(res); } - else if(vt->isAnyType()) - { - auto fn = cgn::glue::any::generateGetValueFromAnyFunction(cs, target); - iceAssert(fn); - - return CGResult(cs->irb.Call(fn, value)); - } else if(vt->isUnionType() && target->isUnionVariantType()) { if(auto parent = target->toUnionVariantType()->getParentUnion(); parent != vt) @@ -96,15 +82,7 @@ namespace sst auto value = this->left->codegen(cs).value; auto target = this->right->codegen(cs).value->getType(); - if(value->getType()->isAnyType()) - { - // get the type out. - auto res = cs->irb.BitwiseAND(cs->irb.GetAnyTypeID(value), - cs->irb.BitwiseNOT(fir::ConstantInt::getUNative(BUILTIN_ANY_FLAG_MASK))); - - return CGResult(res = cs->irb.ICmpEQ(res, fir::ConstantInt::getUNative(target->getID()))); - } - else if(value->getType()->isUnionType() && target->isUnionVariantType()) + if(value->getType()->isUnionType() && target->isUnionVariantType()) { // it's slightly more complicated. auto vid1 = cs->irb.GetUnionVariantID(value); @@ -325,47 +303,6 @@ namespace cgn error("no"); } - else if((lt->isPrimitiveType() && rt->isConstantNumberType()) || (lt->isConstantNumberType() && rt->isPrimitiveType())) - { - if(lr->getType()->isFloatingPointType()) - { - if(op == Operator::CompareEQ) return CGResult(this->irb.FCmpEQ_ORD(lr, rr)); - if(op == Operator::CompareNEQ) return CGResult(this->irb.FCmpNEQ_ORD(lr, rr)); - if(op == Operator::CompareLT) return CGResult(this->irb.FCmpLT_ORD(lr, rr)); - if(op == Operator::CompareLEQ) return CGResult(this->irb.FCmpLEQ_ORD(lr, rr)); - if(op == Operator::CompareGT) return CGResult(this->irb.FCmpGT_ORD(lr, rr)); - if(op == Operator::CompareGEQ) return CGResult(this->irb.FCmpGEQ_ORD(lr, rr)); - - error("no"); - } - else - { - if(op == Operator::CompareEQ) return CGResult(this->irb.ICmpEQ(lr, rr)); - if(op == Operator::CompareNEQ) return CGResult(this->irb.ICmpNEQ(lr, rr)); - if(op == Operator::CompareLT) return CGResult(this->irb.ICmpLT(lr, rr)); - if(op == Operator::CompareLEQ) return CGResult(this->irb.ICmpLEQ(lr, rr)); - if(op == Operator::CompareGT) return CGResult(this->irb.ICmpGT(lr, rr)); - if(op == Operator::CompareGEQ) return CGResult(this->irb.ICmpGEQ(lr, rr)); - - error("no"); - } - } - else if(lt->isStringType() && rt->isStringType()) - { - auto cmpfn = cgn::glue::string::getCompareFunction(this); - fir::Value* res = this->irb.Call(cmpfn, lv, rv); - - fir::Value* zero = fir::ConstantInt::getNative(0); - - if(op == Operator::CompareEQ) return CGResult(this->irb.ICmpEQ(res, zero)); - if(op == Operator::CompareNEQ) return CGResult(this->irb.ICmpNEQ(res, zero)); - if(op == Operator::CompareLT) return CGResult(this->irb.ICmpLT(res, zero)); - if(op == Operator::CompareLEQ) return CGResult(this->irb.ICmpLEQ(res, zero)); - if(op == Operator::CompareGT) return CGResult(this->irb.ICmpGT(res, zero)); - if(op == Operator::CompareGEQ) return CGResult(this->irb.ICmpGEQ(res, zero)); - - error("no"); - } else if(lt->isEnumType() && lt == rt) { auto li = this->irb.GetEnumCaseIndex(lv); @@ -380,7 +317,7 @@ namespace cgn error("no"); } - else if((lt->isDynamicArrayType() || lt->isArraySliceType()) && lt == rt) + else if(lt->isArraySliceType() && lt == rt) { //! use opf when we have operator overloads auto cmpfn = cgn::glue::array::getCompareFunction(this, lt, 0); @@ -404,14 +341,13 @@ namespace cgn } else { - if((lt->isPrimitiveType() || lt->isConstantNumberType()) && (rt->isPrimitiveType() || rt->isConstantNumberType())) + if(lt->isPrimitiveType() && rt->isPrimitiveType()) { auto [ lr, rr ] = this->autoCastValueTypes(l, r); return CGResult(this->irb.BinaryOp(op, lr, rr)); } - else if((lt->isPointerType() && (rt->isIntegerType() || rt->isConstantNumberType())) - || ((lt->isIntegerType() || lt->isConstantNumberType()) && rt->isPointerType())) + else if((lt->isPointerType() && rt->isIntegerType()) || (lt->isIntegerType() && rt->isPointerType())) { auto ofsv = (lt->isPointerType() ? rv : lv); auto ofs = this->oneWayAutocast(ofsv, fir::Type::getNativeWord()); @@ -423,98 +359,6 @@ namespace cgn return CGResult(ptr); } - else if(lt->isStringType() && rt->isStringType()) - { - if(op != Operator::Plus) - unsupportedError(lhs.first, lt, rhs.first, rt); - - #if 0 - // ok. - // if we're both string literals, then fuck it, do it compile-time - if(dcast(fir::ConstantCharSlice, lv) && dcast(fir::ConstantCharSlice, rv)) - { - std::string cls = dcast(fir::ConstantCharSlice, lv)->getValue(); - std::string crs = dcast(fir::ConstantCharSlice, rv)->getValue(); - - info(loc, "const strings"); - return CGResult(fir::ConstantCharSlice::get(cls + crs)); - } - #endif - - - auto appfn = cgn::glue::string::getConstructFromTwoFunction(this); - auto res = this->irb.Call(appfn, this->irb.CreateSliceFromSAA(lv, false), this->irb.CreateSliceFromSAA(rv, false)); - this->addRefCountedValue(res); - - return CGResult(res); - } - else if((lt->isStringType() && rt->isCharSliceType()) || (lt->isCharSliceType() && rt->isStringType())) - { - if(op != Operator::Plus) - unsupportedError(lhs.first, lt, rhs.first, rt); - - // make life easier - if(lt->isCharSliceType()) - { - std::swap(lt, rt); - std::swap(lv, rv); - } - - auto appfn = cgn::glue::string::getConstructFromTwoFunction(this); - auto res = this->irb.Call(appfn, this->irb.CreateSliceFromSAA(lv, false), rv); - this->addRefCountedValue(res); - - return CGResult(res); - } - else if((lt->isStringType() && rt->isCharType()) || (lt->isCharType() && rt->isStringType())) - { - if(op != Operator::Plus) - unsupportedError(lhs.first, lt, rhs.first, rt); - - // make life easier - if(lt->isCharType()) - { - std::swap(lt, rt); - std::swap(lv, rv); - } - - - #if 0 - if(dcast(fir::ConstantCharSlice, lv) && dcast(fir::ConstantChar, rv)) - { - std::string cls = dcast(fir::ConstantCharSlice, lv)->getValue(); - char crs = dcast(fir::ConstantChar, rv)->getValue(); - - info(loc, "const strings"); - return CGResult(fir::ConstantCharSlice::get(cls + crs)); - } - #endif - - - auto appfn = cgn::glue::string::getConstructWithCharFunction(this); - auto res = this->irb.Call(appfn, this->irb.CreateSliceFromSAA(lv, true), rv); - this->addRefCountedValue(res); - - return CGResult(res); - } - else if(lt->isDynamicArrayType() && rt->isDynamicArrayType() && lt->getArrayElementType() == rt->getArrayElementType()) - { - // check what we're doing - if(op != Operator::Plus) - unsupportedError(lhs.first, lt, rhs.first, rt); - - // ok, do the append - auto maketwof = cgn::glue::array::getConstructFromTwoFunction(this, lt->toDynamicArrayType()); - - fir::Value* res = this->irb.Call(maketwof, this->irb.CreateSliceFromSAA(lv, false), - this->irb.CreateSliceFromSAA(rv, false)); - - this->addRefCountedValue(res); - - return CGResult(res); - - // error(loc, "i'm gonna stop you right here"); - } else { unsupportedError(lhs.first, lt, rhs.first, rt); diff --git a/source/codegen/assign.cpp b/source/codegen/assign.cpp index 56790c24..050add03 100644 --- a/source/codegen/assign.cpp +++ b/source/codegen/assign.cpp @@ -45,67 +45,6 @@ CGResult sst::AssignOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) // some things -- if we're doing +=, and the types are supported, then just call the actual // append function, instead of doing the + first then assigning it. - if(nonass == Operator::Plus) - { - if(lt->isDynamicArrayType() && lt == rt) - { - // right then. - if(!lr->islvalue()) - error(this, "cannot append to an r-value array"); - - auto appendf = cgn::glue::array::getAppendFunction(cs, lt->toDynamicArrayType()); - - //? are there any ramifications for these actions for ref-counted things? - auto res = cs->irb.Call(appendf, lr, cs->irb.CreateSliceFromSAA(rr, false)); - - cs->irb.Store(res, lr); - return CGResult(0); - } - else if(lt->isDynamicArrayType() && lt->getArrayElementType() == rt) - { - // right then. - if(!lr->islvalue()) - error(this, "cannot append to an r-value array"); - - auto appendf = cgn::glue::array::getElementAppendFunction(cs, lt->toDynamicArrayType()); - - //? are there any ramifications for these actions for ref-counted things? - auto res = cs->irb.Call(appendf, lr, rr); - - cs->irb.Store(res, lr); - return CGResult(0); - } - else if(lt->isStringType() && lt == rt) - { - // right then. - if(!lr->islvalue()) - error(this, "cannot append to an r-value array"); - - auto appendf = cgn::glue::string::getAppendFunction(cs); - - //? are there any ramifications for these actions for ref-counted things? - auto res = cs->irb.Call(appendf, lr, cs->irb.CreateSliceFromSAA(rr, true)); - - cs->irb.Store(res, lr); - return CGResult(0); - } - else if(lt->isStringType() && rt->isCharType()) - { - // right then. - if(!lr->islvalue()) - error(this, "cannot append to an r-value string"); - - auto appendf = cgn::glue::string::getCharAppendFunction(cs); - - //? are there any ramifications for these actions for ref-counted things? - auto res = cs->irb.Call(appendf, lr, rr); - - cs->irb.Store(res, lr); - return CGResult(0); - } - } - - // do the op first auto res = cs->performBinaryOperation(this->loc, { this->left->loc, lr }, { this->right->loc, rr }, nonass); @@ -122,7 +61,7 @@ CGResult sst::AssignOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) if(lt != rr->getType()) error(this, "what? left = %s, right = %s", lt, rr->getType()); - cs->autoAssignRefCountedValue(lr, rr, /* isInitial: */ false); + cs->performAssignment(lr, rr, /* isInitial: */ false); return CGResult(0); } @@ -169,7 +108,7 @@ CGResult sst::TupleAssignOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) val->getType(), lr.value->getType()); } - cs->autoAssignRefCountedValue(lr.value, rr, /* isInitial: */ false); + cs->performAssignment(lr.value, rr, /* isInitial: */ false); } return CGResult(0); diff --git a/source/codegen/autocasting.cpp b/source/codegen/autocasting.cpp index 56026977..1bc9c233 100644 --- a/source/codegen/autocasting.cpp +++ b/source/codegen/autocasting.cpp @@ -10,117 +10,6 @@ namespace cgn { - fir::ConstantValue* CodegenState::unwrapConstantNumber(fir::ConstantValue* cv) - { - iceAssert(cv->getType()->isConstantNumberType()); - auto cn = dcast(fir::ConstantNumber, cv); - iceAssert(cn); - - auto ty = cv->getType()->toConstantNumberType(); - iceAssert(ty); - - if(ty->isFloating()) - { - if(ty->getMinBits() <= fir::Type::getFloat64()->getBitWidth()) - return fir::ConstantFP::getFloat64(cn->getDouble()); - - else - error("float overflow"); - } - else - { - if(ty->getMinBits() < fir::Type::getNativeWord()->getBitWidth() - 1) - return fir::ConstantInt::getNative(cn->getInt64()); - - else if(!ty->isSigned() && ty->getMinBits() <= fir::Type::getNativeUWord()->getBitWidth()) - return fir::ConstantInt::getUNative(cn->getUint64()); - - else - error("int overflow"); - } - } - - - static fir::ConstantValue* _unwrapConstantNumber(CodegenState* cs, fir::ConstantNumber* num, fir::Type* target, bool isAutocast) - { - if(!(target->isIntegerType() || target->isFloatingPointType())) - error(cs->loc(), "unable to cast number literal to inferred type '%s'", target); - - auto ty = num->getType()->toConstantNumberType(); - - bool signConvert = false; - if(ty->isFloating() && target->isIntegerType()) - { - if(isAutocast) return 0; - warn(cs->loc(), "casting floating-point literal to integer type '%s' will cause a truncation", target); - } - else if(target->isIntegerType() && !target->isSignedIntType() && ty->isSigned()) - { - if(isAutocast) return 0; - warn(cs->loc(), "casting negative literal to an unsigned integer type '%s'", target); - signConvert = true; - } - - - if(target->toPrimitiveType()->getBitWidth() < ty->getMinBits()) - { - // TODO: actually do what we say. - warn(cs->loc(), "casting literal to type '%s' will cause an overflow; value will be truncated bitwise to fit", - target); - } - - if(signConvert) - { - // eg. ((size_t) -1) gives SIZET_MAX, basically. - // so what we do, is we get the max of the target type, - // then subtract (num - 1) - - if(target == fir::Type::getUint8()) - return fir::ConstantInt::get(target, num->getUint8()); - - else if(target == fir::Type::getUint16()) - return fir::ConstantInt::get(target, num->getUint16()); - - else if(target == fir::Type::getUint32()) - return fir::ConstantInt::get(target, num->getUint32()); - - else if(target == fir::Type::getUint64()) - return fir::ConstantInt::get(target, num->getUint64()); - - else - error("what %s", target); - } - - if(target == fir::Type::getFloat32()) return fir::ConstantFP::getFloat32(num->getFloat()); - else if(target == fir::Type::getFloat64()) return fir::ConstantFP::getFloat64(num->getDouble()); - else if(target == fir::Type::getInt8()) return fir::ConstantInt::get(target, num->getInt8()); - else if(target == fir::Type::getInt16()) return fir::ConstantInt::get(target, num->getInt16()); - else if(target == fir::Type::getInt32()) return fir::ConstantInt::get(target, num->getInt32()); - else if(target == fir::Type::getInt64()) return fir::ConstantInt::get(target, num->getInt64()); - else if(target == fir::Type::getUint8()) return fir::ConstantInt::get(target, num->getUint8()); - else if(target == fir::Type::getUint16()) return fir::ConstantInt::get(target, num->getUint16()); - else if(target == fir::Type::getUint32()) return fir::ConstantInt::get(target, num->getUint32()); - else if(target == fir::Type::getUint64()) return fir::ConstantInt::get(target, num->getUint64()); - - else if(target == fir::Type::getNativeWord()) return fir::ConstantInt::get(target, num->getInt64()); - else if(target == fir::Type::getNativeUWord()) return fir::ConstantInt::get(target, num->getUint64()); - else error("unsupported type '%s'", target); - } - - - - fir::ConstantValue* CodegenState::unwrapConstantNumber(fir::ConstantNumber* cv, fir::Type* target) - { - if(target) return _unwrapConstantNumber(this, cv, target, false); - else return this->unwrapConstantNumber(cv); - } - - - - - - - // TODO: maybe merge/refactor this and the two-way autocast into one function, // there's a bunch of duplication here fir::Value* CodegenState::oneWayAutocast(fir::Value* from, fir::Type* target) @@ -154,33 +43,6 @@ namespace cgn { result = this->irb.GetArraySliceData(from); } - else if(fromType->isStringType() && target == fir::Type::getInt8Ptr()) - { - result = this->irb.PointerTypeCast(this->irb.GetSAAData(from), fir::Type::getInt8Ptr()); - } - else if(fromType->isStringType() && target->isCharSliceType()) - { - auto ret = this->irb.CreateValue(target); - ret = this->irb.SetArraySliceData(ret, this->irb.GetSAAData(from)); - ret = this->irb.SetArraySliceLength(ret, this->irb.GetSAALength(from)); - - result = ret; - } - else if(fromType->isDynamicArrayType() && target->isArraySliceType() && target->getArrayElementType() == fromType->getArrayElementType()) - { - // ok, then - auto ret = this->irb.CreateValue(fir::ArraySliceType::get(fromType->getArrayElementType(), target->toArraySliceType()->isMutable())); - ret = this->irb.SetArraySliceData(ret, this->irb.GetSAAData(from)); - ret = this->irb.SetArraySliceLength(ret, this->irb.GetSAALength(from)); - - result = ret; - } - else if(fromType->isPointerType() && target->isPointerType() && fromType->getPointerElementType()->isClassType() - && fromType->getPointerElementType()->toClassType()->hasParent(target->getPointerElementType())) - { - auto ret = this->irb.PointerTypeCast(from, target); - result = ret; - } else if(fromType->isPointerType() && target->isPointerType() && fromType->getPointerElementType() == target->getPointerElementType() && fromType->isMutablePointer() && target->isImmutablePointer()) { @@ -223,14 +85,6 @@ namespace cgn if(!failed) result = tuple; } - else if(target->isAnyType()) - { - // great. - auto fn = glue::any::generateCreateAnyWithValueFunction(this, from->getType()); - iceAssert(fn); - - result = this->irb.Call(fn, from); - } if(!result) @@ -239,9 +93,6 @@ namespace cgn } else { - if(fir::isRefCountedType(result->getType())) - this->addRefCountedValue(result); - return result; } } @@ -252,16 +103,6 @@ namespace cgn auto rt = rhs->getType(); if(lt == rt) { - // if(lt->isConstantNumberType()) - // { - // // well. do the sensible default, i guess. - // iceAssert(rt->isConstantNumberType()); - - // auto cnt = fir::unifyConstantTypes(lt->toConstantNumberType(), rt->toConstantNumberType()); - // if(cnt->isFloating()) - // return { this->irb.AppropriateCast(lhs, cnt), this->irb.AppropriateCast(rhs, cnt) }; - // } - return { lhs, rhs }; } @@ -272,22 +113,7 @@ namespace cgn else if(lt->isPointerType() && rt->isNullType()) return std::make_pair(lhs, this->irb.PointerTypeCast(rhs, lt)); - - /* if(lt->isConstantNumberType() && !rt->isConstantNumberType()) - { - auto cn = dcast(fir::ConstantNumber, lhs); - iceAssert(cn); - - auto res = _unwrapConstantNumber(this, cn, rt, true); - if(!res) return { lhs, rhs }; - else return { CGResult(res), rhs }; - } - else if(!lt->isConstantNumberType() && rt->isConstantNumberType()) - { - auto [ l, r ] = this->autoCastValueTypes(rhs, lhs); - return { r, l }; - } - else */if(lt->isIntegerType() && rt->isIntegerType() && lt->isSignedIntType() == rt->isSignedIntType()) + if(lt->isIntegerType() && rt->isIntegerType() && lt->isSignedIntType() == rt->isSignedIntType()) { // ok, neither are constants // do the normal thing diff --git a/source/codegen/builtin.cpp b/source/codegen/builtin.cpp index d244d255..0699dce0 100644 --- a/source/codegen/builtin.cpp +++ b/source/codegen/builtin.cpp @@ -11,32 +11,6 @@ namespace names = strs::names; -static fir::Value* checkNullPointerOrReturnZero(cgn::CodegenState* cs, fir::Value* ptr) -{ - iceAssert(ptr->getType() == fir::Type::getNativeWordPtr()); - - auto isnull = cs->irb.ICmpEQ(ptr, fir::ConstantValue::getZeroValue(fir::Type::getNativeWordPtr())); - - auto prevb = cs->irb.getCurrentBlock(); - auto deref = cs->irb.addNewBlockAfter("deref", prevb); - auto merge = cs->irb.addNewBlockAfter("merge", deref); - - cs->irb.CondBranch(isnull, merge, deref); - - cs->irb.setCurrentBlock(deref); - auto rc = cs->irb.ReadPtr(ptr); - cs->irb.UnCondBranch(merge); - - cs->irb.setCurrentBlock(merge); - auto phi = cs->irb.CreatePHINode(fir::Type::getNativeWord()); - phi->addIncoming(fir::ConstantInt::getNative(0), prevb); - phi->addIncoming(rc, deref); - - return phi; -} - - - CGResult sst::BuiltinDotOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); @@ -47,109 +21,24 @@ CGResult sst::BuiltinDotOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) if(this->isFunctionCall) { - std::vector arguments = zfu::map(this->args, [cs](sst::Expr* e) -> fir::Value* { return e->codegen(cs).value; }); - if(this->name == names::saa::FN_CLONE) - { - iceAssert(arguments.empty()); - auto clonef = cgn::glue::saa_common::generateCloneFunction(cs, ty); - - auto ret = cs->irb.Call(clonef, cs->irb.CreateSliceFromSAA(res.value, false), fir::ConstantInt::getNative(0)); - - iceAssert(fir::isRefCountedType(ret->getType())); - cs->addRefCountedValue(ret); - - return CGResult(ret); - } - else if(this->name == names::array::FN_POP) - { - iceAssert(!ty->isStringType()); - - if(!res->islvalue()) - error(this->lhs, "cannot call 'pop()' on an rvalue"); - - else if(res->isConst()) - error(this->lhs, "cannot call 'pop()' (which mutates) on a constant value"); - - else if(ty->isArrayType()) - error(this->lhs, "cannot call 'pop()' on an array type ('%s')", ty); - - auto popf = cgn::glue::array::getPopElementFromBackFunction(cs, ty); - auto tupl = cs->irb.Call(popf, res.value, fir::ConstantCharSlice::get(this->loc.toString())); - - // tupl[0] is the new array - // tupl[1] is the last element - - auto newarr = cs->irb.ExtractValue(tupl, { 0 }); - auto retelm = cs->irb.ExtractValue(tupl, { 1 }); - - cs->irb.Store(newarr, res.value); - return CGResult(retelm); - } - else if(this->name == names::saa::FN_APPEND) - { - iceAssert(arguments.size() == 1); - - if(!res->islvalue()) - error(this->lhs, "cannot call 'append' on an rvalue"); - - auto arg = arguments[0]; - fir::Function* appendf = cgn::glue::saa_common::generateAppropriateAppendFunction(cs, ty, arg->getType()); - iceAssert(appendf); - - if(arg->getType()->isDynamicArrayType() && arg->getType() == ty) - arg = cs->irb.CreateSliceFromSAA(arg, true); - - else if(arg->getType()->isStringType() && arg->getType() == ty) - arg = cs->irb.CreateSliceFromSAA(arg, true); - - auto ret = cs->irb.Call(appendf, res.value, arg); - - cs->irb.Store(ret, res.value); - - return CGResult(res); - } } else { - if(ty->isStringType() || ty->isDynamicArrayType()) + if(ty->isArraySliceType()) { - if(this->name == names::saa::FIELD_POINTER) - return CGResult(cs->irb.GetSAAData(res.value)); - - else if(this->name == names::saa::FIELD_LENGTH) - return CGResult(cs->irb.GetSAALength(res.value)); - - else if(this->name == names::saa::FIELD_CAPACITY) - return CGResult(cs->irb.GetSAACapacity(res.value)); - - else if(this->name == names::saa::FIELD_REFCOUNT) - { - return CGResult(checkNullPointerOrReturnZero(cs, cs->irb.GetSAARefCountPointer(res.value))); - } - else if(ty->isStringType() && this->name == names::string::FIELD_COUNT) - { - auto fn = cgn::glue::string::getUnicodeLengthFunction(cs); - iceAssert(fn); - - auto ret = cs->irb.Call(fn, cs->irb.GetSAAData(res.value)); - return CGResult(ret); - } - } - else if(ty->isArraySliceType()) - { - if(this->name == names::saa::FIELD_LENGTH) + if(this->name == names::array::FIELD_LENGTH) return CGResult(cs->irb.GetArraySliceLength(res.value)); - else if(this->name == names::saa::FIELD_POINTER) + else if(this->name == names::array::FIELD_POINTER) return CGResult(cs->irb.GetArraySliceData(res.value)); } else if(ty->isArrayType()) { - if(this->name == names::saa::FIELD_LENGTH) + if(this->name == names::array::FIELD_LENGTH) { return CGResult(fir::ConstantInt::getNative(ty->toArrayType()->getArraySize())); } - else if(this->name == names::saa::FIELD_POINTER) + else if(this->name == names::array::FIELD_POINTER) { // TODO: LVALUE HOLE if(res.value->islvalue()) @@ -175,14 +64,6 @@ CGResult sst::BuiltinDotOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) return CGResult(cs->irb.GetRangeStep(res.value)); } - else if(ty->isAnyType()) - { - if(this->name == names::any::FIELD_TYPEID) - return CGResult(cs->irb.GetAnyTypeID(res.value)); - - else if(this->name == names::any::FIELD_REFCOUNT) - return CGResult(checkNullPointerOrReturnZero(cs, cs->irb.GetAnyRefCountPointer(res.value))); - } else if(ty->isEnumType()) { if(this->name == names::enumeration::FIELD_INDEX) diff --git a/source/codegen/call.cpp b/source/codegen/call.cpp index 9a157a0e..62da18c5 100644 --- a/source/codegen/call.cpp +++ b/source/codegen/call.cpp @@ -89,14 +89,6 @@ static std::vector _codegenAndArrangeFunctionCallArguments(cgn::Cod auto doCastIfNecessary = [cs](const Location& loc, fir::Value* val, fir::Type* infer) -> fir::Value* { - if(val->getType()->isConstantNumberType()) - { - auto cv = dcast(fir::ConstantValue, val); - iceAssert(cv); - - val = cs->unwrapConstantNumber(cv); - } - if(!infer) return val; @@ -136,21 +128,6 @@ static std::vector _codegenAndArrangeFunctionCallArguments(cgn::Cod //* copyRAIIValue will just return 'val' if it is not a class type, so we don't check it here! val = cs->copyRAIIValue(val); - - //* arguments are added to the refcounting list in the function, - //* so we need to "pre-increment" the refcount here, so it does not - //* get freed when the function returns. - if(fir::isRefCountedType(val->getType())) - cs->incrementRefCount(val); - - if(val->getType()->isConstantNumberType()) - { - auto cv = dcast(fir::ConstantValue, val); - iceAssert(cv); - - val = cs->unwrapConstantNumber(cv); - } - val = doCastIfNecessary(arg->loc, val, infer); values[k] = val; } @@ -182,19 +159,13 @@ static std::vector _codegenAndArrangeFunctionCallArguments(cgn::Cod } auto val = arg->codegen(cs, infer).value; - if(fir::isRefCountedType(val->getType())) - cs->incrementRefCount(val); - val = doCastIfNecessary(arg->loc, val, infer); if(ft->isCStyleVarArg()) { // auto-convert strings and char slices into char* when passing to va_args - if(val->getType()->isStringType()) - val = cs->irb.GetSAAData(val); - - else if(val->getType()->isCharSliceType()) + if(val->getType()->isCharSliceType()) val = cs->irb.GetArraySliceData(val); // also, see if we need to promote the type! @@ -274,14 +245,6 @@ CGResult sst::FunctionCall::_codegen(cgn::CodegenState* cs, fir::Type* infer) iceAssert(defn.value); vf = defn.value; } - else if(auto fd = dcast(FunctionDefn, this->target); fd && fd->isVirtual) - { - // ok then. - auto ret = cs->callVirtualMethod(this); - cs->addRAIIOrRCValueIfNecessary(ret); - - return CGResult(ret); - } else { vf = this->target->codegen(cs).value; @@ -360,7 +323,7 @@ static CGResult callBuiltinTypeConstructor(cgn::CodegenState* cs, fir::Type* typ { return CGResult(cs->getDefaultValue(type)); } - else if(!type->isStringType()) + else { iceAssert(args.size() == 1); auto ret = cs->oneWayAutocast(args[0]->codegen(cs, type).value, type); @@ -370,44 +333,6 @@ static CGResult callBuiltinTypeConstructor(cgn::CodegenState* cs, fir::Type* typ return CGResult(ret); } - else - { - auto cloneTheSlice = [cs](fir::Value* slc) -> CGResult { - - iceAssert(slc->getType()->isCharSliceType()); - - auto clonef = cgn::glue::string::getCloneFunction(cs); - iceAssert(clonef); - - auto ret = cs->irb.Call(clonef, slc, fir::ConstantInt::getNative(0)); - cs->addRefCountedValue(ret); - - return CGResult(ret); - }; - - if(args.size() == 1) - { - iceAssert(args[0]->type->isCharSliceType()); - return cloneTheSlice(args[0]->codegen(cs, fir::Type::getCharSlice(false)).value); - } - else - { - iceAssert(args.size() == 2); - iceAssert(args[0]->type == fir::Type::getInt8Ptr() || args[0]->type == fir::Type::getMutInt8Ptr()); - iceAssert(args[1]->type->isIntegerType()); - - auto ptr = args[0]->codegen(cs).value; - auto len = cs->oneWayAutocast(args[1]->codegen(cs, fir::Type::getNativeWord()).value, fir::Type::getNativeWord()); - - auto slc = cs->irb.CreateValue(fir::Type::getCharSlice(false)); - slc = cs->irb.SetArraySliceData(slc, (ptr->getType()->isMutablePointer() - ? cs->irb.PointerTypeCast(ptr, fir::Type::getInt8Ptr()) : ptr)); - - slc = cs->irb.SetArraySliceLength(slc, len); - - return cloneTheSlice(slc); - } - } } diff --git a/source/codegen/classes.cpp b/source/codegen/classes.cpp deleted file mode 100644 index 092662e5..00000000 --- a/source/codegen/classes.cpp +++ /dev/null @@ -1,208 +0,0 @@ -// classes.h -// Copyright (c) 2017, zhiayang -// Licensed under the Apache License Version 2.0. - -#include "errors.h" -#include "codegen.h" -#include "typecheck.h" -#include "memorypool.h" - -CGResult sst::ClassDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) -{ - cs->pushLoc(this); - defer(cs->popLoc()); - - iceAssert(this->type && this->type->isClassType()); - - std::vector meths; - std::vector inits; - - - auto clsty = this->type->toClassType(); - - //* this looks stupid, but in 'setbaseclass' we update the virtual methods of the current class. - //* since when we previously set the base class there were no virtual methods (we were still typechecking), - //* we need to do it again. - if(this->baseClass) - { - this->baseClass->codegen(cs); - clsty->setBaseClass(clsty->getBaseClass()); - } - - - for(auto method : this->methods) - { - auto res = method->codegen(cs); - - auto f = dcast(fir::Function, res.value); - meths.push_back(f); - - if(method->isVirtual) - clsty->addVirtualMethod(f); - - if(method->id.name == "init") inits.push_back(f); - if(method->id.name == "deinit") clsty->setDestructor(f); - if(method->id.name == "copy") clsty->setCopyConstructor(f); - if(method->id.name == "move") clsty->setMoveConstructor(f); - } - - clsty->setMethods(meths); - clsty->setInitialiserFunctions(inits); - - - for(auto sm : this->staticFields) - sm->codegen(cs); - - for(auto sm : this->staticMethods) - sm->codegen(cs); - - for(auto nt : this->nestedTypes) - nt->codegen(cs); - - - auto restore = cs->irb.getCurrentBlock(); - - - - // make the inline initialiser - { - fir::Function* func = cs->module->getOrCreateFunction(fir::Name::obfuscate(clsty->encodedStr(), "_inline_init"), - fir::FunctionType::get({ this->type->getMutablePointerTo() }, fir::Type::getVoid()), - fir::LinkageType::Internal); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - auto self = cs->irb.Dereference(func->getArguments()[0], "this"); - - // make sure we call the base init first. - if(clsty->getBaseClass()) - { - auto bii = clsty->getBaseClass()->getInlineInitialiser(); - iceAssert(bii); - - cs->irb.Call(bii, cs->irb.PointerTypeCast(cs->irb.AddressOf(self, true), clsty->getBaseClass()->getMutablePointerTo())); - } - - // set our vtable - if(clsty->getVirtualMethodCount() > 0) - { - auto vtable = cs->irb.PointerTypeCast(cs->irb.AddressOf(cs->module->getOrCreateVirtualTableForClass(clsty), false), - fir::Type::getInt8Ptr()); - cs->irb.SetVtable(self, vtable); - } - - for(auto fd : this->fields) - { - if(fd->init) - { - auto res = fd->init->codegen(cs, fd->type).value; - auto elmptr = cs->irb.GetStructMember(self, fd->id.name); - - cs->autoAssignRefCountedValue(elmptr, res, true); - } - else - { - auto elmptr = cs->irb.GetStructMember(self, fd->id.name); - cs->autoAssignRefCountedValue(elmptr, cs->getDefaultValue(fd->type), true); - } - } - - cs->irb.ReturnVoid(); - clsty->setInlineInitialiser(func); - } - - // this is the inline destructor - { - fir::Function* func = cs->module->getOrCreateFunction(fir::Name::obfuscate(clsty->encodedStr(), "_inline_deinit"), - fir::FunctionType::get({ this->type->getMutablePointerTo() }, fir::Type::getVoid()), - fir::LinkageType::Internal); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - auto selfptr = func->getArguments()[0]; - auto self = cs->irb.Dereference(selfptr, "this"); - - for(auto f : this->fields) - { - if(f->type->isClassType()) - { - auto fld = cs->irb.GetStructMember(self, f->id.name); - cs->callDestructor(fld); - } - } - - // ok, now that we have destroyed our own fields, call the base class destructor, followed by the base class inline destructor! - if(auto base = clsty->getBaseClass(); base) - { - auto baseptr = cs->irb.PointerTypeCast(selfptr, base->getMutablePointerTo()); - - if(auto des = base->getDestructor(); des) - cs->irb.Call(des, baseptr); - - cs->irb.Call(base->getInlineDestructor(), baseptr); - } - - cs->irb.ReturnVoid(); - clsty->setInlineDestructor(func); - } - - cs->irb.setCurrentBlock(restore); - - - return CGResult(0); -} - - - - -fir::Value* cgn::CodegenState::callVirtualMethod(sst::FunctionCall* call) -{ - auto fd = dcast(sst::FunctionDefn, call->target); - iceAssert(fd); - - auto cls = fd->parentTypeForMethod->toClassType(); - iceAssert(cls); - - - if(call->isImplicitMethodCall) - { - iceAssert(this->isInMethodBody() && fd->parentTypeForMethod); - - auto fake = util::pool(call->loc, fd->parentTypeForMethod->getPointerTo()); - fake->rawValue = CGResult(this->irb.AddressOf(this->getMethodSelf(), /* mutable: */ true)); - - //! SELF HANDLING (INSERTION) (CODEGEN) - call->arguments.insert(call->arguments.begin(), FnCallArgument(call->loc, "this", fake, 0)); - } - - iceAssert(fd->type->isFunctionType()); - - auto ft = fd->type->toFunctionType(); - auto args = this->codegenAndArrangeFunctionCallArguments(fd, ft, call->arguments); - - auto idx = cls->getVirtualMethodIndex(call->name, ft); - return this->irb.CallVirtualMethod(cls, ft, idx, args); -} - - - - - - - - - - - - - - - - - - - - - diff --git a/source/codegen/codegenstate.cpp b/source/codegen/codegenstate.cpp index f09e0c8e..94202658 100644 --- a/source/codegen/codegenstate.cpp +++ b/source/codegen/codegenstate.cpp @@ -15,7 +15,7 @@ namespace cgn this->methodSelfStack.push_back(self); auto ty = self->getType(); - iceAssert(ty->isClassType() || ty->isStructType()); + iceAssert(ty->isStructType()); this->methodList[method] = ty; } @@ -176,30 +176,7 @@ namespace cgn fir::Value* CodegenState::getDefaultValue(fir::Type* type) { fir::Value* ret = 0; - if(type->isStringType()) - { - fir::Value* arr = this->irb.CreateValue(type); - - arr = this->irb.SetSAAData(arr, this->irb.PointerTypeCast(this->irb.GetArraySliceData(fir::ConstantCharSlice::get("")), - fir::Type::getMutInt8Ptr())); - arr = this->irb.SetSAALength(arr, fir::ConstantInt::getNative(0)); - arr = this->irb.SetSAACapacity(arr, fir::ConstantInt::getNative(0)); - arr = this->irb.SetSAARefCountPointer(arr, fir::ConstantValue::getZeroValue(fir::Type::getNativeWord()->getPointerTo())); - - ret = arr; - } - else if(type->isDynamicArrayType()) - { - fir::Value* arr = this->irb.CreateValue(type); - - arr = this->irb.SetSAAData(arr, fir::ConstantValue::getZeroValue(type->getArrayElementType()->getMutablePointerTo())); - arr = this->irb.SetSAALength(arr, fir::ConstantInt::getNative(0)); - arr = this->irb.SetSAACapacity(arr, fir::ConstantInt::getNative(0)); - arr = this->irb.SetSAARefCountPointer(arr, fir::ConstantValue::getZeroValue(fir::Type::getNativeWord()->getPointerTo())); - - ret = arr; - } - else if(type->isArraySliceType()) + if(type->isArraySliceType()) { fir::Value* arr = this->irb.CreateValue(type); arr = this->irb.SetArraySliceData(arr, fir::ConstantValue::getZeroValue(type->getArrayElementType()->getPointerTo())); @@ -207,47 +184,11 @@ namespace cgn ret = arr; } - else if(type->isClassType()) - { - // TODO - //! use constructClassWithArguments!!! - - auto clsdef = dcast(sst::ClassDefn, this->typeDefnMap[type]); - iceAssert(clsdef); - - clsdef->codegen(this); - - // first need to check if we have any initialisers with 0 parameters. - auto cls = type->toClassType(); - - sst::FunctionDefn* ifn = 0; - for(auto init : clsdef->initialisers) - { - //* note: count == 1 because of 'self' - if(init->arguments.size() == 1) - { - ifn = init; - break; - } - } - - if(ifn == 0) - { - SimpleError::make(this->loc(), "class '%s' cannot be automatically initialised as it does not have a constructor taking 0 arguments", - cls->getTypeName())->append(SimpleError::make(MsgType::Note, clsdef->loc, "class '%s' was defined here:", clsdef->id.name)) - ->postAndQuit(); - } - - ret = this->constructClassWithArguments(cls, ifn, { }); - } else { ret = fir::ConstantValue::getZeroValue(type); } - if(fir::isRefCountedType(type)) - this->addRefCountedValue(ret); - ret->setKind(fir::Value::Kind::prvalue); return ret; } diff --git a/source/codegen/constructor.cpp b/source/codegen/constructor.cpp index f79fabab..5518befd 100644 --- a/source/codegen/constructor.cpp +++ b/source/codegen/constructor.cpp @@ -38,99 +38,11 @@ fir::Value* cgn::CodegenState::getConstructedStructValue(fir::StructType* str, c } } - if(fir::isRefCountedType(str)) - this->addRefCountedValue(value); - return value; } -fir::Value* cgn::CodegenState::constructClassWithArguments(fir::ClassType* cls, sst::FunctionDefn* constr, const std::vector& args) -{ - if(auto c = this->typeDefnMap[cls]) - c->codegen(this); - - auto initfn = cls->getInlineInitialiser(); - iceAssert(initfn); - - auto constrfn = dcast(fir::Function, constr->codegen(this, cls).value); - iceAssert(constrfn); - - // this is dirty, very fucking dirty!!! - std::vector vargs; - { - auto copy = args; - auto fake = util::pool(this->loc(), cls->getMutablePointerTo()); - fake->rawValue = CGResult(fir::ConstantValue::getZeroValue(cls->getMutablePointerTo())); - - //? what we are doing here is inserting a fake argument to placate `codegenAndArrangeFunctionCallArguments`, so that - //? it does not error. this just allows us to get *THE REST* of the values in the correct order and generated appropriately, - //? so that we can use their values and get their types below. - - copy.insert(copy.begin(), FnCallArgument(this->loc(), "this", fake, 0)); - vargs = this->codegenAndArrangeFunctionCallArguments(constr, constrfn->getType(), copy); - - // for sanity, assert that it did not change. We should not have to cast anything, and "this" is always the first - // argument in a constructor anyway! - iceAssert(vargs[0] == fake->rawValue.value); - - // after we are done with that shennanigans, erase the first thing, which is the 'this', which doesn't really - // exist here! - vargs.erase(vargs.begin()); - } - - - // make a wrapper... - auto fname = fir::Name::obfuscate("init_wrapper", constr->id.str()); - fir::Function* wrapper_func = this->module->getFunction(fname); - - if(!wrapper_func) - { - auto restore = this->irb.getCurrentBlock(); - - auto arglist = zfu::map(vargs, [](fir::Value* v) -> auto { - return v->getType(); - }); - - wrapper_func = this->module->getOrCreateFunction(fname, fir::FunctionType::get(arglist, cls), fir::LinkageType::Internal); - - fir::IRBlock* entry = this->irb.addNewBlockInFunction("entry", wrapper_func); - this->irb.setCurrentBlock(entry); - - // make the self: - auto selfptr = this->irb.StackAlloc(cls, "self"); - - std::vector argvals = zfu::map(wrapper_func->getArguments(), [](auto a) -> fir::Value* { - return a; - }); - - argvals.insert(argvals.begin(), selfptr); - - this->irb.Call(initfn, selfptr); - - this->irb.Call(constrfn, argvals); - this->irb.Return(this->irb.ReadPtr(selfptr)); - - this->irb.setCurrentBlock(restore); - } - - if(vargs.size() != wrapper_func->getArgumentCount()) - { - SimpleError::make(this->loc(), "mismatched number of arguments in constructor call to class '%s'; expected %d, found %d instead", - cls, constrfn->getArgumentCount(), vargs.size()) - ->append(SimpleError::make(MsgType::Note, constr->loc, "constructor was defined here:")) - ->postAndQuit(); - } - - auto ret = this->irb.Call(wrapper_func, vargs); - this->addRAIIValue(ret); - - return ret; -} - - - CGResult sst::StructConstructorCall::_codegen(cgn::CodegenState* cs, fir::Type* infer) { cs->pushLoc(this); @@ -159,66 +71,6 @@ CGResult sst::StructConstructorCall::_codegen(cgn::CodegenState* cs, fir::Type* -CGResult sst::ClassConstructorCall::_codegen(cgn::CodegenState* cs, fir::Type* infer) -{ - cs->pushLoc(this); - defer(cs->popLoc()); - - this->classty->codegen(cs); - - auto cls = this->classty->type->toClassType(); - auto ret = cs->constructClassWithArguments(cls, this->target, this->arguments); - - if(fir::isRefCountedType(cls)) - cs->addRefCountedValue(ret); - - return CGResult(ret); -} - - - -CGResult sst::BaseClassConstructorCall::_codegen(cgn::CodegenState* cs, fir::Type* infer) -{ - cs->pushLoc(this); - defer(cs->popLoc()); - - this->classty->codegen(cs); - - auto cls = this->classty->type; - auto self = cs->getMethodSelf(); - - iceAssert(self->getType()->isClassType()); - - auto selfty = self->getType()->toClassType(); - iceAssert(selfty->getBaseClass()); - - auto basety = selfty->getBaseClass(); - - // just do it manually here: since we already have a self pointer, we can call the base class constructor function - // directly. plus, we are not calling the inline initialiser also. - { - auto constrfn = dcast(fir::Function, this->target->codegen(cs, cls).value); - iceAssert(constrfn); - - auto copy = this->arguments; - auto selfptr = util::pool(this->loc, selfty->getMutablePointerTo()); - selfptr->rawValue = CGResult(cs->irb.PointerTypeCast(cs->irb.AddressOf(cs->getMethodSelf(), /* mutable: */ true), - basety->getMutablePointerTo())); - - copy.insert(copy.begin(), FnCallArgument(this->loc, "this", selfptr, 0)); - - std::vector vargs = cs->codegenAndArrangeFunctionCallArguments(this->target, constrfn->getType(), copy); - - cs->irb.Call(constrfn, vargs); - } - - return CGResult(0); -} - - - - - diff --git a/source/codegen/controlflow.cpp b/source/codegen/controlflow.cpp index ccaf6cf6..2489fa6c 100644 --- a/source/codegen/controlflow.cpp +++ b/source/codegen/controlflow.cpp @@ -27,8 +27,8 @@ CGResult sst::IfStmt::_codegen(cgn::CodegenState* cs, fir::Type* infer) iceAssert(this->elseCase); fir::IRBlock* elseblk = 0; - if(this->elseCase) elseblk = cs->irb.addNewBlockAfter("elseCase-" + this->elseCase->loc.shortString(), trueblk); - else elseblk = mergeblk; + if(this->elseCase) elseblk = cs->irb.addNewBlockAfter("elseCase-" + this->elseCase->loc.shortString(), trueblk); + else elseblk = mergeblk; // first we gotta do all the inits of all the cases first. // we're already in our own scope, so it shouldn't matter. @@ -108,19 +108,6 @@ CGResult sst::IfStmt::_codegen(cgn::CodegenState* cs, fir::Type* infer) } cs->irb.setCurrentBlock(falseblkr); - { - // TODO: why tf is this commented out?? - - // ok, do the next thing. - // if we're the last block, then gtfo and branch to merge - // if() - // { - // if(!cs->irb.getCurrentBlock()->isTerminated()) - // cs->irb.UnCondBranch(elseblk); - - // break; - // } - } } } else @@ -174,29 +161,12 @@ std::vector sst::IfStmt::getBlocks() static void doBlockEndThings(cgn::CodegenState* cs, const cgn::ControlFlowPoint& cfp, const cgn::BlockPoint& bp) { - #if DEBUG_ARRAY_REFCOUNTING | DEBUG_STRING_REFCOUNTING - { - cs->printIRDebugMessage("\n! CTRLFLOW: at: " + cfp.block->loc.shortString() + "\n{", { }); - cs->pushIRDebugIndentation(); - } - #endif - // then do the defers for(auto stmt : cfp.block->deferred) stmt->_codegen(cs); for(auto c : bp.raiiValues) cs->callDestructor(c); - - for(auto v : bp.refCountedValues) - cs->decrementRefCount(v); - - #if DEBUG_ARRAY_REFCOUNTING | DEBUG_STRING_REFCOUNTING - { - cs->popIRDebugIndentation(); - cs->printIRDebugMessage("}", { }); - } - #endif } CGResult sst::BreakStmt::_codegen(cgn::CodegenState* cs, fir::Type* infer) @@ -233,21 +203,15 @@ CGResult sst::ContinueStmt::_codegen(cgn::CodegenState* cs, fir::Type* infer) CGResult sst::ReturnStmt::_codegen(cgn::CodegenState* cs, fir::Type* infer) { - // check if we have a value, and whether it's refcounted - // if so, inflate its refcount so it doesn't get deallocated and can survive - if(this->value) { auto v = this->value->codegen(cs, this->expectedType).value; - if(fir::isRefCountedType(v->getType())) - cs->incrementRefCount(v); - if(v->getType() != this->expectedType) v = cs->oneWayAutocast(v, this->expectedType); //! RAII: COPY CONSTRUCTOR CALL //? the copy constructor is called when a function returns an object by value - if(v->getType()->isClassType()) + if(cs->typeHasCopyConstructor(v->getType())) v = cs->copyRAIIValue(v); doBlockEndThings(cs, cs->getCurrentCFPoint(), cs->getCurrentBlockPoint()); @@ -299,29 +263,12 @@ CGResult sst::Block::_codegen(cgn::CodegenState* cs, fir::Type* infer) // and ContinueStmt will do it too. if(!broke) { - #if DEBUG_ARRAY_REFCOUNTING | DEBUG_STRING_REFCOUNTING - { - cs->printIRDebugMessage("\n! BLOCKEND: at: " + this->closingBrace.shortString() + "\n{", { }); - cs->pushIRDebugIndentation(); - } - #endif - //* this duplicates stuff from doBlockEndThings!! for(auto it = this->deferred.rbegin(); it != this->deferred.rend(); it++) (*it)->_codegen(cs); for(auto c : cs->getCurrentBlockPoint().raiiValues) cs->callDestructor(c); - - for(auto v : cs->getRefCountedValues()) - cs->decrementRefCount(v); - - #if DEBUG_ARRAY_REFCOUNTING | DEBUG_STRING_REFCOUNTING - { - cs->popIRDebugIndentation(); - cs->printIRDebugMessage("}", { }); - } - #endif } return CGResult(0); diff --git a/source/codegen/destructure.cpp b/source/codegen/destructure.cpp index e1313a67..b3d724bc 100644 --- a/source/codegen/destructure.cpp +++ b/source/codegen/destructure.cpp @@ -23,21 +23,6 @@ CGResult sst::DecompDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) static void handleDefn(cgn::CodegenState* cs, sst::VarDefn* defn, CGResult res) { - // do a quick check for refcounting. - //* note: due to the way vardefn codegen works, if we're assigning from an rvalue and the type is refcounted, - //* we simply remove the rhs from the refcounting stack instead of changing refcounts around. - //* so, since everything that we generate from destructuring is an rvalue, we always need to remove it. - - //* thus in order to remove it, we must first insert it. - - //* also, since the vardefn adds itself to the counting stack, when it dies we will get decremented. - //* however, this cannot be allowed to happen, because we want a copy and not a move. - if(fir::isRefCountedType(res->getType())) - { - cs->addRefCountedValue(res.value); - cs->incrementRefCount(res.value); - } - if(defn) { auto v = util::pool(defn->loc, res.value->getType()); @@ -83,168 +68,81 @@ static void checkArray(cgn::CodegenState* cs, const DecompMapping& bind, CGResul auto rt = rhs.value->getType(); bool shouldSliceBeMutable = sst::getMutabilityOfSliceOfType(rt); - if(!rt->isArrayType() && !rt->isDynamicArrayType() && !rt->isArraySliceType() && !rt->isStringType()) + if(!rt->isArrayType() && !rt->isArraySliceType()) error(bind.loc, "expected array type in destructuring declaration; found type '%s' instead", rt); - if(rt->isStringType()) + auto array = rhs.value; + fir::Value* arrlen = 0; + + auto numbinds = fir::ConstantInt::getNative(bind.inner.size()); { - // do a bounds check. - auto numbinds = fir::ConstantInt::getNative(bind.inner.size()); - { - auto checkf = cgn::glue::string::getBoundsCheckFunction(cs, true); - if(checkf) - { - auto strloc = fir::ConstantCharSlice::get(bind.loc.toString()); - cs->irb.Call(checkf, cs->irb.GetSAALength(rhs.value), numbinds, strloc); - } - } + if(rt->isArrayType()) arrlen = fir::ConstantInt::getNative(rt->toArrayType()->getArraySize()); + else if(rt->isArraySliceType()) arrlen = cs->irb.GetArraySliceLength(array); + else iceAssert(0); + } - //* note: special-case this, because 1. we want to return chars - auto strdat = cs->irb.PointerTypeCast(cs->irb.GetSAAData(rhs.value), fir::Type::getMutInt8Ptr()); - { - size_t idx = 0; - for(auto& b : bind.inner) - { - auto v = CGResult(cs->irb.ReadPtr(cs->irb.GetPointer(strdat, fir::ConstantInt::getNative(idx)))); - cs->generateDecompositionBindings(b, v, false); + // # if 0 + if(!rhs->islvalue() && rt->isArrayType()) + { + //* because of the way LLVM is designed, and hence by extension how we are designed, + //* fixed-sized arrays are kinda dumb. If we don't have a pointer to the array (for whatever reason???), + //* then we can't do a GEP access, and hence can't get a pointer to use for the 'rest' binding. So, + //* we error on that case but allow binding the rest. - idx++; - } - } + //* theoretically if the compiler is well designed we should never hit this case, but who knows? - if(!bind.restName.empty()) + size_t idx = 0; + for(auto& b : bind.inner) { - if(bind.restRef) - { - // make a slice of char. - auto remaining = cs->irb.Subtract(cs->irb.GetSAALength(rhs.value), numbinds); - - auto slice = cs->irb.CreateValue(fir::Type::getCharSlice(shouldSliceBeMutable)); - slice = cs->irb.SetArraySliceData(slice, cs->irb.GetPointer(strdat, numbinds)); - slice = cs->irb.SetArraySliceLength(slice, remaining); - - handleDefn(cs, bind.restDefn, CGResult(slice)); - } - else - { - // make string. - // auto remaining = cs->irb.Subtract(cs->irb.GetSAALength(rhs.value), numbinds); + auto v = CGResult(cs->irb.ExtractValue(array, { idx })); + cs->generateDecompositionBindings(b, v, false); - auto clonef = cgn::glue::string::getCloneFunction(cs); - iceAssert(clonef); - - auto string = cs->irb.Call(clonef, rhs.value, numbinds); - - handleDefn(cs, bind.restDefn, CGResult(string)); - } + idx++; } + + warn(bind.loc, "destructure of array without pointer (shouldn't happen!)"); + if(!bind.restName.empty()) + error(bind.loc, "could not get pointer to array (of type '%s') to create binding for '...'", rt); } else - { - auto array = rhs.value; - fir::Value* arrlen = 0; + // #endif - auto numbinds = fir::ConstantInt::getNative(bind.inner.size()); - { - if(rt->isArrayType()) arrlen = fir::ConstantInt::getNative(rt->toArrayType()->getArraySize()); - else if(rt->isArraySliceType()) arrlen = cs->irb.GetArraySliceLength(array); - else if(rt->isDynamicArrayType()) arrlen = cs->irb.GetSAALength(array); - else iceAssert(0); - - //* note: 'true' means we're performing a decomposition, so print a more appropriate error message on bounds failure. - auto checkf = cgn::glue::array::getBoundsCheckFunction(cs, true); - if(checkf) - { - auto strloc = fir::ConstantCharSlice::get(bind.loc.toString()); - cs->irb.Call(checkf, arrlen, numbinds, strloc); - } - } + { + fir::Value* data = 0; - // # if 0 - if(!rhs->islvalue() && rt->isArrayType()) - { - //* because of the way LLVM is designed, and hence by extension how we are designed, - //* fixed-sized arrays are kinda dumb. If we don't have a pointer to the array (for whatever reason???), - //* then we can't do a GEP access, and hence can't get a pointer to use for the 'rest' binding. So, - //* we error on that case but allow binding the rest. + if(rt->isArrayType()) data = cs->irb.ConstGEP2(rhs.value, 0, 0); + else if(rt->isArraySliceType()) data = cs->irb.GetArraySliceData(array); + else iceAssert(0); - //* theoretically if the compiler is well designed we should never hit this case, but who knows? - size_t idx = 0; - for(auto& b : bind.inner) - { - auto v = CGResult(cs->irb.ExtractValue(array, { idx })); - cs->generateDecompositionBindings(b, v, false); + size_t idx = 0; + for(auto& b : bind.inner) + { + auto ptr = cs->irb.GetPointer(data, fir::ConstantInt::getNative(idx)); - idx++; - } + auto v = CGResult(cs->irb.Dereference(ptr)); + cs->generateDecompositionBindings(b, v, true); - warn(bind.loc, "destructure of array without pointer (shouldn't happen!)"); - if(!bind.restName.empty()) - error(bind.loc, "could not get pointer to array (of type '%s') to create binding for '...'", rt); + idx++; } - else - // #endif + if(!bind.restName.empty()) { - fir::Value* data = 0; - - if(rt->isArrayType()) data = cs->irb.ConstGEP2(rhs.value, 0, 0); - else if(rt->isArraySliceType()) data = cs->irb.GetArraySliceData(array); - else if(rt->isDynamicArrayType()) data = cs->irb.GetSAAData(array); - else iceAssert(0); - - - size_t idx = 0; - for(auto& b : bind.inner) + if(bind.restRef) { - auto ptr = cs->irb.GetPointer(data, fir::ConstantInt::getNative(idx)); + auto sty = fir::ArraySliceType::get(rt->getArrayElementType(), shouldSliceBeMutable); - auto v = CGResult(cs->irb.Dereference(ptr)); - cs->generateDecompositionBindings(b, v, true); + auto remaining = cs->irb.Subtract(arrlen, numbinds); - idx++; - } + auto slice = cs->irb.CreateValue(sty); + slice = cs->irb.SetArraySliceData(slice, cs->irb.GetPointer(data, numbinds)); + slice = cs->irb.SetArraySliceLength(slice, remaining); - if(!bind.restName.empty()) + handleDefn(cs, bind.restDefn, CGResult(slice)); + } + else { - if(bind.restRef) - { - auto sty = fir::ArraySliceType::get(rt->getArrayElementType(), shouldSliceBeMutable); - - auto remaining = cs->irb.Subtract(arrlen, numbinds); - - auto slice = cs->irb.CreateValue(sty); - slice = cs->irb.SetArraySliceData(slice, cs->irb.GetPointer(data, numbinds)); - slice = cs->irb.SetArraySliceLength(slice, remaining); - - handleDefn(cs, bind.restDefn, CGResult(slice)); - } - else - { - // always return a dynamic array here. - //* note: in order to make our lives somewhat easier, for fixed arrays, we create a fake slice pointing to its data, then we - //* call clone on that instead. - - fir::Value* clonee = 0; - if(rt->isArrayType()) - { - clonee = cs->irb.CreateValue(fir::ArraySliceType::get(rt->getArrayElementType(), shouldSliceBeMutable)); - clonee = cs->irb.SetArraySliceData(clonee, data); - clonee = cs->irb.SetArraySliceLength(clonee, fir::ConstantInt::getNative(rt->toArrayType()->getArraySize())); - } - else - { - clonee = array; - } - - auto clonef = cgn::glue::array::getCloneFunction(cs, clonee->getType()); - iceAssert(clonef); - - auto ret = cs->irb.Call(clonef, clonee, numbinds); - - handleDefn(cs, bind.restDefn, CGResult(ret)); - } + error("gone"); } } } diff --git a/source/codegen/dotop.cpp b/source/codegen/dotop.cpp index 64d665fe..7dc1d509 100644 --- a/source/codegen/dotop.cpp +++ b/source/codegen/dotop.cpp @@ -10,7 +10,7 @@ static bool isAutoDereferencable(fir::Type* t) { - return (t->isStructType() || t->isClassType() || t->isRawUnionType()); + return (t->isStructType() || t->isRawUnionType()); } static CGResult getAppropriateValuePointer(cgn::CodegenState* cs, sst::Expr* user, sst::Expr* lhs, fir::Type** baseType) @@ -222,9 +222,6 @@ CGResult cgn::CodegenState::getStructFieldImplicitly(std::string name) if(ty->isStructType()) return dothing(ty->toStructType()); - else if(ty->isClassType()) - return dothing(ty->toClassType()); - else error(this->loc(), "invalid self type '%s' for field named '%s'", ty, name); } diff --git a/source/codegen/glue/any.cpp b/source/codegen/glue/any.cpp deleted file mode 100644 index 37b07059..00000000 --- a/source/codegen/glue/any.cpp +++ /dev/null @@ -1,332 +0,0 @@ -// any.cpp -// Copyright (c) 2017, zhiayang -// Licensed under the Apache License Version 2.0. - - -#include "codegen.h" -#include "platform.h" -#include "gluecode.h" - -namespace cgn { -namespace glue { -namespace any -{ - static void _doRefCount(CodegenState* cs, fir::Function* func, bool decrement) - { - auto any = func->getArguments()[0]; - auto rcp = cs->irb.GetAnyRefCountPointer(any, "rcp"); - - fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); - fir::IRBlock* dorc = cs->irb.addNewBlockInFunction("dorc", func); - - cs->irb.CondBranch(cs->irb.ICmpEQ(rcp, fir::ConstantValue::getZeroValue(fir::Type::getNativeWordPtr())), - merge, dorc); - - cs->irb.setCurrentBlock(dorc); - { - auto oldrc = cs->irb.ReadPtr(rcp, "oldrc"); - auto newrc = cs->irb.Add(oldrc, fir::ConstantInt::getNative(decrement ? -1 : 1)); - - cs->irb.SetAnyRefCount(any, newrc); - - #if DEBUG_ANY_REFCOUNTING - { - std::string x = decrement ? "(decr)" : "(incr)"; - - cs->printIRDebugMessage("* ANY: " + x + " - new rc of: (rcptr: %p) = %d", - { cs->irb.GetAnyRefCountPointer(any), cs->irb.GetAnyRefCount(any) }); - } - #endif - - if(decrement) - { - fir::IRBlock* dofree = cs->irb.addNewBlockInFunction("dofree", func); - - auto cond = cs->irb.ICmpEQ(newrc, fir::ConstantInt::getNative(0)); - - // this thing checks for the MSB of the typeid; if it's set, means we used heap memory and so we need to free. - cond = cs->irb.BitwiseAND(cond, - cs->irb.ICmpGT(cs->irb.BitwiseAND(cs->irb.GetAnyTypeID(any), fir::ConstantInt::getUNative(BUILTIN_ANY_FLAG_MASK)), - fir::ConstantInt::getUNative(0))); - - cs->irb.CondBranch(cond, dofree, merge); - - cs->irb.setCurrentBlock(dofree); - { - auto freefn = cs->getOrDeclareLibCFunction(FREE_MEMORY_FUNC); - iceAssert(freefn); - - //* because llvm is a little restrictive wrt. how we can fiddle with types and memory, in - //* order to cast the data buffer (which is an array) to a i64*, we first get the array, - //* then make a stack alloc, store the array value, use the alloc as an address and cast it - //* to i64*, then dereference that to get the actual pointer to the heap memory. - - // 1. this gets us a memory location we can use. - auto _buf = cs->irb.GetAnyData(any, "buf"); - auto buf = cs->irb.StackAlloc(_buf->getType()); - cs->irb.WritePtr(_buf, buf); - - // 2. 'buf' is a pointer to the array itself -- we cast it to i64*, so the dereference - // gives us the first 8 bytes of the data buffer. - buf = cs->irb.PointerTypeCast(buf, fir::Type::getNativeWordPtr()); - - // 3. this is the dereference. - auto ptr = cs->irb.ReadPtr(buf); - - // 4. the first 8 bytes are actually a pointer to the heap memory. - ptr = cs->irb.IntToPointerCast(ptr, fir::Type::getMutInt8Ptr()); - - cs->irb.Call(freefn, ptr); - cs->irb.Call(freefn, cs->irb.PointerTypeCast(cs->irb.GetAnyRefCountPointer(any), fir::Type::getMutInt8Ptr())); - - #if DEBUG_ANY_ALLOCATION - { - cs->printIRDebugMessage("* ANY: free(): (ptr: %p / rcp: %p)", { - ptr, cs->irb.GetAnyRefCountPointer(any) }); - } - #endif - } - } - - cs->irb.UnCondBranch(merge); - } - - cs->irb.setCurrentBlock(merge); - { - cs->irb.ReturnVoid(); - } - } - - - - - fir::Function* getRefCountIncrementFunction(CodegenState* cs) - { - auto fname = misc::getIncrRefcount_FName(fir::Type::getAny()); - fir::Function* retfn = cs->module->getFunction(fname); - - if(!retfn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ fir::Type::getAny() }, fir::Type::getVoid()), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - _doRefCount(cs, func, false); - - cs->irb.setCurrentBlock(restore); - retfn = func; - } - - iceAssert(retfn); - return retfn; - } - - fir::Function* getRefCountDecrementFunction(CodegenState* cs) - { - auto fname = misc::getDecrRefcount_FName(fir::Type::getAny()); - fir::Function* retfn = cs->module->getFunction(fname); - - if(!retfn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ fir::Type::getAny() }, fir::Type::getVoid()), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - _doRefCount(cs, func, true); - - cs->irb.setCurrentBlock(restore); - retfn = func; - } - - iceAssert(retfn); - return retfn; - } - - - - fir::Function* generateCreateAnyWithValueFunction(CodegenState* cs, fir::Type* type) - { - auto fname = misc::getCreateAnyOf_FName(type); - fir::Function* retfn = cs->module->getFunction(fname); - - if(!retfn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ type }, fir::Type::getAny()), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - - auto any = cs->irb.CreateValue(fir::Type::getAny()); - auto dataarrty = fir::ArrayType::get(fir::Type::getInt8(), BUILTIN_ANY_DATA_BYTECOUNT); - - // make the refcount pointer. - auto rcp = cs->irb.PointerTypeCast(cs->irb.Call(cs->getOrDeclareLibCFunction(ALLOCATE_MEMORY_FUNC), - fir::ConstantInt::getNative(REFCOUNT_SIZE)), fir::Type::getNativeWordPtr()); - - any = cs->irb.SetAnyRefCountPointer(any, rcp); - cs->irb.SetAnyRefCount(any, fir::ConstantInt::getNative(1)); - - size_t tid = type->getID(); - if(auto typesz = fir::getSizeOfType(type); typesz > BUILTIN_ANY_DATA_BYTECOUNT) - { - tid |= BUILTIN_ANY_FLAG_MASK; - - auto ptr = cs->irb.PointerTypeCast(cs->irb.Call(cs->getOrDeclareLibCFunction(ALLOCATE_MEMORY_FUNC), - fir::ConstantInt::getNative(typesz)), type->getMutablePointerTo()); - - #if DEBUG_ANY_ALLOCATION - { - cs->printIRDebugMessage("* ANY: alloc(): (id: %lu, ptr: %p / rcp: %p)", { - fir::ConstantInt::getUNative(tid), ptr, rcp }); - } - #endif - - cs->irb.WritePtr(func->getArguments()[0], ptr); - ptr = cs->irb.PointerToIntCast(ptr, fir::Type::getNativeWord()); - - // now, we make a fake data, and then store it. - auto arrptr = cs->irb.StackAlloc(dataarrty); - auto fakeptr = cs->irb.PointerTypeCast(arrptr, fir::Type::getNativeWordPtr()->getMutablePointerVersion()); - cs->irb.WritePtr(ptr, fakeptr); - - auto arr = cs->irb.ReadPtr(arrptr); - any = cs->irb.SetAnyData(any, arr); - } - else - { - auto arrptr = cs->irb.StackAlloc(dataarrty); - auto fakeptr = cs->irb.PointerTypeCast(arrptr, type->getMutablePointerTo()); - cs->irb.WritePtr(func->getArguments()[0], fakeptr); - - auto arr = cs->irb.ReadPtr(arrptr); - any = cs->irb.SetAnyData(any, arr); - - - } - - any = cs->irb.SetAnyTypeID(any, fir::ConstantInt::getUNative(tid)); - - cs->irb.Return(any); - - cs->irb.setCurrentBlock(restore); - retfn = func; - } - - iceAssert(retfn); - return retfn; - } - - fir::Function* generateGetValueFromAnyFunction(CodegenState* cs, fir::Type* type) - { - auto fname = misc::getGetValueFromAny_FName(type); - fir::Function* retfn = cs->module->getFunction(fname); - - if(!retfn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ fir::Type::getAny() }, type), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - auto any = func->getArguments()[0]; - - auto dataarrty = fir::ArrayType::get(fir::Type::getInt8(), BUILTIN_ANY_DATA_BYTECOUNT); - auto tid = cs->irb.BitwiseAND(cs->irb.GetAnyTypeID(any), fir::ConstantInt::getUNative(~BUILTIN_ANY_FLAG_MASK)); - - fir::IRBlock* invalid = cs->irb.addNewBlockInFunction("invalid", cs->irb.getCurrentFunction()); - fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", cs->irb.getCurrentFunction()); - - auto valid = cs->irb.ICmpEQ(tid, fir::ConstantInt::getUNative(type->getID())); - cs->irb.CondBranch(valid, merge, invalid); - - cs->irb.setCurrentBlock(invalid); - { - printRuntimeError(cs, fir::ConstantCharSlice::get(cs->loc().toString()), - "invalid unwrap of 'any' with type id '%ld' into type '%s' (with id '%ld')", - { tid, cs->module->createGlobalString(type->str()), fir::ConstantInt::getUNative(type->getID()) } - ); - } - - cs->irb.setCurrentBlock(merge); - { - if(fir::getSizeOfType(type) > BUILTIN_ANY_DATA_BYTECOUNT) - { - // same as above, but in reverse. - auto arrptr = cs->irb.StackAlloc(dataarrty); - cs->irb.WritePtr(cs->irb.GetAnyData(any), arrptr); - - // cast the array* into a type**, so when we dereference it, we get the first 8 bytes interpreted as a type*. - // we then just load and return that. - auto fakeptr = cs->irb.PointerTypeCast(arrptr, type->getMutablePointerTo()->getMutablePointerTo()); - auto typeptr = cs->irb.ReadPtr(fakeptr); - - cs->irb.Return(cs->irb.ReadPtr(typeptr)); - } - else - { - auto arrptr = cs->irb.StackAlloc(dataarrty); - cs->irb.WritePtr(cs->irb.GetAnyData(any), arrptr); - - // same as above but we skip a load. - auto fakeptr = cs->irb.PointerTypeCast(arrptr, type->getMutablePointerTo()); - auto ret = cs->irb.ReadPtr(fakeptr); - - cs->irb.Return(ret); - } - } - - - cs->irb.setCurrentBlock(restore); - retfn = func; - } - - iceAssert(retfn); - return retfn; - } -} -} -} - - - - - - - - - - - - - - - - - - - - - diff --git a/source/codegen/glue/arrays.cpp b/source/codegen/glue/arrays.cpp index 33d29c5f..ea393ae1 100644 --- a/source/codegen/glue/arrays.cpp +++ b/source/codegen/glue/arrays.cpp @@ -11,223 +11,6 @@ namespace cgn { namespace glue { namespace array { - fir::Function* getBoundsCheckFunction(CodegenState* cs, bool isPerformingDecomposition) - { - return saa_common::generateBoundsCheckFunction(cs, /* isString: */false, isPerformingDecomposition); - } - - fir::Function* getCloneFunction(CodegenState* cs, fir::Type* arrtype) - { - return saa_common::generateCloneFunction(cs, arrtype); - } - - fir::Function* getReserveExtraFunction(CodegenState* cs, fir::DynamicArrayType* arrtype) - { - return saa_common::generateReserveExtraFunction(cs, arrtype); - } - - fir::Function* getReserveAtLeastFunction(CodegenState* cs, fir::DynamicArrayType* arrtype) - { - return saa_common::generateReserveAtLeastFunction(cs, arrtype); - } - - fir::Function* getAppendFunction(CodegenState* cs, fir::DynamicArrayType* arrtype) - { - return saa_common::generateAppendFunction(cs, arrtype); - } - - fir::Function* getElementAppendFunction(CodegenState* cs, fir::DynamicArrayType* arrtype) - { - return saa_common::generateElementAppendFunction(cs, arrtype); - } - - - - - - fir::Function* getCallClassConstructorOnElementsFunction(CodegenState* cs, fir::ClassType* cls, sst::FunctionDefn* constr, - const std::vector& args) - { - iceAssert(cls); - - auto fname = misc::getCallClassConstructor_FName(cls); - fir::Function* fn = cs->module->getFunction(fname); - - if(!fn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ cls->getPointerTo(), fir::Type::getNativeWord() }, fir::Type::getVoid()), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - // ok: the real difference with the one below is that we need to call the constructor function on every element. - - fir::Value* arrdata = func->getArguments()[0]; - fir::Value* len = func->getArguments()[1]; - - - fir::IRBlock* check = cs->irb.addNewBlockInFunction("check", func); - fir::IRBlock* body = cs->irb.addNewBlockInFunction("body", func); - fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); - - auto ctrptr = cs->irb.StackAlloc(fir::Type::getNativeWord()); - - // already set to 0 internally - - cs->irb.UnCondBranch(check); - cs->irb.setCurrentBlock(check); - { - auto cond = cs->irb.ICmpLT(cs->irb.ReadPtr(ctrptr), len); - cs->irb.CondBranch(cond, body, merge); - } - - cs->irb.setCurrentBlock(body); - { - auto ctr = cs->irb.ReadPtr(ctrptr); - auto ptr = cs->irb.GetPointer(arrdata, ctr); - - auto val = cs->constructClassWithArguments(cls, constr, args); - - // TODO: this is a bit dubious?? - cs->irb.WritePtr(val, ptr); - - cs->irb.WritePtr(cs->irb.Add(ctr, fir::ConstantInt::getNative(1)), ctrptr); - - cs->irb.UnCondBranch(check); - } - - cs->irb.setCurrentBlock(merge); - cs->irb.ReturnVoid(); - - - - - cs->irb.setCurrentBlock(restore); - fn = func; - } - - return fn; - } - - - fir::Function* getSetElementsToValueFunction(CodegenState* cs, fir::Type* elmType) - { - iceAssert(elmType); - - auto fname = misc::getSetElements_FName(elmType); - fir::Function* fn = cs->module->getFunction(fname); - - if(!fn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ elmType->getMutablePointerTo(), fir::Type::getNativeWord(), elmType }, fir::Type::getVoid()), - fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - fir::Value* arrdata = func->getArguments()[0]; - fir::Value* len = func->getArguments()[1]; - fir::Value* value = func->getArguments()[2]; - - iceAssert(value); - fir::IRBlock* check = cs->irb.addNewBlockInFunction("check", func); - fir::IRBlock* body = cs->irb.addNewBlockInFunction("body", func); - fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); - - auto ctrptr = cs->irb.StackAlloc(fir::Type::getNativeWord()); - - cs->irb.UnCondBranch(check); - cs->irb.setCurrentBlock(check); - { - auto cond = cs->irb.ICmpLT(cs->irb.ReadPtr(ctrptr), len); - cs->irb.CondBranch(cond, body, merge); - } - - cs->irb.setCurrentBlock(body); - { - auto ctr = cs->irb.ReadPtr(ctrptr); - auto ptr = cs->irb.GetPointer(arrdata, ctr); - - cs->autoAssignRefCountedValue(ptr, value, true); - - cs->irb.WritePtr(cs->irb.Add(ctr, fir::ConstantInt::getNative(1)), ctrptr); - - cs->irb.UnCondBranch(check); - } - - cs->irb.setCurrentBlock(merge); - cs->irb.ReturnVoid(); - - - cs->irb.setCurrentBlock(restore); - fn = func; - } - - return fn; - } - - - fir::Function* getSetElementsToDefaultValueFunction(CodegenState* cs, fir::Type* elmType) - { - iceAssert(elmType); - - auto fname = misc::getSetElementsDefault_FName(elmType); - fir::Function* fn = cs->module->getFunction(fname); - - if(!fn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ elmType->getMutablePointerTo(), fir::Type::getNativeWord() }, fir::Type::getVoid()), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - fir::Value* value = 0; - - if(elmType->isClassType()) - value = cs->irb.CreateValue(elmType); - - else - value = cs->getDefaultValue(elmType); - - iceAssert(value); - - auto setfn = getSetElementsToValueFunction(cs, elmType); - iceAssert(setfn); - - cs->irb.Call(setfn, func->getArguments()[0], func->getArguments()[1], value); - - cs->irb.ReturnVoid(); - - - cs->irb.setCurrentBlock(restore); - fn = func; - } - - return fn; - } - - - - - - - - static void _compareFunctionUsingBuiltinCompare(CodegenState* cs, fir::Type* arrtype, fir::Function* func, fir::Value* arg1, fir::Value* arg2) { @@ -242,12 +25,7 @@ namespace array fir::Value* ptr1 = 0; fir::Value* ptr2 = 0; - if(arrtype->isDynamicArrayType()) - { - ptr1 = cs->irb.GetSAAData(arg1); - ptr2 = cs->irb.GetSAAData(arg2); - } - else if(arrtype->isArraySliceType()) + if(arrtype->isArraySliceType()) { ptr1 = cs->irb.GetArraySliceData(arg1); ptr2 = cs->irb.GetArraySliceData(arg2); @@ -264,12 +42,7 @@ namespace array fir::Value* len1 = 0; fir::Value* len2 = 0; - if(arrtype->isDynamicArrayType()) - { - len1 = cs->irb.GetSAALength(arg1); - len2 = cs->irb.GetSAALength(arg2); - } - else if(arrtype->isArraySliceType()) + if(arrtype->isArraySliceType()) { len1 = cs->irb.GetArraySliceLength(arg1); len2 = cs->irb.GetArraySliceLength(arg2); @@ -388,8 +161,6 @@ namespace array error("notsup"); } - - fir::Function* getCompareFunction(CodegenState* cs, fir::Type* arrtype, fir::Function* opf) { iceAssert(arrtype); @@ -434,313 +205,6 @@ namespace array iceAssert(cmpf); return cmpf; } - - - - - - - - - static fir::Function* makeRecursiveRefCountingFunction(CodegenState* cs, fir::DynamicArrayType* arrtype, bool incr) - { - auto fname = misc::getRecursiveRefcount_FName(arrtype, incr); - fir::Function* retf = cs->module->getFunction(fname); - - if(!retf) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ arrtype }, fir::Type::getVoid()), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - fir::Value* arr = func->getArguments()[0]; - - auto ptr = cs->irb.GetSAAData(arr); - auto len = cs->irb.GetSAALength(arr); - auto cap = cs->irb.GetSAACapacity(arr); - - - { - auto elmtype = arrtype->getElementType(); - - // here we check whether we actually have a refcount pointer. If we don't, then we're a literal, and there's no need to change - // the refcount anyway. - auto prevblk = cs->irb.getCurrentBlock(); - auto dorc = cs->irb.addNewBlockInFunction("dorc", cs->irb.getCurrentFunction()); - auto dontrc = cs->irb.addNewBlockInFunction("dontrcliteral", cs->irb.getCurrentFunction()); - { - auto rcp = cs->irb.GetSAARefCountPointer(arr); - auto cond = cs->irb.ICmpNEQ(cs->irb.PointerToIntCast(rcp, fir::Type::getNativeWord()), fir::ConstantInt::getNative(0)); - - cs->irb.CondBranch(cond, dorc, dontrc); - } - - fir::Value* therefc = 0; - cs->irb.setCurrentBlock(dorc); - { - therefc = cs->irb.GetSAARefCount(arr); - - fir::Value* newrc = 0; - if(incr) newrc = cs->irb.Add(therefc, fir::ConstantInt::getNative(1)); - else newrc = cs->irb.Subtract(therefc, fir::ConstantInt::getNative(1)); - - // update it. - therefc = newrc; - cs->irb.SetSAARefCount(arr, newrc); - cs->irb.UnCondBranch(dontrc); - } - - cs->irb.setCurrentBlock(dontrc); - - #if DEBUG_ARRAY_REFCOUNTING - { - std::string x = incr ? "(incr)" : "(decr)"; - - cs->printIRDebugMessage("* ARRAY: " + x + " - new rc of: (ptr: %p, len: %ld, cap: %ld) = %d", - { cs->irb.GetSAAData(arr), cs->irb.GetSAALength(arr), cs->irb.GetSAACapacity(arr), cs->irb.GetSAARefCount(arr) }); - } - #endif - - // ok. if we're incrementing, then we're done -- but if we're decrementing, we may need to free the memory. - if(!incr) - { - fir::IRBlock* dealloc = cs->irb.addNewBlockInFunction("dealloc", func); - fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); - - auto zv = fir::ConstantInt::getNative(0); - - //! NOTE: what we want to happen here is for us to free the memory, but only if refcnt == 0 && capacity >= 0 - //* so our condition is (REFCOUNT == 0) & (CAP >= 0) - - auto refc = cs->irb.CreatePHINode(fir::Type::getNativeWord()); - refc->addIncoming(therefc, dorc); - refc->addIncoming(fir::ConstantInt::getNative(-1), prevblk); - - auto dofree = cs->irb.BitwiseAND(cs->irb.ICmpEQ(refc, zv), cs->irb.ICmpGEQ(cap, zv)); - - - cs->irb.CondBranch(dofree, dealloc, merge); - - cs->irb.setCurrentBlock(dealloc); - { - auto memptr = cs->irb.PointerTypeCast(ptr, fir::Type::getMutInt8Ptr()); - - auto freefn = cs->getOrDeclareLibCFunction(FREE_MEMORY_FUNC); - iceAssert(freefn); - - // only when we free, do we loop through our array and decrement its refcount. - if(fir::isRefCountedType(elmtype)) - { - auto ctrp = cs->irb.StackAlloc(fir::Type::getNativeWord()); - cs->irb.WritePtr(zv, ctrp); - - cs->createWhileLoop([cs, ctrp, len](auto pass, auto fail) { - auto cond = cs->irb.ICmpLT(cs->irb.ReadPtr(ctrp), len); - cs->irb.CondBranch(cond, pass, fail); - }, - [cs, ctrp, ptr]() { - - auto ctr = cs->irb.ReadPtr(ctrp); - auto p = cs->irb.GetPointer(ptr, ctr); - - cs->decrementRefCount(cs->irb.ReadPtr(p)); - - cs->irb.WritePtr(cs->irb.Add(ctr, fir::ConstantInt::getNative(1)), ctrp); - }); - } - - cs->irb.Call(freefn, memptr); - cs->irb.Call(freefn, cs->irb.PointerTypeCast(cs->irb.GetSAARefCountPointer(arr), fir::Type::getMutInt8Ptr())); - - #if DEBUG_ARRAY_ALLOCATION - { - cs->printIRDebugMessage("* ARRAY: free(): (ptr: %p / rcp: %p)", { - memptr, cs->irb.GetSAARefCountPointer(arr) }); - } - #endif - - - cs->irb.UnCondBranch(merge); - } - - cs->irb.setCurrentBlock(merge); - } - } - - - - cs->irb.ReturnVoid(); - - cs->irb.setCurrentBlock(restore); - retf = func; - } - - iceAssert(retf); - return retf; - } - - - - - - - static fir::Function* _getDoRefCountFunctionForDynamicArray(CodegenState* cs, fir::DynamicArrayType* arrtype, bool increment) - { - auto fname = (increment ? misc::getLoopIncrRefcount_FName(arrtype) : misc::getLoopDecrRefcount_FName(arrtype)); - fir::Function* cmpf = cs->module->getFunction(fname); - - if(!cmpf) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ arrtype }, arrtype), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - fir::Value* arr = func->getArguments()[0]; - auto fn = makeRecursiveRefCountingFunction(cs, arr->getType()->toDynamicArrayType(), increment); - iceAssert(fn); - - cs->irb.Call(fn, arr); - - cs->irb.Return(arr); - - cs->irb.setCurrentBlock(restore); - cmpf = func; - } - - iceAssert(cmpf); - return cmpf; - } - - static fir::Function* _getDoRefCountFunctionForArray(CodegenState* cs, fir::ArrayType* arrtype, bool incr) - { - error("NO!"); - } - - - fir::Function* getIncrementArrayRefCountFunction(CodegenState* cs, fir::Type* arrtype) - { - if(arrtype->isDynamicArrayType()) return _getDoRefCountFunctionForDynamicArray(cs, arrtype->toDynamicArrayType(), true); - else return _getDoRefCountFunctionForArray(cs, arrtype->toArrayType(), true); - } - - fir::Function* getDecrementArrayRefCountFunction(CodegenState* cs, fir::Type* arrtype) - { - if(arrtype->isDynamicArrayType()) return _getDoRefCountFunctionForDynamicArray(cs, arrtype->toDynamicArrayType(), false); - else return _getDoRefCountFunctionForArray(cs, arrtype->toArrayType(), false); - } - - - - - - - - - - - - - fir::Function* getConstructFromTwoFunction(CodegenState* cs, fir::DynamicArrayType* arrtype) - { - return saa_common::generateConstructFromTwoFunction(cs, arrtype); - } - - - fir::Function* getPopElementFromBackFunction(CodegenState* cs, fir::Type* arrtype) - { - iceAssert(arrtype); - iceAssert(arrtype->isDynamicArrayType() || arrtype->isArraySliceType()); - - auto fname = misc::getPopBack_FName(arrtype); - fir::Function* fn = cs->module->getFunction(fname); - - if(!fn) - { - bool isslice = arrtype->isArraySliceType(); - - auto restore = cs->irb.getCurrentBlock(); - auto retTy = fir::TupleType::get({ arrtype, arrtype->getArrayElementType() }); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ arrtype, fir::Type::getCharSlice(false) }, retTy), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - - fir::Value* arr = func->getArguments()[0]; - fir::Value* loc = func->getArguments()[1]; - - fir::Value* origlen = (isslice ? cs->irb.GetArraySliceLength(arr) : cs->irb.GetSAALength(arr)); - - fir::IRBlock* fail = cs->irb.addNewBlockInFunction("fail", func); - fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); - - auto cond = cs->irb.ICmpLT(origlen, fir::ConstantInt::getNative(1)); - - cs->irb.CondBranch(cond, fail, merge); - cs->irb.setCurrentBlock(fail); - { - printRuntimeError(cs, loc, "calling pop() on an empty array\n", { }); - } - - - cs->irb.setCurrentBlock(merge); - { - auto newlen = cs->irb.Subtract(origlen, fir::ConstantInt::getNative(1)); - fir::Value* ret = 0; - - // first, load the last value - if(isslice) - { - auto ptr = cs->irb.GetArraySliceData(arr); - auto val = cs->irb.ReadPtr(cs->irb.GetPointer(ptr, newlen)); - - auto newarr = cs->irb.SetArraySliceLength(arr, newlen); - ret = cs->irb.CreateValue(retTy); - ret = cs->irb.InsertValue(ret, { 0 }, newarr); - ret = cs->irb.InsertValue(ret, { 1 }, val); - } - else - { - auto ptr = cs->irb.GetSAAData(arr); - auto val = cs->irb.ReadPtr(cs->irb.GetPointer(ptr, newlen)); - - auto newarr = cs->irb.SetSAALength(arr, newlen); - ret = cs->irb.CreateValue(retTy); - ret = cs->irb.InsertValue(ret, { 0 }, newarr); - ret = cs->irb.InsertValue(ret, { 1 }, val); - } - - iceAssert(ret); - cs->irb.Return(ret); - } - - - cs->irb.setCurrentBlock(restore); - fn = func; - } - - return fn; - } - - - - } } } diff --git a/source/codegen/glue/misc.cpp b/source/codegen/glue/misc.cpp index 87805d98..9712a13d 100644 --- a/source/codegen/glue/misc.cpp +++ b/source/codegen/glue/misc.cpp @@ -35,161 +35,6 @@ void printRuntimeError(cgn::CodegenState* cs, fir::Value* pos, const std::string namespace misc { - fir::Function* getMallocWrapperFunction(CodegenState* cs) - { - auto fname = getMallocWrapper_FName(); - fir::Function* fn = cs->module->getFunction(fname); - - if(!fn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ fir::Type::getNativeWord(), fir::Type::getCharSlice(false) }, fir::Type::getMutInt8Ptr()), - fir::LinkageType::Internal); - - func->setAlwaysInline(); - - auto sz = func->getArguments()[0]; - auto locstr = func->getArguments()[1]; - - auto entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - // do the alloc. - auto mallocf = cs->getOrDeclareLibCFunction(ALLOCATE_MEMORY_FUNC); - iceAssert(mallocf); - - auto mem = cs->irb.Call(mallocf, sz); - auto cond = cs->irb.ICmpEQ(mem, fir::ConstantValue::getZeroValue(fir::Type::getInt8Ptr())); - - auto alloc_succ = cs->irb.addNewBlockAfter("success", cs->irb.getCurrentBlock()); - auto alloc_fail = cs->irb.addNewBlockAfter("failure", cs->irb.getCurrentBlock()); - - cs->irb.CondBranch(cond, alloc_fail, alloc_succ); - cs->irb.setCurrentBlock(alloc_succ); - { - cs->irb.Return(mem); - } - - cs->irb.setCurrentBlock(alloc_fail); - { - printRuntimeError(cs, locstr, "allocation failed (returned null) (tried to allocate %d bytes)", { sz }); - - // it emits an unreachable for us. - } - - fn = func; - cs->irb.setCurrentBlock(restore); - } - - iceAssert(fn); - return fn; - } - - fir::Function* getRangeSanityCheckFunction(CodegenState* cs) - { - if(frontend::getIsNoRuntimeChecks()) - return 0; - - auto fname = getRangeSanityCheck_FName(); - fir::Function* fn = cs->module->getFunction(fname); - - if(!fn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ fir::Type::getRange(), fir::Type::getCharSlice(false) }, fir::Type::getVoid()), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - /* - Valid scenarios: - - 1. start <= end, step > 0 - 2. start >= end, step < 0 - */ - auto entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - auto check = cs->irb.addNewBlockAfter("check", cs->irb.getCurrentBlock()); - - auto checkstepneg = cs->irb.addNewBlockAfter("checkstepneg", cs->irb.getCurrentBlock()); - auto checksteppos = cs->irb.addNewBlockAfter("checksteppos", cs->irb.getCurrentBlock()); - - auto stepnotneg = cs->irb.addNewBlockAfter("fail_stepnotneg", cs->irb.getCurrentBlock()); - auto stepnotpos = cs->irb.addNewBlockAfter("fail_stepnotpos", cs->irb.getCurrentBlock()); - auto stepzero = cs->irb.addNewBlockAfter("fail_stepzero", cs->irb.getCurrentBlock()); - - auto merge = cs->irb.addNewBlockAfter("merge", cs->irb.getCurrentBlock()); - - - auto lower = cs->irb.GetRangeLower(func->getArguments()[0]); - auto upper = cs->irb.GetRangeUpper(func->getArguments()[0]); - auto step = cs->irb.GetRangeStep(func->getArguments()[0]); - - auto zero = fir::ConstantInt::getNative(0); - // first of all check if step is zero. - { - auto cond = cs->irb.ICmpEQ(step, zero); - cs->irb.CondBranch(cond, stepzero, check); - } - - - // first, check if start <= end. - cs->irb.setCurrentBlock(check); - { - auto cond = cs->irb.ICmpLEQ(lower, upper); - - // if start < end, check step > 0. else check step < 0. - cs->irb.CondBranch(cond, checksteppos, checkstepneg); - } - - cs->irb.setCurrentBlock(checksteppos); - { - auto cond = cs->irb.ICmpGT(step, zero); - cs->irb.CondBranch(cond, merge, stepnotpos); - } - - cs->irb.setCurrentBlock(checkstepneg); - { - auto cond = cs->irb.ICmpLT(step, zero); - cs->irb.CondBranch(cond, merge, stepnotneg); - } - - - // ok, now the failure messages. - { - cs->irb.setCurrentBlock(stepzero); - { - printRuntimeError(cs, func->getArguments()[1], "range step had value of zero\n", { }); - } - - cs->irb.setCurrentBlock(stepnotpos); - { - printRuntimeError(cs, func->getArguments()[1], "range had negative step value ('%ld'); invalid when start < end\n", { step }); - } - - cs->irb.setCurrentBlock(stepnotneg); - { - printRuntimeError(cs, func->getArguments()[1], "range had positive step value ('%ld'); invalid when start > end\n", { step }); - } - } - - cs->irb.setCurrentBlock(merge); - cs->irb.ReturnVoid(); - - fn = func; - cs->irb.setCurrentBlock(restore); - } - - iceAssert(fn); - return fn; - } - - - using Idt = fir::Name; Idt getOI(const std::string& name, fir::Type* t = 0) { @@ -198,37 +43,6 @@ namespace misc } Idt getCompare_FName(fir::Type* t) { return getOI("compare", t); } - Idt getSetElements_FName(fir::Type* t) { return getOI("setelements", t); } - Idt getCallClassConstructor_FName(fir::Type* t) { return getOI("callclassinit", t); } - Idt getSetElementsDefault_FName(fir::Type* t) { return getOI("setelementsdefault", t); } - - Idt getClone_FName(fir::Type* t) { return getOI("clone", t); } - Idt getAppend_FName(fir::Type* t) { return getOI("append", t); } - Idt getPopBack_FName(fir::Type* t) { return getOI("popback", t); } - Idt getMakeFromOne_FName(fir::Type* t) { return getOI("makefromone", t); } - Idt getMakeFromTwo_FName(fir::Type* t) { return getOI("makefromtwo", t); } - Idt getReserveExtra_FName(fir::Type* t) { return getOI("reserveextra", t); } - Idt getAppendElement_FName(fir::Type* t) { return getOI("appendelement", t); } - Idt getReserveEnough_FName(fir::Type* t) { return getOI("reservesufficient", t); } - Idt getRecursiveRefcount_FName(fir::Type* t, bool incr) - { - return getOI(strprintf("rrc_%s", incr ? "incr" : "decr"), t); - } - - Idt getIncrRefcount_FName(fir::Type* t) { return getOI("incr_rc", t); } - Idt getDecrRefcount_FName(fir::Type* t) { return getOI("decr_rc", t); } - Idt getLoopIncrRefcount_FName(fir::Type* t) { return getOI("loop_incr_rc", t); } - Idt getLoopDecrRefcount_FName(fir::Type* t) { return getOI("loop_decr_rc", t); } - - Idt getCreateAnyOf_FName(fir::Type* t) { return getOI("create_any_of", t); } - Idt getGetValueFromAny_FName(fir::Type* t) { return getOI("get_value_from_any", t); } - - Idt getUtf8Length_FName() { return getOI("utf8_length"); } - Idt getRangeSanityCheck_FName() { return getOI("range_sanity"); } - Idt getMallocWrapper_FName() { return getOI("malloc_wrapper"); } - Idt getBoundsCheck_FName() { return getOI("boundscheck"); } - Idt getDecompBoundsCheck_FName() { return getOI("boundscheck_decomp"); } - } } } diff --git a/source/codegen/glue/saa_common.cpp b/source/codegen/glue/saa_common.cpp deleted file mode 100644 index 57b3638c..00000000 --- a/source/codegen/glue/saa_common.cpp +++ /dev/null @@ -1,876 +0,0 @@ -// saa_common.cpp -// Copyright (c) 2017, zhiayang -// Licensed under the Apache License Version 2.0. - - -#include "codegen.h" -#include "platform.h" -#include "gluecode.h" -#include "frontend.h" - -// namespace cgn::glue::saa_common -namespace cgn { -namespace glue { -namespace saa_common -{ - static inline bool isSAA(fir::Type* t) { return t->isStringType() || t->isDynamicArrayType(); } - static inline fir::Type* getSAAElm(fir::Type* t) { iceAssert(isSAA(t)); return (t->isStringType() ? fir::Type::getInt8() : t->getArrayElementType()); } - static inline fir::Type* getSAASlice(fir::Type* t, bool mut = true) { iceAssert(isSAA(t)); return fir::ArraySliceType::get(getSAAElm(t), mut); } - static inline fir::ConstantInt* getCI(int64_t i) { return fir::ConstantInt::getNative(i); } - - static fir::Value* castRawBufToElmPtr(CodegenState* cs, fir::Type* saa, fir::Value* buf) - { - auto ptrty = getSAAElm(saa)->getMutablePointerTo(); - - if(buf->getType()->isPointerType()) - return cs->irb.PointerTypeCast(buf, ptrty); - - else - return cs->irb.IntToPointerCast(buf, ptrty); - } - - static fir::Function* generateIncrementArrayRefCountInLoopFunction(CodegenState* cs, fir::Type* elm) - { - iceAssert(fir::isRefCountedType(elm)); - - auto fname = misc::getLoopIncrRefcount_FName(elm); - fir::Function* retfn = cs->module->getFunction(fname); - - if(!retfn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ elm->getPointerTo(), fir::Type::getNativeWord() }, fir::Type::getVoid()), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - fir::IRBlock* cond = cs->irb.addNewBlockInFunction("loopCond", func); - fir::IRBlock* body = cs->irb.addNewBlockInFunction("loopBody", func); - fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); - - fir::Value* ctrPtr = cs->irb.StackAlloc(fir::Type::getNativeWord()); - - - fir::Value* s2ptr = func->getArguments()[0]; - fir::Value* s2len = func->getArguments()[1]; - - cs->irb.UnCondBranch(cond); - cs->irb.setCurrentBlock(cond); - { - // check the condition - fir::Value* ctr = cs->irb.ReadPtr(ctrPtr); - fir::Value* res = cs->irb.ICmpLT(ctr, s2len); - - cs->irb.CondBranch(res, body, merge); - } - - cs->irb.setCurrentBlock(body); - { - // increment refcount - fir::Value* val = cs->irb.ReadPtr(cs->irb.GetPointer(s2ptr, cs->irb.ReadPtr(ctrPtr))); - - cs->incrementRefCount(val); - - // increment counter - cs->irb.WritePtr(cs->irb.Add(fir::ConstantInt::getNative(1), cs->irb.ReadPtr(ctrPtr)), ctrPtr); - cs->irb.UnCondBranch(cond); - } - - cs->irb.setCurrentBlock(merge); - cs->irb.ReturnVoid(); - - - cs->irb.setCurrentBlock(restore); - retfn = func; - } - - iceAssert(retfn); - return retfn; - } - - fir::Value* makeNewRefCountPointer(CodegenState* cs, fir::Value* rc) - { - iceAssert(rc->getType()->isIntegerType() && "not integer type"); - - auto rcp = cs->irb.Call(cs->getOrDeclareLibCFunction(ALLOCATE_MEMORY_FUNC), getCI(REFCOUNT_SIZE)); - rcp = cs->irb.PointerTypeCast(rcp, fir::Type::getNativeWordPtr()->getMutablePointerVersion()); - - cs->irb.WritePtr(rc, rcp); - return cs->irb.PointerTypeCast(rcp, fir::Type::getNativeWordPtr()); - } - - fir::Value* initSAAWithRefCount(CodegenState* cs, fir::Value* saa, fir::Value* rc) - { - iceAssert(isSAA(saa->getType()) && "not saa type"); - iceAssert(rc->getType()->isIntegerType() && "not integer type"); - - auto rcp = makeNewRefCountPointer(cs, rc); - return cs->irb.SetSAARefCountPointer(saa, rcp); - } - - - - - - - - /* - * NOTE * - - since we're changing strings and dynamic arrays to behave much the same way, why not just collapse the runtime gluecode as much - as possible. - - we're going with the { ptr, len, cap, rcp } structure for both types, and so we can do a lot of things commonly. one thing is that - we still want null terminators on strings, so that's just a couple of if-checks sprinkled around -- nothing too obnoxious. - */ - - - static void _callCloneFunctionInLoop(CodegenState* cs, fir::Function* curfunc, fir::Function* fn, - fir::Value* ptr, fir::Value* len, fir::Value* newptr, fir::Value* startIndex) - { - fir::IRBlock* loopcond = cs->irb.addNewBlockInFunction("loopcond", curfunc); - fir::IRBlock* loopbody = cs->irb.addNewBlockInFunction("loopbody", curfunc); - fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", curfunc); - - fir::Value* counter = cs->irb.StackAlloc(fir::Type::getNativeWord()); - cs->irb.WritePtr(startIndex, counter); - - cs->irb.UnCondBranch(loopcond); - cs->irb.setCurrentBlock(loopcond); - { - fir::Value* res = cs->irb.ICmpEQ(cs->irb.ReadPtr(counter), len); - cs->irb.CondBranch(res, merge, loopbody); - } - - cs->irb.setCurrentBlock(loopbody); - { - // make clone - fir::Value* origElm = cs->irb.GetPointer(ptr, cs->irb.ReadPtr(counter)); - fir::Value* clone = 0; - - //* note: the '0' argument specifies the offset to clone from -- since want the whole thing, the offset is 0. - auto elm = cs->irb.ReadPtr(origElm); - - clone = cs->irb.Call(fn, isSAA(elm->getType()) ? cs->irb.CreateSliceFromSAA(elm, false) : elm, fir::ConstantInt::getNative(0)); - - // store clone - fir::Value* newElm = cs->irb.GetPointer(newptr, cs->irb.ReadPtr(counter)); - cs->irb.WritePtr(clone, newElm); - - // increment counter - cs->irb.WritePtr(cs->irb.Add(cs->irb.ReadPtr(counter), fir::ConstantInt::getNative(1)), counter); - cs->irb.UnCondBranch(loopcond); - } - - cs->irb.setCurrentBlock(merge); - } - - static void _handleCallingAppropriateCloneFunction(CodegenState* cs, fir::Function* func, fir::Type* elmType, fir::Value* oldptr, - fir::Value* newptr, fir::Value* oldlen, fir::Value* bytecount, fir::Value* startIndex) - { - if(elmType->isPrimitiveType() || elmType->isCharType() || elmType->isEnumType()) - { - fir::Function* memcpyf = cs->module->getIntrinsicFunction("memmove"); - - cs->irb.Call(memcpyf, { newptr, cs->irb.PointerTypeCast(cs->irb.GetPointer(oldptr, - startIndex), fir::Type::getMutInt8Ptr()), bytecount, fir::ConstantBool::get(false) }); - - #if DEBUG_ARRAY_ALLOCATION | DEBUG_STRING_ALLOCATION - { - cs->printIRDebugMessage("* SAACOM: clone(): (oldptr: %p, oldlen: %d), (newptr: %p, bytecount: %d, index: %d)", { - oldptr, oldlen, newptr, bytecount, startIndex }); - } - #endif - - } - else if(elmType->isDynamicArrayType()) - { - // yo dawg i heard you like arrays... - fir::Function* clonef = generateCloneFunction(cs, elmType); - iceAssert(clonef); - - // loop - fir::Value* cloneptr = cs->irb.PointerTypeCast(newptr, elmType->getMutablePointerTo()); - _callCloneFunctionInLoop(cs, func, clonef, oldptr, oldlen, cloneptr, startIndex); - } - else if(elmType->isArraySliceType()) - { - // yo dawg i heard you like arrays... - fir::Function* clonef = generateCloneFunction(cs, elmType); - iceAssert(clonef); - - // loop - fir::Value* cloneptr = cs->irb.PointerTypeCast(newptr, elmType->getMutablePointerTo()); - _callCloneFunctionInLoop(cs, func, clonef, oldptr, oldlen, cloneptr, startIndex); - } - else if(elmType->isStringType()) - { - fir::Function* clonef = glue::string::getCloneFunction(cs); - iceAssert(clonef); - - // loop - fir::Value* cloneptr = cs->irb.PointerTypeCast(newptr, elmType->getMutablePointerTo()); - _callCloneFunctionInLoop(cs, func, clonef, oldptr, oldlen, cloneptr, startIndex); - } - else if(elmType->isStructType() || elmType->isClassType() || elmType->isTupleType() || elmType->isArrayType()) - { - // todo: call copy constructors and stuff - - fir::Function* memcpyf = cs->module->getIntrinsicFunction("memmove"); - - cs->irb.Call(memcpyf, { newptr, cs->irb.PointerTypeCast(cs->irb.GetPointer(oldptr, - startIndex), fir::Type::getMutInt8Ptr()), bytecount, fir::ConstantBool::get(false) }); - } - else - { - error("unsupported element type '%s' for array clone", elmType); - } - } - - - - - - - fir::Function* generateCloneFunction(CodegenState* cs, fir::Type* _saa) - { - auto fname = misc::getClone_FName(_saa); - - iceAssert(isSAA(_saa) || _saa->isArraySliceType()); - auto slicetype = (isSAA(_saa) ? getSAASlice(_saa, false) : fir::ArraySliceType::get(_saa->getArrayElementType(), false)); - - iceAssert(slicetype->isArraySliceType()); - bool isArray = !_saa->isStringType(); - - fir::Type* outtype = (isSAA(_saa) ? _saa : fir::DynamicArrayType::get(slicetype->getArrayElementType())); - - fir::Function* retfn = cs->module->getFunction(fname); - - if(!retfn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ slicetype, fir::Type::getNativeWord() }, outtype), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - auto s1 = func->getArguments()[0]; - auto cloneofs = func->getArguments()[1]; - - auto lhsbuf = cs->irb.GetArraySliceData(s1, "lhsbuf"); - - fir::IRBlock* isnull = cs->irb.addNewBlockInFunction("isnull", func); - fir::IRBlock* notnull = cs->irb.addNewBlockInFunction("notnull", func); - - // if it's null we just fuck off now. - cs->irb.CondBranch(cs->irb.ICmpEQ(lhsbuf, fir::ConstantValue::getZeroValue(slicetype->getArrayElementType()->getPointerTo())), - isnull, notnull); - - cs->irb.setCurrentBlock(notnull); - { - auto lhslen = cs->irb.Subtract(cs->irb.GetArraySliceLength(s1, "l1"), cloneofs, "lhslen"); - auto newcap = cs->irb.Call(cs->module->getIntrinsicFunction("roundup_pow2"), lhslen, "newcap"); - - auto lhsbytecount = cs->irb.Multiply(lhslen, cs->irb.Sizeof(slicetype->getArrayElementType()), "lhsbytecount"); - auto newbytecount = cs->irb.Multiply(newcap, cs->irb.Sizeof(slicetype->getArrayElementType()), "newbytecount"); - - fir::Value* newbuf = cs->irb.Call(cgn::glue::misc::getMallocWrapperFunction(cs), - !isArray ? cs->irb.Add(newbytecount, getCI(1)) : newbytecount, fir::ConstantCharSlice::get("(no location)"), "buf"); - { - // fir::Function* memcpyf = cs->module->getIntrinsicFunction("memmove"); - // cs->irb.Call(memcpyf, { buf, castRawBufToElmPtr(cs, saa, lhsbuf), lhsbytecount, - // fir::ConstantInt::getInt32(0), fir::ConstantBool::get(false) }); - - _handleCallingAppropriateCloneFunction(cs, func, slicetype->getArrayElementType(), lhsbuf, - newbuf, lhslen, lhsbytecount, cloneofs); - - // null terminator - if(!isArray) - cs->irb.WritePtr(fir::ConstantInt::getInt8(0), cs->irb.GetPointer(newbuf, lhsbytecount)); - } - - - { - auto ret = cs->irb.CreateValue(outtype); - ret = cs->irb.SetSAAData(ret, castRawBufToElmPtr(cs, outtype, newbuf)); - ret = cs->irb.SetSAALength(ret, lhslen); //? vv for the null terminator - ret = cs->irb.SetSAACapacity(ret, !isArray ? cs->irb.Subtract(newcap, getCI(1)) : newcap); - ret = initSAAWithRefCount(cs, ret, getCI(1)); - - cs->irb.Return(ret); - } - } - - cs->irb.setCurrentBlock(isnull); - { - auto ret = cs->irb.CreateValue(outtype); - ret = cs->irb.SetSAAData(ret, castRawBufToElmPtr(cs, outtype, getCI(0))); - ret = cs->irb.SetSAALength(ret, getCI(0)); - ret = cs->irb.SetSAACapacity(ret, getCI(0)); - ret = initSAAWithRefCount(cs, ret, getCI(1)); - - cs->irb.Return(ret); - } - - retfn = func; - cs->irb.setCurrentBlock(restore); - } - - iceAssert(retfn); - return retfn; - } - - - fir::Function* generateAppropriateAppendFunction(CodegenState* cs, fir::Type* saa, fir::Type* appendee) - { - iceAssert(isSAA(saa)); - if(appendee == getSAAElm(saa)) - return generateElementAppendFunction(cs, saa); - - else if(zfu::match(appendee, getSAASlice(saa), getSAASlice(saa, false), saa)) - return generateAppendFunction(cs, saa); - - else - error(cs->loc(), "cannot append '%s' to '%s'", appendee, saa); - } - - - fir::Function* generateAppendFunction(CodegenState* cs, fir::Type* saa) - { - auto fname = misc::getAppend_FName(saa); - - iceAssert(isSAA(saa)); - fir::Function* retfn = cs->module->getFunction(fname); - - if(!retfn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ saa, getSAASlice(saa, false) }, saa), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - fir::Value* lhs = func->getArguments()[0]; - fir::Value* rhs = func->getArguments()[1]; - - auto lhslen = cs->irb.GetSAALength(lhs, "lhslen"); - - auto rhsbuf = cs->irb.GetArraySliceData(rhs, "rhsbuf"); - auto rhslen = cs->irb.GetArraySliceLength(rhs, "rhslen"); - auto rhsbytecount = cs->irb.Multiply(rhslen, cs->irb.Sizeof(rhs->getType()->getArrayElementType()), "rhsbytecount"); - - // this handles the null case as well. - lhs = cs->irb.Call(generateReserveAtLeastFunction(cs, saa), lhs, cs->irb.Add(lhslen, rhslen)); - auto lhsbuf = cs->irb.GetSAAData(lhs, "lhsbuf"); - - // do a copy over the rhs. - { - fir::Function* memcpyf = cs->module->getIntrinsicFunction("memmove"); - cs->irb.Call(memcpyf, { - cs->irb.PointerTypeCast(cs->irb.GetPointer(lhsbuf, lhslen), fir::Type::getMutInt8Ptr()), - cs->irb.PointerTypeCast(rhsbuf, fir::Type::getMutInt8Ptr()), rhsbytecount, - fir::ConstantBool::get(false) - }); - - // null terminator - if(saa->isStringType()) - { - cs->irb.WritePtr(fir::ConstantInt::getInt8(0), cs->irb.PointerTypeCast(cs->irb.GetPointer(lhsbuf, cs->irb.Add(lhslen, rhslen)), - fir::Type::getMutInt8Ptr())); - } - } - - lhs = cs->irb.SetSAALength(lhs, cs->irb.Add(lhslen, rhslen)); - - // handle refcounting - if(fir::isRefCountedType(getSAAElm(saa))) - { - auto incrfn = generateIncrementArrayRefCountInLoopFunction(cs, getSAAElm(saa)); - iceAssert(incrfn); - - cs->irb.Call(incrfn, rhsbuf, rhslen); - } - - cs->irb.Return(lhs); - - - cs->irb.setCurrentBlock(restore); - retfn = func; - } - - iceAssert(retfn); - return retfn; - } - - - fir::Function* generateElementAppendFunction(CodegenState* cs, fir::Type* saa) - { - auto fname = misc::getAppendElement_FName(saa); - - iceAssert(isSAA(saa)); - fir::Function* retfn = cs->module->getFunction(fname); - - if(!retfn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ saa, getSAAElm(saa) }, saa), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - fir::Value* lhs = func->getArguments()[0]; - fir::Value* rhs = func->getArguments()[1]; - - auto rhsp = cs->irb.ImmutStackAlloc(getSAAElm(saa), rhs, "rhsptr"); - - auto rhsslice = cs->irb.CreateValue(getSAASlice(saa), "rhsslice"); - rhsslice = cs->irb.SetArraySliceData(rhsslice, cs->irb.PointerTypeCast(rhsp, rhsp->getType()->getMutablePointerVersion())); - rhsslice = cs->irb.SetArraySliceLength(rhsslice, getCI(1)); - - auto appf = generateAppendFunction(cs, saa); - iceAssert(appf); - - auto ret = cs->irb.Call(appf, lhs, rhsslice); - cs->irb.Return(ret); - - cs->irb.setCurrentBlock(restore); - retfn = func; - } - - iceAssert(retfn); - return retfn; - } - - - - - fir::Function* generateConstructFromTwoFunction(CodegenState* cs, fir::Type* saa) - { - auto fname = misc::getMakeFromTwo_FName(saa); - - iceAssert(isSAA(saa)); - fir::Function* retfn = cs->module->getFunction(fname); - - if(!retfn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ getSAASlice(saa, false), getSAASlice(saa, false) }, saa), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - fir::Value* lhs = func->getArguments()[0]; - fir::Value* rhs = func->getArguments()[1]; - - auto lhslen = cs->irb.GetArraySliceLength(lhs, "lhslen"); - auto rhslen = cs->irb.GetArraySliceLength(rhs, "rhslen"); - - auto lhsbuf = cs->irb.GetArraySliceData(lhs, "lhsbuf"); - auto rhsbuf = cs->irb.GetArraySliceData(rhs, "rhsbuf"); - - // step 1 -- make a null of the SAA - auto ret = cs->irb.CreateValue(saa); - ret = cs->irb.SetSAAData(ret, castRawBufToElmPtr(cs, saa, getCI(0))); - ret = cs->irb.SetSAALength(ret, getCI(0)); - ret = cs->irb.SetSAACapacity(ret, getCI(0)); //? vv we count on the 'reserveAtLeast' function to init our refcount - ret = cs->irb.SetSAARefCountPointer(ret, fir::ConstantValue::getZeroValue(fir::Type::getNativeWordPtr())); - - - ret = cs->irb.Call(generateReserveAtLeastFunction(cs, saa), ret, cs->irb.Add(cs->irb.Add(lhslen, rhslen), - saa->isStringType() ? getCI(1) : getCI(0))); - - - #if DEBUG_ARRAY_ALLOCATION | DEBUG_STRING_ALLOCATION - { - cs->printIRDebugMessage("* SAACOM: construct2(): (ptr: %p, len: %d) + (ptr: %p, len: %d) = %p", { - lhsbuf, lhslen, rhsbuf, rhslen, cs->irb.GetSAAData(ret) }); - } - #endif - - - auto buf = cs->irb.GetSAAData(ret, "buf"); - { - fir::Function* memcpyf = cs->module->getIntrinsicFunction("memmove"); - - auto rawbuf = cs->irb.PointerTypeCast(buf, fir::Type::getMutInt8Ptr(), "rawbuf"); - auto rawlhsbuf = cs->irb.PointerTypeCast(lhsbuf, fir::Type::getMutInt8Ptr(), "rawlhsbuf"); - auto rawrhsbuf = cs->irb.PointerTypeCast(rhsbuf, fir::Type::getMutInt8Ptr(), "rawrhsbuf"); - - auto lhsbytecount = cs->irb.Multiply(lhslen, cs->irb.Sizeof(getSAAElm(saa)), "lhsbytecount"); - auto rhsbytecount = cs->irb.Multiply(rhslen, cs->irb.Sizeof(getSAAElm(saa)), "rhsbytecount"); - - cs->irb.Call(memcpyf, { rawbuf, rawlhsbuf, - lhsbytecount, fir::ConstantBool::get(false) - }); - - cs->irb.Call(memcpyf, { cs->irb.GetPointer(rawbuf, lhsbytecount), rawrhsbuf, - rhsbytecount, fir::ConstantBool::get(false) - }); - - // if it's a string, again, null terminator. - if(saa->isStringType()) - { - cs->irb.WritePtr(fir::ConstantInt::getInt8(0), cs->irb.GetPointer(rawbuf, cs->irb.Add(lhsbytecount, rhsbytecount))); - } - else if(fir::isRefCountedType(getSAAElm(saa))) - { - auto incrfn = generateIncrementArrayRefCountInLoopFunction(cs, getSAAElm(saa)); - iceAssert(incrfn); - - cs->irb.Call(incrfn, lhsbuf, lhslen); - cs->irb.Call(incrfn, rhsbuf, rhslen); - } - - ret = cs->irb.SetSAALength(ret, cs->irb.Add(lhslen, rhslen)); - cs->irb.Return(ret); - } - - - cs->irb.setCurrentBlock(restore); - retfn = func; - } - - iceAssert(retfn); - return retfn; - } - - - - fir::Function* generateConstructWithElementFunction(CodegenState* cs, fir::Type* saa) - { - auto fname = misc::getMakeFromOne_FName(saa); - - iceAssert(isSAA(saa)); - fir::Function* retfn = cs->module->getFunction(fname); - - if(!retfn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ getSAASlice(saa), getSAAElm(saa) }, saa), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - fir::Value* lhs = func->getArguments()[0]; - fir::Value* rhs = func->getArguments()[1]; - - auto rhsslice = cs->irb.CreateValue(getSAASlice(saa, /* mut: */ false), "rhsslice"); - rhsslice = cs->irb.SetArraySliceData(rhsslice, cs->irb.ImmutStackAlloc(getSAAElm(saa), rhs, "rhsptr")); - rhsslice = cs->irb.SetArraySliceLength(rhsslice, getCI(1)); - - auto appf = generateConstructFromTwoFunction(cs, saa); - iceAssert(appf); - - auto ret = cs->irb.Call(appf, lhs, rhsslice); - cs->irb.Return(ret); - - cs->irb.setCurrentBlock(restore); - retfn = func; - } - - iceAssert(retfn); - return retfn; - } - - - - - - - - - // TODO: this shit is bloody unmaintainable - fir::Function* generateReserveAtLeastFunction(CodegenState* cs, fir::Type* saa) - { - auto fname = misc::getReserveEnough_FName(saa); - - iceAssert(isSAA(saa)); - fir::Function* retfn = cs->module->getFunction(fname); - - if(!retfn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ saa, fir::Type::getNativeWord() }, saa), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - - auto s1 = func->getArguments()[0]; - auto minsz = func->getArguments()[1]; - - auto oldlen = cs->irb.GetSAALength(s1, "oldlen"); - auto oldcap = cs->irb.GetSAACapacity(s1, "oldcap"); - - fir::IRBlock* nullrc = cs->irb.addNewBlockInFunction("nullrc", func); - fir::IRBlock* notnullrc = cs->irb.addNewBlockInFunction("notnullrc", func); - fir::IRBlock* mergerc = cs->irb.addNewBlockInFunction("mergerc", func); - - auto oldrcp = cs->irb.GetSAARefCountPointer(s1, "oldrcp"); - cs->irb.CondBranch(cs->irb.ICmpEQ(oldrcp, cs->irb.IntToPointerCast(getCI(0), fir::Type::getNativeWordPtr())), nullrc, notnullrc); - - - //? these phi nodes are for the refcount pointer of the thing we will eventually return. - fir::Value* nullphi = 0; - fir::Value* notnullphi = 0; - - cs->irb.setCurrentBlock(nullrc); - { - nullphi = makeNewRefCountPointer(cs, getCI(1)); - cs->irb.UnCondBranch(mergerc); - } - - cs->irb.setCurrentBlock(notnullrc); - { - notnullphi = cs->irb.GetSAARefCountPointer(s1, "oldref"); - cs->irb.UnCondBranch(mergerc); - } - - - cs->irb.setCurrentBlock(mergerc); - { - auto rcptr = cs->irb.CreatePHINode(fir::Type::getNativeWordPtr()); - rcptr->addIncoming(nullphi, nullrc); - rcptr->addIncoming(notnullphi, notnullrc); - - fir::IRBlock* returnUntouched = cs->irb.addNewBlockInFunction("noExpansion", func); - fir::IRBlock* doExpansion = cs->irb.addNewBlockInFunction("expand", func); - - cs->irb.CondBranch(cs->irb.ICmpLEQ(minsz, oldcap), returnUntouched, doExpansion); - - - cs->irb.setCurrentBlock(doExpansion); - { - auto newlen = cs->irb.Divide(cs->irb.Multiply(minsz, getCI(3)), getCI(2), "mul1.5"); - - // call realloc. handles the null case as well, which is nice. - const auto oldbuf = cs->irb.PointerTypeCast(cs->irb.GetSAAData(s1), fir::Type::getMutInt8Ptr(), "oldbuf"); - - auto newbytecount = cs->irb.Multiply(newlen, cs->irb.Sizeof(getSAAElm(saa)), "newbytecount"); - - if(saa->isStringType()) - newbytecount = cs->irb.Add(newbytecount, getCI(1)); - - // if the capacity was negative, then the buffer points to constant memory that did not come from the heap!! - // so, we cannot call realloc with oldbuf, and call it with NULL instead. also for strings, capacity of 0 is empty - // so we do the same dealio. - auto isfake = cs->irb.ICmpLEQ(oldcap, getCI(0)); - auto origbuf = cs->irb.Select(isfake, fir::ConstantValue::getZeroValue(fir::Type::getMutInt8Ptr()), oldbuf); - - auto _newbuf = cs->irb.Call(cs->getOrDeclareLibCFunction(REALLOCATE_MEMORY_FUNC), origbuf, newbytecount, "newbuf"); - auto newbuf = castRawBufToElmPtr(cs, saa, _newbuf); - - - // again with the NULL thingy: now we need to (possibly) copy the data from the old buffer to the new buffer - // bopian need some branching here. - { - auto needcopy = cs->irb.addNewBlockInFunction("copyold", func); - auto nocopy = cs->irb.addNewBlockInFunction("nocopyold", func); - - cs->irb.CondBranch(isfake, needcopy, nocopy); - cs->irb.setCurrentBlock(needcopy); - { - cs->irb.Call(cs->module->getIntrinsicFunction("memmove"), _newbuf, oldbuf, cs->irb.Multiply(oldlen, - cs->irb.Sizeof(getSAAElm(saa))), /* isVolatile: */ fir::ConstantBool::get(false)); - cs->irb.UnCondBranch(nocopy); - } - - cs->irb.setCurrentBlock(nocopy); - } - - // null terminator - if(saa->isStringType()) - cs->irb.WritePtr(fir::ConstantInt::getInt8(0), cs->irb.GetPointer(newbuf, cs->irb.Subtract(newbytecount, getCI(1)))); - - - auto ret = cs->irb.CreateValue(saa); - ret = cs->irb.SetSAAData(ret, newbuf); - ret = cs->irb.SetSAALength(ret, oldlen); - ret = cs->irb.SetSAACapacity(ret, newlen); - ret = cs->irb.SetSAARefCountPointer(ret, rcptr); - - #if DEBUG_ARRAY_ALLOCATION | DEBUG_STRING_ALLOCATION - { - cs->printIRDebugMessage("* SAACOM: realloc(): (ptr: %p, cap: %d / rcp: %p)", { - newbuf, newlen, cs->irb.GetSAARefCountPointer(ret) }); - } - #endif - - cs->irb.Return(ret); - } - - cs->irb.setCurrentBlock(returnUntouched); - { - // as the name implies, do nothing. - cs->irb.Return(s1); - } - } - - cs->irb.setCurrentBlock(restore); - retfn = func; - } - - iceAssert(retfn); - return retfn; - } - - - fir::Function* generateReserveExtraFunction(CodegenState* cs, fir::Type* saa) - { - // we can just do this in terms of reserveAtLeast. - - auto fname = misc::getReserveExtra_FName(saa); - - iceAssert(isSAA(saa)); - fir::Function* retfn = cs->module->getFunction(fname); - - if(!retfn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ saa, fir::Type::getNativeWord() }, saa), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - auto s1 = func->getArguments()[0]; - auto extrasz = func->getArguments()[1]; - - auto minsz = cs->irb.Add(cs->irb.GetSAACapacity(s1), extrasz); - auto ret = cs->irb.Call(generateReserveAtLeastFunction(cs, saa), s1, minsz); - - cs->irb.Return(ret); - - cs->irb.setCurrentBlock(restore); - retfn = func; - } - - iceAssert(retfn); - return retfn; - } - - - - fir::Function* generateBoundsCheckFunction(CodegenState* cs, bool isString, bool isDecomp) - { - if(frontend::getIsNoRuntimeChecks()) - return 0; - - auto fname = (isDecomp ? misc::getDecompBoundsCheck_FName() : misc::getBoundsCheck_FName()); - fir::Function* retfn = cs->module->getFunction(fname); - - if(!retfn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ fir::Type::getNativeWord(), fir::Type::getNativeWord(), fir::Type::getCharSlice(false) }, - fir::Type::getVoid()), fir::LinkageType::Internal); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - fir::IRBlock* failb = cs->irb.addNewBlockInFunction("fail", func); - fir::IRBlock* checkneg = cs->irb.addNewBlockInFunction("checkneg", func); - fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); - - cs->irb.setCurrentBlock(entry); - - fir::Value* max = func->getArguments()[0]; - fir::Value* ind = func->getArguments()[1]; - fir::Value* res = 0; - - // if we're decomposing, it's length vs length, so compare strictly greater. - if(isDecomp) res = cs->irb.ICmpGT(ind, max); - else res = cs->irb.ICmpGEQ(ind, max); - - - cs->irb.CondBranch(res, failb, checkneg); - cs->irb.setCurrentBlock(failb); - { - if(isDecomp) - { - printRuntimeError(cs, func->getArguments()[2], "index '%ld' out of bounds for " - + std::string(isString ? "string" : "array") + " of length %ld\n", { ind, max }); - } - else - { - printRuntimeError(cs, func->getArguments()[2], "binding of '%ld' " - + std::string(isString ? "chars" : "elements") + " out of bounds for string of length %ld\n", { ind, max }); - } - } - - cs->irb.setCurrentBlock(checkneg); - { - fir::Value* res = cs->irb.ICmpLT(ind, fir::ConstantInt::getNative(0)); - cs->irb.CondBranch(res, failb, merge); - } - - cs->irb.setCurrentBlock(merge); - { - cs->irb.ReturnVoid(); - } - - retfn = func; - cs->irb.setCurrentBlock(restore); - } - - iceAssert(retfn); - return retfn; - } - -} -} -} - - - - - - - - - - - - - - - - - - - - - - - diff --git a/source/codegen/glue/strings.cpp b/source/codegen/glue/strings.cpp deleted file mode 100644 index 5f0e8ea7..00000000 --- a/source/codegen/glue/strings.cpp +++ /dev/null @@ -1,376 +0,0 @@ -// strings.cpp -// Copyright (c) 2014 - 2017, zhiayang -// Licensed under the Apache License Version 2.0. - -#include "codegen.h" -#include "platform.h" -#include "gluecode.h" - -// generate runtime glue code - -namespace cgn { -namespace glue { -namespace string -{ - fir::Function* getCloneFunction(CodegenState* cs) - { - return saa_common::generateCloneFunction(cs, fir::Type::getString()); - } - - fir::Function* getAppendFunction(CodegenState* cs) - { - return saa_common::generateAppendFunction(cs, fir::Type::getString()); - } - - fir::Function* getCharAppendFunction(CodegenState* cs) - { - return saa_common::generateElementAppendFunction(cs, fir::Type::getString()); - } - - fir::Function* getConstructFromTwoFunction(CodegenState* cs) - { - return saa_common::generateConstructFromTwoFunction(cs, fir::Type::getString()); - } - - fir::Function* getConstructWithCharFunction(CodegenState* cs) - { - return saa_common::generateConstructWithElementFunction(cs, fir::Type::getString()); - } - - fir::Function* getBoundsCheckFunction(CodegenState* cs, bool isDecomp) - { - return saa_common::generateBoundsCheckFunction(cs, /* isString: */ true, isDecomp); - } - - fir::Function* getCompareFunction(CodegenState* cs) - { - auto fname = misc::getCompare_FName(fir::Type::getString()); - fir::Function* cmpf = cs->module->getFunction(fname); - - if(!cmpf) - { - // great. - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ fir::Type::getString(), fir::Type::getString() }, - fir::Type::getNativeWord()), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - fir::Value* s1 = func->getArguments()[0]; - fir::Value* s2 = func->getArguments()[1]; - - /* - int strcmp(const char* s1, const char* s2) - { - while(*s1 && (*s1 == *s2)) - s1++, s2++; - - return *(const unsigned char*) s1 - *(const unsigned char*) s2; - } - */ - - { - fir::Value* str1p = cs->irb.StackAlloc(fir::Type::getMutInt8Ptr()); - cs->irb.WritePtr(cs->irb.GetSAAData(s1, "s1"), str1p); - - fir::Value* str2p = cs->irb.StackAlloc(fir::Type::getMutInt8Ptr()); - cs->irb.WritePtr(cs->irb.GetSAAData(s2, "s2"), str2p); - - - fir::IRBlock* loopcond = cs->irb.addNewBlockInFunction("cond1", func); - fir::IRBlock* loopincr = cs->irb.addNewBlockInFunction("loopincr", func); - fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); - - cs->irb.UnCondBranch(loopcond); - cs->irb.setCurrentBlock(loopcond); - { - fir::IRBlock* cond2 = cs->irb.addNewBlockInFunction("cond2", func); - - fir::Value* str1 = cs->irb.ReadPtr(str1p); - fir::Value* str2 = cs->irb.ReadPtr(str2p); - - // make sure ptr1 is not null - fir::Value* cnd = cs->irb.ICmpNEQ(cs->irb.ReadPtr(str1), fir::ConstantInt::getInt8(0)); - cs->irb.CondBranch(cnd, cond2, merge); - - cs->irb.setCurrentBlock(cond2); - { - // check that they are equal - fir::Value* iseq = cs->irb.ICmpEQ(cs->irb.ReadPtr(str1), cs->irb.ReadPtr(str2)); - cs->irb.CondBranch(iseq, loopincr, merge); - } - - - cs->irb.setCurrentBlock(loopincr); - { - // increment str1 and str2 - fir::Value* v1 = cs->irb.GetPointer(str1, fir::ConstantInt::getNative(1)); - fir::Value* v2 = cs->irb.GetPointer(str2, fir::ConstantInt::getNative(1)); - - cs->irb.WritePtr(v1, str1p); - cs->irb.WritePtr(v2, str2p); - - cs->irb.UnCondBranch(loopcond); - } - } - - cs->irb.setCurrentBlock(merge); - fir::Value* ret = cs->irb.Subtract(cs->irb.ReadPtr(cs->irb.ReadPtr(str1p)), - cs->irb.ReadPtr(cs->irb.ReadPtr(str2p))); - - ret = cs->irb.IntSizeCast(ret, func->getReturnType()); - - cs->irb.Return(ret); - } - - cmpf = func; - cs->irb.setCurrentBlock(restore); - } - - iceAssert(cmpf); - return cmpf; - } - - - static void _doRefCount(CodegenState* cs, fir::Function* func, bool decrement) - { - auto str = func->getArguments()[0]; - auto rcp = cs->irb.GetSAARefCountPointer(str, "rcp"); - - fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); - fir::IRBlock* dorc = cs->irb.addNewBlockInFunction("dorc", func); - - cs->irb.CondBranch(cs->irb.ICmpEQ(rcp, fir::ConstantValue::getZeroValue(fir::Type::getNativeWordPtr())), - merge, dorc); - - cs->irb.setCurrentBlock(dorc); - { - auto oldrc = cs->irb.ReadPtr(rcp, "oldrc"); - auto newrc = cs->irb.Add(oldrc, fir::ConstantInt::getNative(decrement ? -1 : 1)); - - cs->irb.SetSAARefCount(str, newrc); - - #if DEBUG_STRING_REFCOUNTING - { - std::string x = decrement ? "(decr)" : "(incr)"; - - cs->printIRDebugMessage("* STRING: " + x + " - new rc of: (ptr: %p, len: %ld, cap: %ld) = %d", - { cs->irb.GetSAAData(str), cs->irb.GetSAALength(str), cs->irb.GetSAACapacity(str), cs->irb.GetSAARefCount(str) }); - } - #endif - - if(decrement) - { - fir::IRBlock* dofree = cs->irb.addNewBlockInFunction("dofree", func); - cs->irb.CondBranch(cs->irb.ICmpEQ(newrc, fir::ConstantInt::getNative(0)), - dofree, merge); - - cs->irb.setCurrentBlock(dofree); - { - auto freefn = cs->getOrDeclareLibCFunction(FREE_MEMORY_FUNC); - iceAssert(freefn); - - auto buf = cs->irb.GetSAAData(str, "buf"); - buf = cs->irb.PointerTypeCast(buf, fir::Type::getMutInt8Ptr()); - - cs->irb.Call(freefn, buf); - cs->irb.Call(freefn, cs->irb.PointerTypeCast(cs->irb.GetSAARefCountPointer(str), fir::Type::getMutInt8Ptr())); - - #if DEBUG_STRING_ALLOCATION - { - cs->printIRDebugMessage("* STRING: free(): (ptr: %p / rcp: %p)", { - buf, cs->irb.GetSAARefCountPointer(str) }); - } - #endif - } - } - - cs->irb.UnCondBranch(merge); - } - - cs->irb.setCurrentBlock(merge); - { - cs->irb.ReturnVoid(); - } - } - - - - - fir::Function* getRefCountIncrementFunction(CodegenState* cs) - { - auto fname = misc::getIncrRefcount_FName(fir::Type::getString()); - fir::Function* retfn = cs->module->getFunction(fname); - - if(!retfn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ fir::Type::getString() }, fir::Type::getVoid()), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - _doRefCount(cs, func, false); - - cs->irb.setCurrentBlock(restore); - retfn = func; - } - - iceAssert(retfn); - return retfn; - } - - fir::Function* getRefCountDecrementFunction(CodegenState* cs) - { - auto fname = misc::getDecrRefcount_FName(fir::Type::getString()); - fir::Function* retfn = cs->module->getFunction(fname); - - if(!retfn) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ fir::Type::getString() }, fir::Type::getVoid()), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - _doRefCount(cs, func, true); - - cs->irb.setCurrentBlock(restore); - retfn = func; - } - - iceAssert(retfn); - return retfn; - } - - - - - - fir::Function* getUnicodeLengthFunction(CodegenState* cs) - { - auto fname = misc::getUtf8Length_FName(); - fir::Function* lenf = cs->module->getFunction(fname); - - if(!lenf) - { - auto restore = cs->irb.getCurrentBlock(); - - fir::Function* func = cs->module->getOrCreateFunction(fname, - fir::FunctionType::get({ fir::Type::getInt8Ptr() }, fir::Type::getNativeWord()), fir::LinkageType::Internal); - - func->setAlwaysInline(); - - fir::IRBlock* entry = cs->irb.addNewBlockInFunction("entry", func); - cs->irb.setCurrentBlock(entry); - - fir::Value* _ptr = func->getArguments()[0]; - iceAssert(_ptr); - - fir::Value* ptrp = cs->irb.StackAlloc(fir::Type::getInt8Ptr()); - cs->irb.WritePtr(_ptr, ptrp); - - /* - - public fn Utf8Length(_text: i8*) -> i64 - { - var len = 0 - var text = _text - - - while *text != 0 - { - if (*text & 0xC0) != 0x80 - { - len += 1 - } - - text = text + 1 - } - - return len - } - */ - auto i0 = fir::ConstantInt::getNative(0); - auto i1 = fir::ConstantInt::getNative(1); - auto c0 = fir::ConstantInt::getInt8(0); - - fir::Value* lenp = cs->irb.StackAlloc(fir::Type::getNativeWord()); - cs->irb.WritePtr(i0, lenp); - - - fir::IRBlock* cond = cs->irb.addNewBlockInFunction("cond", func); - fir::IRBlock* body = cs->irb.addNewBlockInFunction("body", func); - fir::IRBlock* merge = cs->irb.addNewBlockInFunction("merge", func); - - - fir::Value* isnull = cs->irb.ICmpEQ(fir::ConstantValue::getZeroValue(fir::Type::getInt8Ptr()), _ptr); - cs->irb.CondBranch(isnull, merge, cond); - - cs->irb.setCurrentBlock(cond); - { - auto ch = cs->irb.ReadPtr(cs->irb.ReadPtr(ptrp)); - auto isnotzero = cs->irb.ICmpNEQ(ch, c0); - - cs->irb.CondBranch(isnotzero, body, merge); - } - - cs->irb.setCurrentBlock(body); - { - // if statement - auto ch = cs->irb.ReadPtr(cs->irb.ReadPtr(ptrp)); - - auto mask = cs->irb.BitwiseAND(ch, cs->irb.IntSizeCast(fir::ConstantInt::getUint8(0xC0), fir::Type::getInt8())); - auto isch = cs->irb.ICmpNEQ(mask, cs->irb.IntSizeCast(fir::ConstantInt::getUint8(0x80), fir::Type::getInt8())); - - fir::IRBlock* incr = cs->irb.addNewBlockInFunction("incr", func); - fir::IRBlock* skip = cs->irb.addNewBlockInFunction("skip", func); - - cs->irb.CondBranch(isch, incr, skip); - cs->irb.setCurrentBlock(incr); - { - cs->irb.WritePtr(cs->irb.Add(cs->irb.ReadPtr(lenp), i1), lenp); - - cs->irb.UnCondBranch(skip); - } - - cs->irb.setCurrentBlock(skip); - { - auto newptr = cs->irb.GetPointer(cs->irb.ReadPtr(ptrp), i1); - cs->irb.WritePtr(newptr, ptrp); - - cs->irb.UnCondBranch(cond); - } - } - - cs->irb.setCurrentBlock(merge); - { - auto len = cs->irb.ReadPtr(lenp); - cs->irb.Return(len); - } - - - lenf = func; - cs->irb.setCurrentBlock(restore); - } - - iceAssert(lenf); - return lenf; - } -} -} -} - diff --git a/source/codegen/literals.cpp b/source/codegen/literals.cpp index b3b07d20..0f072728 100644 --- a/source/codegen/literals.cpp +++ b/source/codegen/literals.cpp @@ -10,22 +10,14 @@ CGResult sst::LiteralNumber::_codegen(cgn::CodegenState* cs, fir::Type* infer) cs->pushLoc(this); defer(cs->popLoc()); + if(this->is_floating != this->type->isFloatingPointType()) + error(this, "TODO cannot do this"); - if(this->type->isConstantNumberType()) - { - if(infer && !infer->isPrimitiveType()) - infer = 0; + if(this->type->isFloatingPointType()) + return CGResult(fir::ConstantFP::get(this->type, this->floating)); - return CGResult(cs->unwrapConstantNumber(fir::ConstantNumber::get(this->type->toConstantNumberType(), this->num), infer)); - } else - { - if(this->type->isFloatingPointType()) - return CGResult(fir::ConstantFP::get(this->type, this->num.toDouble())); - - else - return CGResult(fir::ConstantInt::get(this->type, this->type->isSignedIntType() ? this->num.toLLong() : this->num.toULLong())); - } + return CGResult(fir::ConstantInt::get(this->type, this->integer)); } CGResult sst::LiteralArray::_codegen(cgn::CodegenState* cs, fir::Type* infer) @@ -36,9 +28,6 @@ CGResult sst::LiteralArray::_codegen(cgn::CodegenState* cs, fir::Type* infer) if(this->type->isArrayType()) { auto elmty = this->type->toArrayType()->getElementType(); - if(fir::isRefCountedType(elmty)) - error(this, "cannot have refcounted type in array literal"); - std::vector vals; for(auto v : this->values) { @@ -55,7 +44,7 @@ CGResult sst::LiteralArray::_codegen(cgn::CodegenState* cs, fir::Type* infer) // ok return CGResult(fir::ConstantArray::get(this->type, vals)); } - else if(this->type->isDynamicArrayType() || this->type->isArraySliceType()) + else if(this->type->isArraySliceType()) { // ok, this can basically be anything. // no restrictions. @@ -70,14 +59,7 @@ CGResult sst::LiteralArray::_codegen(cgn::CodegenState* cs, fir::Type* infer) error(this, "failed to infer type for empty array literal"); auto z = fir::ConstantInt::getNative(0); - if(infer->isDynamicArrayType()) - { - // ok. - elmty = infer->getArrayElementType(); - returnValue = fir::ConstantDynamicArray::get(fir::DynamicArrayType::get(elmty), - fir::ConstantValue::getZeroValue(elmty->getPointerTo()), z, z); - } - else if(infer->isArraySliceType()) + if(infer->isArraySliceType()) { elmty = infer->getArrayElementType(); @@ -146,20 +128,7 @@ CGResult sst::LiteralArray::_codegen(cgn::CodegenState* cs, fir::Type* infer) } // return it - if(this->type->isDynamicArrayType()) - { - auto arrptr = cs->irb.AddressOf(array, true); - - auto aa = cs->irb.CreateValue(this->type->toDynamicArrayType()); - - aa = cs->irb.SetSAAData(aa, cs->irb.ConstGEP2(arrptr, 0, 0)); - aa = cs->irb.SetSAALength(aa, fir::ConstantInt::getNative(this->values.size())); - aa = cs->irb.SetSAACapacity(aa, fir::ConstantInt::getNative(-1)); - aa = cs->irb.SetSAARefCountPointer(aa, fir::ConstantValue::getZeroValue(fir::Type::getNativeWordPtr())); - - returnValue = aa; - } - else if(this->type->isArraySliceType()) + if(this->type->isArraySliceType()) { auto arrptr = cs->irb.AddressOf(array, true); diff --git a/source/codegen/loops.cpp b/source/codegen/loops.cpp index e03cb450..b583064c 100644 --- a/source/codegen/loops.cpp +++ b/source/codegen/loops.cpp @@ -184,18 +184,10 @@ CGResult sst::ForeachLoop::_codegen(cgn::CodegenState* cs, fir::Type* inferred) cs->irb.WritePtr(fir::ConstantInt::getNative(0), idxptr); step = fir::ConstantInt::getNative(1); - if(array->getType()->isDynamicArrayType()) - { - end = cs->irb.GetSAALength(array); - } - else if(array->getType()->isArraySliceType()) + if(array->getType()->isArraySliceType()) { end = cs->irb.GetArraySliceLength(array); } - else if(array->getType()->isStringType()) - { - end = cs->irb.GetSAALength(array); - } else if(array->getType()->isArrayType()) { end = fir::ConstantInt::getNative(array->getType()->toArrayType()->getArraySize()); @@ -214,8 +206,8 @@ CGResult sst::ForeachLoop::_codegen(cgn::CodegenState* cs, fir::Type* inferred) if(array->getType()->isRangeType()) { cond = cs->irb.Select(cs->irb.ICmpGT(step, fir::ConstantInt::getNative(0)), - cs->irb.ICmpLT(cs->irb.ReadPtr(idxptr), end), // i < end for step > 0 - cs->irb.ICmpGT(cs->irb.ReadPtr(idxptr), end)); // i > end for step < 0 + cs->irb.ICmpLT(cs->irb.ReadPtr(idxptr), end), // i < end for step > 0 + cs->irb.ICmpGT(cs->irb.ReadPtr(idxptr), end)); // i > end for step < 0 } else { @@ -231,15 +223,9 @@ CGResult sst::ForeachLoop::_codegen(cgn::CodegenState* cs, fir::Type* inferred) if(array->getType()->isRangeType()) theptr = idxptr; - else if(array->getType()->isDynamicArrayType()) - theptr = cs->irb.GetPointer(cs->irb.GetSAAData(array), cs->irb.ReadPtr(idxptr)); - - else if(array->getType()->isArraySliceType()) + if(array->getType()->isArraySliceType()) theptr = cs->irb.GetPointer(cs->irb.GetArraySliceData(array), cs->irb.ReadPtr(idxptr)); - else if(array->getType()->isStringType()) - theptr = cs->irb.PointerTypeCast(cs->irb.GetPointer(cs->irb.GetSAAData(array), cs->irb.ReadPtr(idxptr)), fir::Type::getInt8Ptr()); - else if(array->getType()->isArrayType()) { fir::Value* arrptr = 0; @@ -272,7 +258,7 @@ CGResult sst::ForeachLoop::_codegen(cgn::CodegenState* cs, fir::Type* inferred) // TODO: is this correct??? auto res = CGResult(cs->irb.Dereference(theptr)); - cs->generateDecompositionBindings(this->mappings, res, !(_array->getType()->isRangeType() || _array->getType()->isStringType())); + cs->generateDecompositionBindings(this->mappings, res, !(_array->getType()->isRangeType())); if(this->indexVar) { diff --git a/source/codegen/operators.cpp b/source/codegen/operators.cpp index 80ea503b..121d8230 100644 --- a/source/codegen/operators.cpp +++ b/source/codegen/operators.cpp @@ -11,14 +11,13 @@ namespace cgn std::pair CodegenState::getOperatorFunctionForTypes(fir::Type* a, fir::Type* b, std::string op) { std::function isBuiltinType = [&](fir::Type* t) -> bool { - if(t->isPrimitiveType()) return true; - else if(t->isBoolType()) return true; - else if(t->isCharType()) return true; - else if(t->isStringType()) return true; - else if(t->isNullType()) return true; - else if(t->isVoidType()) return true; - else if(t->isPointerType()) return true; - else if(t->isArrayType() || t->isDynamicArrayType() || t->isArraySliceType()) + if(t->isPrimitiveType()) return true; + else if(t->isBoolType()) return true; + else if(t->isCharType()) return true; + else if(t->isNullType()) return true; + else if(t->isVoidType()) return true; + else if(t->isPointerType()) return true; + else if(t->isArrayType() || t->isArraySliceType()) { return isBuiltinType(t->getArrayElementType()); } diff --git a/source/codegen/raii.cpp b/source/codegen/raii.cpp index 5a9b6dc0..ecb8d0dd 100644 --- a/source/codegen/raii.cpp +++ b/source/codegen/raii.cpp @@ -8,6 +8,17 @@ namespace cgn { + void CodegenState::performAssignment(fir::Value* lhs, fir::Value* rhs, bool isinit) + { + iceAssert(lhs && rhs); + + if(!lhs->islvalue()) + error(this->loc(), "assignment (move) to non-lvalue and non-pointer (type '%s')", lhs->getType()); + + // copy will do the right thing in all cases (handle non-RAII, and call move if possible) + this->copyRAIIValue(rhs, lhs); + } + void CodegenState::addRAIIValue(fir::Value* val) { // TODO: we need global destructors eventually. @@ -58,9 +69,6 @@ namespace cgn if(!ty) ty = val->getType(); - if(fir::isRefCountedType(ty)) - this->addRefCountedValue(val); - if(this->isRAIIType(ty)) this->addRAIIValue(val); } @@ -115,68 +123,16 @@ namespace cgn fir::Value* selfptr = getAddressOfOrMakeTemporaryLValue(this, val, /* mutable: */ true); + auto destructor = getImplementationForRAIITrait(this, strs::names::support::RAII_TRAIT_DROP, val->getType()); - if(val->getType()->isClassType()) - { - auto cls = val->getType()->toClassType(); - - // call the user-defined one first, if any: - if(auto des = cls->getDestructor(); des) - this->irb.Call(des, selfptr); - - // call the auto one. this will handle calling base class destructors for us! - this->irb.Call(cls->getInlineDestructor(), selfptr); - } - else - { - auto destructor = getImplementationForRAIITrait(this, strs::names::support::RAII_TRAIT_DROP, val->getType()); - - // well if you didn't implement it then the typechecker would have already complained about you so... - iceAssert(destructor); - this->irb.Call(destructor, selfptr); - } + // well if you didn't implement it then the typechecker would have already complained about you so... + iceAssert(destructor); + this->irb.Call(destructor, selfptr); } - static void doMemberWiseStuffIfNecessary(CodegenState* cs, fir::ClassType* clsty, fir::Value* from, fir::Value* target, bool move) - { - // check if there are even any class types inside. if not, do the simple thing! - bool needSpecial = false; - - for(auto m : clsty->getElements()) - { - if(m->isClassType()) - { - needSpecial = true; - break; - } - } - - if(needSpecial) - { - auto selfptr = getAddressOfOrMakeTemporaryLValue(cs, target, true); - auto otherptr = getAddressOfOrMakeTemporaryLValue(cs, from, true); - - // assign `lhs = rhs` - - for(const auto& name : clsty->getNameList()) - { - auto lhs = cs->irb.GetStructMember(cs->irb.Dereference(selfptr), name); - auto rhs = cs->irb.GetStructMember(cs->irb.Dereference(otherptr), name); - - if(move) cs->moveRAIIValue(rhs, lhs); - else cs->copyRAIIValue(rhs, lhs); - } - } - else - { - cs->irb.Store(from, target); - } - } - - @@ -211,28 +167,6 @@ namespace cgn return; } - // there's probably a better way to structure this, but i can't be bothered right now - // or ever. it's just 2 lines of code dupe anyway. so sue me. - - if(from->getType()->isClassType()) - { - auto clsty = from->getType()->toClassType(); - - // if there is a copy-constructor, then we will call the copy constructor. - if(auto copycon = clsty->getCopyConstructor(); copycon) - { - // note: we make otherptr immutable, because copy() isn't supposed to pass the thing mutably! - auto selfptr = getAddressOfOrMakeTemporaryLValue(this, target, true); - auto otherptr = getAddressOfOrMakeTemporaryLValue(this, from, false); - - this->irb.Call(copycon, selfptr, otherptr); - } - else - { - doMemberWiseStuffIfNecessary(this, clsty, from, target, /* move: */ false); - } - } - else { // note: we make otherptr immutable, because copy() isn't supposed to pass the thing mutably! auto selfptr = getAddressOfOrMakeTemporaryLValue(this, target, true); @@ -261,25 +195,6 @@ namespace cgn return; } - if(from->getType()->isClassType()) - { - auto clsty = from->getType()->toClassType(); - - // if there is a copy-constructor, then we will call the copy constructor. - if(auto movecon = clsty->getMoveConstructor(); movecon) - { - // note: here both are mutable. - auto selfptr = getAddressOfOrMakeTemporaryLValue(this, target, true); - auto otherptr = getAddressOfOrMakeTemporaryLValue(this, from, true); - - this->irb.Call(movecon, selfptr, otherptr); - } - else - { - doMemberWiseStuffIfNecessary(this, clsty, from, target, /* move: */ true); - } - } - else { // note: here both are mutable. auto selfptr = getAddressOfOrMakeTemporaryLValue(this, target, true); @@ -300,9 +215,6 @@ namespace cgn // TODO: memoise this for each type; the typeHas-blalba ones also! static bool findRAIITraitImpl(CodegenState* cs, fir::Type* ty, const std::string& name) { - if(ty->isClassType()) - return true; - if(!ty->isStructType()) return false; diff --git a/source/codegen/ranges.cpp b/source/codegen/ranges.cpp index 3d331485..cf6480e0 100644 --- a/source/codegen/ranges.cpp +++ b/source/codegen/ranges.cpp @@ -42,11 +42,6 @@ CGResult sst::RangeExpr::_codegen(cgn::CodegenState* cs, fir::Type* infer) ret = cs->irb.SetRangeUpper(ret, end); ret = cs->irb.SetRangeStep(ret, step); - // now that we have all the values, it's time to sanity check these things. - auto checkf = cgn::glue::misc::getRangeSanityCheckFunction(cs); - if(checkf) cs->irb.Call(checkf, ret, fir::ConstantCharSlice::get(this->loc.toString())); - - return CGResult(ret); } diff --git a/source/codegen/refcounting.cpp b/source/codegen/refcounting.cpp deleted file mode 100644 index ac3a83b3..00000000 --- a/source/codegen/refcounting.cpp +++ /dev/null @@ -1,200 +0,0 @@ -// refcounting.cpp -// Copyright (c) 2014 - 2017, zhiayang -// Licensed under the Apache License Version 2.0. - -#include "sst.h" -#include "codegen.h" -#include "gluecode.h" - -namespace cgn -{ - void CodegenState::addRefCountedValue(fir::Value* val) - { - if(this->isWithinGlobalInitFunction()) - return; - - auto list = &this->blockPointStack.back().refCountedValues; - - if(auto it = std::find(list->begin(), list->end(), val); it == list->end()) - { - list->push_back(val); - } - else - { - error(this->loc(), "adding duplicate refcounted value (ptr = %p, type = '%s')", - reinterpret_cast(val), val->getType()); - } - } - - void CodegenState::removeRefCountedValue(fir::Value* val) - { - if(this->isWithinGlobalInitFunction()) - return; - - auto list = &this->blockPointStack.back().refCountedValues; - - if(auto it = std::find(list->begin(), list->end(), val); it != list->end()) - { - list->erase(it); - } - else - { - error(this->loc(), "removing non-existent refcounted value (ptr = %p, type = '%s')", - reinterpret_cast(val), val->getType()); - } - } - - std::vector CodegenState::getRefCountedValues() - { - return this->blockPointStack.back().refCountedValues; - } - - - void CodegenState::autoAssignRefCountedValue(fir::Value* lhs, fir::Value* rhs, bool isinit) - { - iceAssert(lhs && rhs); - - if(!lhs->islvalue()) - error(this->loc(), "assignment (move) to non-lvalue and non-pointer (type '%s')", lhs->getType()); - - if(fir::isRefCountedType(rhs->getType())) - { - if(!isinit) - this->decrementRefCount(lhs); - - if(rhs->canmove()) - { - this->removeRefCountedValue(rhs); - } - else - { - this->incrementRefCount(rhs); - } - } - - // copy will do the right thing in all cases (handle non-RAII, and call move if possible) - this->copyRAIIValue(rhs, lhs); - } - - - - - - - - - - - - - - - - static bool isStructuredAggregate(fir::Type* t) - { - return t->isStructType() || t->isClassType() || t->isTupleType(); - } - - - template - void doRefCountOfAggregateType(CodegenState* cs, T* type, fir::Value* value, bool incr) - { - size_t i = 0; - for(auto m : type->getElements()) - { - if(fir::isRefCountedType(m)) - { - fir::Value* mem = cs->irb.ExtractValue(value, { i }); - - if(incr) cs->incrementRefCount(mem); - else cs->decrementRefCount(mem); - } - else if(isStructuredAggregate(m)) - { - fir::Value* mem = cs->irb.ExtractValue(value, { i }); - - if(m->isStructType()) doRefCountOfAggregateType(cs, m->toStructType(), mem, incr); - else if(m->isClassType()) doRefCountOfAggregateType(cs, m->toClassType(), mem, incr); - else if(m->isTupleType()) doRefCountOfAggregateType(cs, m->toTupleType(), mem, incr); - } - - i++; - } - } - - static void _doRefCount(CodegenState* cs, fir::Value* val, bool incr) - { - auto type = val->getType(); - - if(type->isStringType()) - { - fir::Function* rf = 0; - if(incr) rf = glue::string::getRefCountIncrementFunction(cs); - else rf = glue::string::getRefCountDecrementFunction(cs); - - cs->irb.Call(rf, val); - } - else if(isStructuredAggregate(type)) - { - auto ty = type; - - if(ty->isStructType()) doRefCountOfAggregateType(cs, ty->toStructType(), val, incr); - else if(ty->isClassType()) doRefCountOfAggregateType(cs, ty->toClassType(), val, incr); - else if(ty->isTupleType()) doRefCountOfAggregateType(cs, ty->toTupleType(), val, incr); - } - else if(type->isDynamicArrayType()) - { - fir::Function* rf = 0; - if(incr) rf = glue::array::getIncrementArrayRefCountFunction(cs, type->toDynamicArrayType()); - else rf = glue::array::getDecrementArrayRefCountFunction(cs, type->toDynamicArrayType()); - - iceAssert(rf); - cs->irb.Call(rf, val); - } - else if(type->isArrayType()) - { - error("no array"); - } - else if(type->isAnyType()) - { - fir::Function* rf = 0; - if(incr) rf = glue::any::getRefCountIncrementFunction(cs); - else rf = glue::any::getRefCountDecrementFunction(cs); - - cs->irb.Call(rf, val); - } - else - { - error("no: '%s'", type); - } - } - - void CodegenState::incrementRefCount(fir::Value* val) - { - iceAssert(fir::isRefCountedType(val->getType())); - _doRefCount(this, val, true); - } - - void CodegenState::decrementRefCount(fir::Value* val) - { - iceAssert(fir::isRefCountedType(val->getType())); - _doRefCount(this, val, false); - } -} - - - - - - - - - - - - - - - - - diff --git a/source/codegen/slice.cpp b/source/codegen/slice.cpp index fb4231a5..db01c0e3 100644 --- a/source/codegen/slice.cpp +++ b/source/codegen/slice.cpp @@ -64,15 +64,6 @@ static void checkSliceOperation(cgn::CodegenState* cs, sst::Expr* user, fir::Val cs->irb.setCurrentBlock(merge); - - // bounds check. - { - // endindex is non-inclusive -- if we're doing a decomposition check then it compares length instead - // of indices here. - fir::Function* checkf = cgn::glue::array::getBoundsCheckFunction(cs, /* isPerformingDecomposition: */ true); - if(checkf) - cs->irb.Call(checkf, maxlen, endIndex, fir::ConstantCharSlice::get(apos.toString())); - } } @@ -119,12 +110,10 @@ CGResult sst::SliceOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) iceAssert(ty == lhs->getType()); fir::Value* length = 0; - if(ty->isDynamicArrayType()) length = cs->irb.GetSAALength(lhs, "orig_len"); - else if(ty->isArraySliceType()) length = cs->irb.GetArraySliceLength(lhs, "orig_len"); - else if(ty->isStringType()) length = cs->irb.GetSAALength(lhs, "orig_len"); - else if(ty->isArrayType()) length = fir::ConstantInt::getNative(ty->toArrayType()->getArraySize()); + if(ty->isArraySliceType()) length = cs->irb.GetArraySliceLength(lhs, "orig_len"); + else if(ty->isArrayType()) length = fir::ConstantInt::getNative(ty->toArrayType()->getArraySize()); else if(ty->isPointerType()) length = fir::ConstantInt::getNative(0); - else error(this, "unsupported type '%s'", ty); + else error(this, "unsupported type '%s'", ty); fir::Value* beginIdx = 0; fir::Value* endIdx = 0; @@ -138,11 +127,11 @@ CGResult sst::SliceOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) if(ty->isPointerType() && !this->end) error(this, "slicing operation on pointers requires an ending index"); - if(this->begin) beginIdx = this->begin->codegen(cs).value; - else beginIdx = fir::ConstantInt::getNative(0); + if(this->begin) beginIdx = this->begin->codegen(cs).value; + else beginIdx = fir::ConstantInt::getNative(0); - if(this->end) endIdx = this->end->codegen(cs).value; - else endIdx = length; + if(this->end) endIdx = this->end->codegen(cs).value; + else endIdx = length; beginIdx = cs->oneWayAutocast(beginIdx, fir::Type::getNativeWord()); endIdx = cs->oneWayAutocast(endIdx, fir::Type::getNativeWord()); @@ -172,11 +161,6 @@ CGResult sst::SliceOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) return performSliceOperation(cs, this, false, ty->getPointerElementType(), lhs, length, beginIdx, endIdx, this->begin, this->end); } - else if(ty->isDynamicArrayType()) - { - return performSliceOperation(cs, this, true, ty->getArrayElementType(), cs->irb.GetSAAData(lhs), - length, beginIdx, endIdx, this->begin, this->end); - } else if(ty->isArrayType()) { // TODO: LVALUE HOLE @@ -195,11 +179,6 @@ CGResult sst::SliceOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) return performSliceOperation(cs, this, true, ty->getArrayElementType(), cs->irb.GetArraySliceData(lhs), length, beginIdx, endIdx, this->begin, this->end); } - else if(ty->isStringType()) - { - return performSliceOperation(cs, this, true, fir::Type::getInt8(), cs->irb.GetSAAData(lhs), - length, beginIdx, endIdx, this->begin, this->end); - } else { error(this, "cannot slice unsupported type '%s'", ty); @@ -237,7 +216,7 @@ CGResult sst::SplatExpr::_codegen(cgn::CodegenState* cs, fir::Type* infer) return CGResult(cs->irb.Bitcast(ret.value, fir::ArraySliceType::getVariadic(ret->getType()->getArrayElementType()))); } } - else if(ty->isDynamicArrayType() || ty->isArrayType()) + else if(ty->isArrayType()) { // just do a slice on it. auto target = fir::ArraySliceType::getVariadic(ty->getArrayElementType()); diff --git a/source/codegen/subscript.cpp b/source/codegen/subscript.cpp index b1099e3d..58a3539f 100644 --- a/source/codegen/subscript.cpp +++ b/source/codegen/subscript.cpp @@ -19,12 +19,7 @@ CGResult sst::SubscriptOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) fir::Value* datapointer = 0; fir::Value* maxlength = 0; - if(lt->isStringType() || lt->isDynamicArrayType()) - { - datapointer = cs->irb.GetSAAData(lr.value); - maxlength = cs->irb.GetSAALength(lr.value); - } - else if(lt->isArraySliceType()) + if(lt->isArraySliceType()) { datapointer = cs->irb.GetArraySliceData(lr.value); maxlength = cs->irb.GetArraySliceLength(lr.value); @@ -56,25 +51,10 @@ CGResult sst::SubscriptOp::_codegen(cgn::CodegenState* cs, fir::Type* infer) // first gen the inside fir::Value* index = this->inside->codegen(cs).value; { - if(index->getType()->isConstantNumberType()) - { - auto cv = dcast(fir::ConstantValue, index); - iceAssert(cv); - - index = cs->unwrapConstantNumber(cv); - } - // of course these will have to be changed eventually iceAssert(index->getType()->isIntegerType()); } - if(maxlength) - { - fir::Function* checkf = cgn::glue::saa_common::generateBoundsCheckFunction(cs, /* isString: */ lt->isStringType(), /* isDecomp: */false); - if(checkf) - cs->irb.Call(checkf, maxlength, index, fir::ConstantCharSlice::get(this->loc.shortString())); - } - // ok, do it fir::Value* ptr = cs->irb.GetPointer(datapointer, index); return CGResult(cs->irb.Dereference(ptr)); diff --git a/source/codegen/variable.cpp b/source/codegen/variable.cpp index 9b384ea1..0a2f9dbb 100644 --- a/source/codegen/variable.cpp +++ b/source/codegen/variable.cpp @@ -56,7 +56,7 @@ CGResult sst::VarDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) else { res = checkStore(res); - cs->autoAssignRefCountedValue(glob, res, true); + cs->performAssignment(glob, res, true); } // go and fix the thing. @@ -84,7 +84,7 @@ CGResult sst::VarDefn::_codegen(cgn::CodegenState* cs, fir::Type* infer) } auto alloc = cs->irb.CreateLValue(this->type, this->id.name); - cs->autoAssignRefCountedValue(alloc, val, /* isInitial: */ true); + cs->performAssignment(alloc, val, /* isInitial: */ true); if(this->immutable) alloc->makeConst(); diff --git a/source/fir/ConstantValue.cpp b/source/fir/ConstantValue.cpp index 99ca5efa..addb1db9 100644 --- a/source/fir/ConstantValue.cpp +++ b/source/fir/ConstantValue.cpp @@ -78,21 +78,6 @@ namespace fir - ConstantNumber* ConstantNumber::get(ConstantNumberType* cnt, const mpfr::mpreal& n) - { - return new ConstantNumber(cnt, n); - } - - ConstantNumber::ConstantNumber(ConstantNumberType* cnt, const mpfr::mpreal& n) : ConstantValue(cnt) - { - this->number = n; - } - - std::string ConstantNumber::str() - { - // 6 decimal places, like default printf. - return this->number.toString("%.6R"); - } @@ -452,58 +437,6 @@ namespace fir - ConstantDynamicArray* ConstantDynamicArray::get(DynamicArrayType* t, ConstantValue* d, ConstantValue* l, ConstantValue* c) - { - auto cda = new ConstantDynamicArray(t); - cda->data = d; - cda->length = l; - cda->capacity = c; - - return cda; - } - - ConstantDynamicArray* ConstantDynamicArray::get(ConstantArray* arr) - { - auto cda = new ConstantDynamicArray(DynamicArrayType::get(arr->getType()->toArrayType()->getElementType())); - cda->arr = arr; - - return cda; - } - - - ConstantDynamicArray::ConstantDynamicArray(DynamicArrayType* t) : ConstantValue(t) - { - } - - std::string ConstantDynamicArray::str() - { - return ""; - } - - - - ConstantDynamicString* ConstantDynamicString::get(const std::string& s) - { - return new ConstantDynamicString(s); - } - - ConstantDynamicString::ConstantDynamicString(const std::string& s) : ConstantValue(fir::Type::getString()) - { - this->value = s; - } - - std::string ConstantDynamicString::getValue() - { - return this->value; - } - - std::string ConstantDynamicString::str() - { - return zpr::sprint("\"%s\"", this->value); - } - - - diff --git a/source/fir/IRBuilder.cpp b/source/fir/IRBuilder.cpp index 3c9cfab6..619a8ffe 100644 --- a/source/fir/IRBuilder.cpp +++ b/source/fir/IRBuilder.cpp @@ -13,21 +13,6 @@ #include "memorypool.h" - -static bool isSAAType(fir::Type* t) -{ - return t->isStringType() || t->isDynamicArrayType(); -} - -static fir::Type* getSAAElmType(fir::Type* t) -{ - iceAssert(isSAAType(t)); - - if(t->isStringType()) return fir::Type::getInt8(); - else return t->getArrayElementType(); -} - - namespace fir { IRBuilder::IRBuilder(Module* mod) @@ -783,13 +768,13 @@ namespace fir bool sgn = ci->getType()->isSignedIntType(); if(targetType == Type::getFloat32()) { - if(sgn) ret = ConstantFP::getFloat32(static_cast(ci->getSignedValue())); - else ret = ConstantFP::getFloat32(static_cast(ci->getUnsignedValue())); + if(sgn) ret = ConstantFP::getFloat32(static_cast(ci->getSignedValue())); + else ret = ConstantFP::getFloat32(static_cast(ci->getUnsignedValue())); } else if(targetType == Type::getFloat64()) { - if(sgn) ret = ConstantFP::getFloat64(static_cast(ci->getSignedValue())); - else ret = ConstantFP::getFloat64(static_cast(ci->getUnsignedValue())); + if(sgn) ret = ConstantFP::getFloat64(static_cast(ci->getSignedValue())); + else ret = ConstantFP::getFloat64(static_cast(ci->getUnsignedValue())); } else { @@ -1021,10 +1006,7 @@ namespace fir else if(fn->isCStyleVarArg()) { // auto-convert strings and char slices into char* when passing to va_args - if(at->isStringType()) - out.push_back(this->GetSAAData(args[i])); - - else if(at->isCharSliceType()) + if(at->isCharSliceType()) out.push_back(this->GetArraySliceData(args[i])); else @@ -1096,29 +1078,6 @@ namespace fir } - Value* IRBuilder::CallVirtualMethod(ClassType* cls, FunctionType* ft, size_t index, const std::vector& args, const std::string& vname) - { - // args[0] must be the self, for obvious reasons. - auto ty = args[0]->getType(); - iceAssert(ty->isPointerType() && ty->getPointerElementType()->isClassType()); - - auto self = ty->getPointerElementType()->toClassType(); - iceAssert(self && self == cls); - - Instruction* instr = make_instr(OpKind::Value_CallVirtualMethod, true, ft->getReturnType(), - zfu::vectorOf( - ConstantValue::getZeroValue(cls), - ConstantInt::getNative(index), - ConstantValue::getZeroValue(ft) - ) + args - ); - - return this->addInstruction(instr, vname); - } - - - - @@ -1213,24 +1172,6 @@ namespace fir } - Value* IRBuilder::CreateSliceFromSAA(Value* saa, bool mut, const std::string& vname) - { - if(!isSAAType(saa->getType())) - error("irbuilder: expected string or dynamic array type, found '%s' instead", saa->getType()); - - auto slc = this->CreateValue(saa->getType()->isStringType() ? Type::getCharSlice(mut) - : ArraySliceType::get(saa->getType()->getArrayElementType(), mut)); - - auto slcelmty = slc->getType()->getArrayElementType(); - - slc = this->SetArraySliceData(slc, this->PointerTypeCast(this->GetSAAData(saa), mut ? slcelmty->getMutablePointerTo() - : slcelmty->getPointerTo())); - - slc = this->SetArraySliceLength(slc, this->GetSAALength(saa)); - slc->setName(vname); - - return slc; - } void IRBuilder::CondBranch(Value* condition, IRBlock* trueB, IRBlock* falseB) @@ -1308,25 +1249,13 @@ namespace fir if(structPtr->getType()->isStructType()) { auto st = structPtr->getType()->toStructType(); - return this->addInstruction(doGEPOnCompoundType(st, structPtr, memberIndex), vname); + return this->addInstruction(doGEPOnCompoundType(st, structPtr, memberIndex), vname); } else if(structPtr->getType()->isTupleType()) { auto tt = structPtr->getType()->toTupleType(); return this->addInstruction(doGEPOnCompoundType(tt, structPtr, memberIndex), vname); } - else if(structPtr->getType()->isClassType()) - { - error("irbuilder: classes do not support element access by index"); - - // auto ct = structPtr->getType()->toClassType(); - // // to compensate for the vtable, we add one to the index if there is a vtable! - // if(ct->getVirtualMethodCount() > 0) - // memberIndex += 1; - - // return this->addInstruction(doGEPOnCompoundType(ct, - // structPtr, memberIndex), vname); - } else { error("irbuilder: type '%s' is not a valid type to GEP into", structPtr->getType()); @@ -1350,23 +1279,6 @@ namespace fir return this->addInstruction(instr, memberName); } - else if(ptr->getType()->isClassType()) - { - auto ct = ptr->getType()->toClassType(); - - iceAssert(ct->hasElementWithName(memberName) && "no element with such name"); - auto memt = ct->getElement(memberName); - - //! VTABLE HANDLING - size_t vTableOfs = 0; - if(ct->getVirtualMethodCount() > 0) - vTableOfs = 1; - - Instruction* instr = make_instr(OpKind::Value_GetStructMember, false, memt, - { ptr, ConstantInt::getUNative(ct->getAbsoluteElementIndex(memberName) + vTableOfs) }, Value::Kind::lvalue); - - return this->addInstruction(instr, memberName); - } else { error("irbuilder: type '%s' is not a valid type to GEP into", ptr->getType()); @@ -1375,23 +1287,6 @@ namespace fir - void IRBuilder::SetVtable(Value* ptr, Value* table) - { - if(!ptr->islvalue()) - error("irbuilder: cannot do set vtable on non-lvalue"); - - auto ty = ptr->getType(); - if(!ty->isClassType()) error("irbuilder: '%s' is not a class type", ty); - if(table->getType() != Type::getInt8Ptr()) error("irbuilder: expected i8* for vtable, got '%s'", table->getType()); - - Instruction* instr = make_instr(OpKind::Value_GetStructMember, false, Type::getInt8Ptr(), { ptr, ConstantInt::getUNative(0) }, Value::Kind::lvalue); - - auto gep = this->addInstruction(instr, "__vtable"); - this->Store(table, gep); - } - - - // equivalent to GEP(ptr*, ptrIndex, elmIndex) Value* IRBuilder::ConstGEP2(Value* ptr, size_t ptrIndex, size_t elmIndex, const std::string& vname) @@ -1411,7 +1306,7 @@ namespace fir if(!ptr->getType()->isPointerType()) error("irbuilder: ptr is not a pointer type (got '%s')", ptr->getType()); - else if(ptr->getType()->getPointerElementType()->isClassType() || ptr->getType()->getPointerElementType()->isStructType()) + else if(ptr->getType()->getPointerElementType()->isStructType()) error("irbuilder: use the other function for struct types"); iceAssert(ptrIndex->getType()->isIntegerType() && "ptrIndex is not integer type"); @@ -1438,7 +1333,7 @@ namespace fir if(!ptrIndex->getType()->isIntegerType()) error("irbuilder: ptrIndex is not an integer type (got '%s')", ptrIndex->getType()); - if(ptr->getType()->getPointerElementType()->isClassType() || ptr->getType()->getPointerElementType()->isStructType()) + if(ptr->getType()->getPointerElementType()->isStructType()) error("irbuilder: use the other function for struct types"); Instruction* instr = make_instr(OpKind::Value_GetPointer, false, ptr->getType(), { ptr, ptrIndex }); @@ -1487,7 +1382,7 @@ namespace fir static Instruction* _insertValue(Value* val, size_t idx, Type* et, Value* elm) { Type* t = val->getType(); - if(!t->isStructType() && !t->isClassType() && !t->isTupleType() && !t->isArrayType()) + if(!t->isStructType() && !t->isTupleType() && !t->isArrayType()) error("irbuilder: val is not an aggregate type (have '%s')", t); if(elm->getType() != et) @@ -1496,12 +1391,7 @@ namespace fir elm->getType(), et); } - int ofs = 0; - //! VTABLE HANDLING - if(t->isClassType() && t->toClassType()->getVirtualMethodCount() > 0) - ofs = 1; - - std::vector args = { val, elm, ConstantInt::getNative(idx + ofs) }; + std::vector args = { val, elm, ConstantInt::getNative(idx) }; // note: no sideeffects, since we return a new aggregate return make_instr(OpKind::Value_InsertValue, false, t, args); @@ -1510,15 +1400,10 @@ namespace fir static Instruction* _extractValue(Value* val, size_t idx, Type* et) { Type* t = val->getType(); - if(!t->isStructType() && !t->isClassType() && !t->isTupleType() && !t->isArrayType()) + if(!t->isStructType() && !t->isTupleType() && !t->isArrayType()) error("irbuilder: val is not an aggregate type (have '%s')", t); - int ofs = 0; - //! VTABLE HANDLING - if(t->isClassType() && t->toClassType()->getVirtualMethodCount() > 0) - ofs = 1; - - std::vector args = { val, ConstantInt::getNative(idx + ofs) }; + std::vector args = { val, ConstantInt::getNative(idx) }; // note: no sideeffects, since we return a new aggregate return make_instr(OpKind::Value_ExtractValue, false, et, args); @@ -1532,9 +1417,6 @@ namespace fir Value* IRBuilder::InsertValue(Value* val, const std::vector& inds, Value* elm, const std::string& vname) { Type* t = val->getType(); - if(t->isClassType()) - error("irbuilder: classes do not support element access by index"); - if(!t->isStructType() && !t->isTupleType() && !t->isArrayType()) error("irbuilder: val is not a supported aggregate type (have '%s')", t); @@ -1554,15 +1436,12 @@ namespace fir Value* IRBuilder::ExtractValue(Value* val, const std::vector& inds, const std::string& vname) { Type* t = val->getType(); - if(!t->isStructType() && !t->isClassType() && !t->isTupleType() && !t->isArrayType()) + if(!t->isStructType() && !t->isTupleType() && !t->isArrayType()) error("irbuilder: val is not an aggregate type (have '%s')", t); if(inds.size() != 1) error("irbuilder: must have exactly one index!"); - if(t->isClassType()) - error("irbuilder: classes do not support element access by index"); - Type* et = 0; if(t->isStructType()) et = t->toStructType()->getElementN(inds[0]); else if(t->isTupleType()) et = t->toTupleType()->getElementN(inds[0]); @@ -1576,13 +1455,12 @@ namespace fir Value* IRBuilder::InsertValueByName(Value* val, const std::string& n, Value* elm, const std::string& vname) { Type* t = val->getType(); - if(!t->isStructType() && !t->isClassType()) - error("irbuilder: val is not an aggregate type with named members (class or struct) (have '%s')", t); + if(!t->isStructType()) + error("irbuilder: val is not an aggregate type with named members (struct) (have '%s')", t); size_t ind = 0; Type* et = 0; if(t->isStructType()) ind = t->toStructType()->getElementIndex(n), et = t->toStructType()->getElement(n); - else if(t->isClassType()) ind = t->toClassType()->getAbsoluteElementIndex(n), et = t->toClassType()->getElement(n); else iceAssert(0); return this->addInstruction(_insertValue(val, ind, et, elm), vname); @@ -1591,13 +1469,12 @@ namespace fir Value* IRBuilder::ExtractValueByName(Value* val, const std::string& n, const std::string& vname) { Type* t = val->getType(); - if(!t->isStructType() && !t->isClassType()) - error("irbuilder: val is not an aggregate type with named members (class or struct) (have '%s')", t); + if(!t->isStructType()) + error("irbuilder: val is not an aggregate type with named members (struct) (have '%s')", t); size_t ind = 0; Type* et = 0; if(t->isStructType()) ind = t->toStructType()->getElementIndex(n), et = t->toStructType()->getElement(n); - else if(t->isClassType()) ind = t->toClassType()->getAbsoluteElementIndex(n), et = t->toClassType()->getElement(n); else iceAssert(0); return this->addInstruction(_extractValue(val, ind, et), vname); @@ -1614,133 +1491,6 @@ namespace fir - Value* IRBuilder::GetSAAData(Value* arr, const std::string& vname) - { - if(!isSAAType(arr->getType())) - error("irbuilder: thing is not an SAA type (got '%s')", arr->getType()); - - Instruction* instr = make_instr(OpKind::SAA_GetData, false, getSAAElmType(arr->getType())->getMutablePointerTo(), { arr }); - - return this->addInstruction(instr, vname); - } - - Value* IRBuilder::SetSAAData(Value* arr, Value* val, const std::string& vname) - { - if(!isSAAType(arr->getType())) - error("irbuilder: thing is not an SAA type (got '%s')", arr->getType()); - - auto t = getSAAElmType(arr->getType()); - if(val->getType() != t->getMutablePointerTo()) - { - error("irbuilder: val is not a pointer to elm type (need '%s', have '%s')", - t->getMutablePointerTo(), val->getType()); - } - - Instruction* instr = make_instr(OpKind::SAA_SetData, true, arr->getType(), { arr, val }); - - return this->addInstruction(instr, vname); - } - - - - Value* IRBuilder::GetSAALength(Value* arr, const std::string& vname) - { - if(!isSAAType(arr->getType())) - error("irbuilder: thing is not an SAA type (got '%s')", arr->getType()); - - Instruction* instr = make_instr(OpKind::SAA_GetLength, false, Type::getNativeWord(), { arr }); - - return this->addInstruction(instr, vname); - } - - Value* IRBuilder::SetSAALength(Value* arr, Value* val, const std::string& vname) - { - if(!isSAAType(arr->getType())) - error("irbuilder: thing is not an SAA type (got '%s')", arr->getType()); - - if(val->getType() != Type::getNativeWord()) - error("irbuilder: val is not an int64"); - - Instruction* instr = make_instr(OpKind::SAA_SetLength, true, arr->getType(), { arr, val }); - - return this->addInstruction(instr, vname); - } - - - - Value* IRBuilder::GetSAACapacity(Value* arr, const std::string& vname) - { - if(!isSAAType(arr->getType())) - error("irbuilder: thing is not an SAA type (got '%s')", arr->getType()); - - Instruction* instr = make_instr(OpKind::SAA_GetCapacity, false, Type::getNativeWord(), { arr }); - - return this->addInstruction(instr, vname); - } - - Value* IRBuilder::SetSAACapacity(Value* arr, Value* val, const std::string& vname) - { - if(!isSAAType(arr->getType())) - error("irbuilder: thing is not an SAA type (got '%s')", arr->getType()); - - if(val->getType() != Type::getNativeWord()) - error("irbuilder: val is not an int64"); - - Instruction* instr = make_instr(OpKind::SAA_SetCapacity, true, arr->getType(), { arr, val }); - - return this->addInstruction(instr, vname); - } - - - - Value* IRBuilder::GetSAARefCountPointer(Value* arr, const std::string& vname) - { - if(!isSAAType(arr->getType())) - error("irbuilder: thing is not an SAA type (got '%s')", arr->getType()); - - Instruction* instr = make_instr(OpKind::SAA_GetRefCountPtr, false, Type::getNativeWordPtr(), { arr }); - - return this->addInstruction(instr, vname); - } - - Value* IRBuilder::SetSAARefCountPointer(Value* arr, Value* val, const std::string& vname) - { - if(!isSAAType(arr->getType())) - error("irbuilder: thing is not an SAA type (got '%s')", arr->getType()); - - if(val->getType() != Type::getNativeWord()->getPointerTo()) - error("irbuilder: val is not an int64 pointer"); - - Instruction* instr = make_instr(OpKind::SAA_SetRefCountPtr, true, arr->getType(), { arr, val }); - - return this->addInstruction(instr, vname); - } - - - - Value* IRBuilder::GetSAARefCount(Value* arr, const std::string& vname) - { - return this->ReadPtr(this->GetSAARefCountPointer(arr), vname); - } - - void IRBuilder::SetSAARefCount(Value* arr, Value* val) - { - if(val->getType() != Type::getNativeWord()) - error("irbuilder: val is not an int64"); - - this->WritePtr(val, this->PointerTypeCast(this->GetSAARefCountPointer(arr), Type::getNativeWordPtr()->getMutablePointerVersion())); - } - - - - - - - - - - - @@ -1816,99 +1566,6 @@ namespace fir - Value* IRBuilder::GetAnyTypeID(Value* any, const std::string& vname) - { - if(!any->getType()->isAnyType()) - error("irbuilder: not any type (got '%s')", any->getType()); - - Instruction* instr = make_instr(OpKind::Any_GetTypeID, false, Type::getNativeUWord(), { any }); - - return this->addInstruction(instr, vname); - } - - Value* IRBuilder::SetAnyTypeID(Value* any, Value* val, const std::string& vname) - { - if(!any->getType()->isAnyType()) - error("irbuilder: not any type (got '%s')", any->getType()); - - else if(val->getType() != Type::getNativeUWord()) - error("irbuilder: val is not a uint64"); - - Instruction* instr = make_instr(OpKind::Any_SetTypeID, true, Type::getAny(), { any, val }); - - return this->addInstruction(instr, vname); - } - - - Value* IRBuilder::GetAnyData(Value* any, const std::string& vname) - { - if(!any->getType()->isAnyType()) - error("irbuilder: not any type (got '%s')", any->getType()); - - Instruction* instr = make_instr(OpKind::Any_GetData, false, ArrayType::get(Type::getInt8(), - BUILTIN_ANY_DATA_BYTECOUNT), { any }); - - return this->addInstruction(instr, vname); - } - - Value* IRBuilder::SetAnyData(Value* any, Value* val, const std::string& vname) - { - if(!any->getType()->isAnyType()) - error("irbuilder: not any type (got '%s')", any->getType()); - - else if(val->getType() != ArrayType::get(Type::getInt8(), BUILTIN_ANY_DATA_BYTECOUNT)) - error("irbuilder: val is not array type (got '%s')", val->getType()); - - Instruction* instr = make_instr(OpKind::Any_SetData, true, Type::getAny(), { any, val }); - - return this->addInstruction(instr, vname); - } - - - Value* IRBuilder::GetAnyRefCountPointer(Value* arr, const std::string& vname) - { - if(!arr->getType()->isAnyType()) - error("irbuilder: arr is not an any type (got '%s')", arr->getType()); - - Instruction* instr = make_instr(OpKind::Any_GetRefCountPtr, false, Type::getNativeWordPtr(), { arr }); - - return this->addInstruction(instr, vname); - } - - Value* IRBuilder::SetAnyRefCountPointer(Value* arr, Value* val, const std::string& vname) - { - if(!arr->getType()->isAnyType()) - error("irbuilder: arr is not an any type (got '%s')", arr->getType()); - - if(val->getType() != Type::getNativeWord()->getPointerTo()) - error("irbuilder: val is not an int64 pointer"); - - Instruction* instr = make_instr(OpKind::Any_SetRefCountPtr, true, arr->getType(), { arr, val }); - - return this->addInstruction(instr, vname); - } - - - - Value* IRBuilder::GetAnyRefCount(Value* arr, const std::string& vname) - { - return this->ReadPtr(this->GetAnyRefCountPointer(arr), vname); - } - - void IRBuilder::SetAnyRefCount(Value* arr, Value* val) - { - if(val->getType() != Type::getNativeWord()) - error("irbuilder: val is not an int64"); - - this->WritePtr(val, this->PointerTypeCast(this->GetAnyRefCountPointer(arr), - Type::getNativeWordPtr()->getMutablePointerVersion())); - } - - - - - - @@ -2240,14 +1897,7 @@ namespace fir { IRBlock* block = new IRBlock(func); if(func != this->currentFunction) - { - // warn("changing current function in irbuilder (from %s to %s)", - // (this->currentFunction ? this->currentFunction->getName().str() : "null"), - // func->getName() - // ); - this->currentFunction = block->parentFunction; - } this->currentFunction->blocks.push_back(block); @@ -2263,15 +1913,7 @@ namespace fir { IRBlock* nb = new IRBlock(block->parentFunction); if(nb->parentFunction != this->currentFunction) - { - // warn("changing current function in irbuilder (from %s to %s)", - // (this->currentFunction ? this->currentFunction->getName().str() : "null"), - // nb->parentFunction->getName() - // ); - - this->currentFunction = nb->parentFunction; - } for(size_t i = 0; i < this->currentFunction->blocks.size(); i++) { diff --git a/source/fir/Instruction.cpp b/source/fir/Instruction.cpp index 933ce9bb..365f7fa7 100644 --- a/source/fir/Instruction.cpp +++ b/source/fir/Instruction.cpp @@ -112,7 +112,6 @@ namespace fir case OpKind::Value_StackAlloc: instrname = "stackAlloc"; break; case OpKind::Value_CallFunction: instrname = "call"; break; case OpKind::Value_CallFunctionPointer: instrname = "callfp"; break; - case OpKind::Value_CallVirtualMethod: instrname = "callvirtual"; break; case OpKind::Value_Return: instrname = "ret"; break; case OpKind::Value_GetPointerToStructMember: instrname = "gep"; break; case OpKind::Value_GetStructMember: instrname = "gep"; break; @@ -127,28 +126,11 @@ namespace fir case OpKind::Value_CreatePHI: instrname = "phi"; break; - case OpKind::SAA_GetData: instrname = "get_saa.data"; break; - case OpKind::SAA_SetData: instrname = "set_saa.data"; break; - case OpKind::SAA_GetLength: instrname = "get_saa.len"; break; - case OpKind::SAA_SetLength: instrname = "set_saa.len"; break; - case OpKind::SAA_GetCapacity: instrname = "get_saa.cap"; break; - case OpKind::SAA_SetCapacity: instrname = "set_saa.cap"; break; - case OpKind::SAA_GetRefCountPtr: instrname = "get_saa.rc_ptr"; break; - case OpKind::SAA_SetRefCountPtr: instrname = "set_saa.rc_ptr"; break; - - case OpKind::ArraySlice_GetData: instrname = "get_slice.data"; break; case OpKind::ArraySlice_SetData: instrname = "set_slice.data"; break; case OpKind::ArraySlice_GetLength: instrname = "get_slice.len"; break; case OpKind::ArraySlice_SetLength: instrname = "set_slice.len"; break; - case OpKind::Any_GetData: instrname = "get_any.data"; break; - case OpKind::Any_SetData: instrname = "set_any.data"; break; - case OpKind::Any_GetTypeID: instrname = "get_any.typeid"; break; - case OpKind::Any_SetTypeID: instrname = "set_any.typeid"; break; - case OpKind::Any_GetRefCountPtr: instrname = "get_any.rc_ptr"; break; - case OpKind::Any_SetRefCountPtr: instrname = "set_any.rc_ptr"; break; - case OpKind::Range_GetLower: instrname = "get_range.lower"; break; case OpKind::Range_SetLower: instrname = "set_range.lower"; break; case OpKind::Range_GetUpper: instrname = "get_range.upper"; break; diff --git a/source/fir/Module.cpp b/source/fir/Module.cpp index cfe6b706..b877e2cf 100644 --- a/source/fir/Module.cpp +++ b/source/fir/Module.cpp @@ -107,35 +107,6 @@ namespace fir - GlobalVariable* Module::getOrCreateVirtualTableForClass(ClassType* cls) - { - if(this->vtables.find(cls) == this->vtables.end()) - { - auto fmethods = std::vector(cls->virtualMethodCount); - auto methods = std::vector(cls->virtualMethodCount); - - for(auto meth : cls->reverseVirtualMethodMap) - { - methods[meth.first] = ConstantBitcast::get(meth.second, FunctionType::get({ }, Type::getVoid())); - fmethods[meth.first] = meth.second; - } - - //! ACHTUNG ! - // TODO: should we make the vtable immutable? - - auto table = ConstantArray::get(ArrayType::get(FunctionType::get({ }, Type::getVoid()), cls->virtualMethodCount), methods); - auto vtab = this->createGlobalVariable(Name::obfuscate("vtable", cls->getTypeName().mangled()), - table->getType(), table, true, LinkageType::External); - - this->vtables[cls] = { fmethods, vtab }; - } - - return this->vtables[cls].second; - } - - - - @@ -334,7 +305,6 @@ namespace fir // should just automatically create it. std::string tl; if(type.second->isStructType()) tl = fir::Type::typeListToString(type.second->toStructType()->getElements()); - else if(type.second->isClassType()) tl = fir::Type::typeListToString(type.second->toClassType()->getElements()); else if(type.second->isTupleType()) tl = fir::Type::typeListToString(type.second->toTupleType()->getElements()); diff --git a/source/fir/Name.cpp b/source/fir/Name.cpp index 67267c07..f49a6f8f 100644 --- a/source/fir/Name.cpp +++ b/source/fir/Name.cpp @@ -91,10 +91,6 @@ namespace fir { return "FA" + lentypestr(mangleType(t->getArrayElementType())) + std::to_string(t->toArrayType()->getArraySize()); } - else if(t->isDynamicArrayType()) - { - return "DA" + lentypestr(mangleType(t->getArrayElementType())); - } else if(t->isArraySliceType()) { return "SL" + lentypestr(mangleType(t->getArrayElementType())); @@ -120,10 +116,6 @@ namespace fir { return lentypestr(mangleScopeName(t->toStructType()->getTypeName())); } - else if(t->isClassType()) - { - return lentypestr(mangleScopeName(t->toClassType()->getTypeName())); - } else if(t->isTupleType()) { std::string ret = "ST" + std::to_string(t->toTupleType()->getElementCount()) + "SM"; @@ -136,10 +128,6 @@ namespace fir { return "PT" + lentypestr(mangleType(t->getPointerElementType())); } - else if(t->isStringType()) - { - return "SR"; - } else if(t->isCharType()) { return "CH"; @@ -148,10 +136,6 @@ namespace fir { return "EN" + lentypestr(mangleType(t->toEnumType()->getCaseType())) + lentypestr(mangleScopeName(t->toEnumType()->getTypeName())); } - else if(t->isAnyType()) - { - return "AY"; - } else { _error_and_exit("unsupported ir type??? ('%s')\n", t); diff --git a/source/fir/Types/ClassType.cpp b/source/fir/Types/ClassType.cpp deleted file mode 100644 index 54796e7b..00000000 --- a/source/fir/Types/ClassType.cpp +++ /dev/null @@ -1,416 +0,0 @@ -// ClassType.cpp -// Copyright (c) 2014 - 2016, zhiayang -// Licensed under the Apache License Version 2.0. - -#include "errors.h" -#include "ir/type.h" -#include "ir/function.h" - -namespace fir -{ - // structs - ClassType::ClassType(const Name& name, const std::vector>& mems, const std::vector& methods, - const std::vector& inits) : Type(TypeKind::Class), className(name) - { - this->setMembers(mems); - this->setMethods(methods); - this->setInitialiserFunctions(inits); - } - - static util::hash_map typeCache; - ClassType* ClassType::create(const Name& name, const std::vector>& members, - const std::vector& methods, const std::vector& inits) - { - if(auto it = typeCache.find(name); it != typeCache.end()) - error("class with name '%s' already exists", name.str()); - - else - return (typeCache[name] = new ClassType(name, members, methods, inits)); - } - - ClassType* ClassType::createWithoutBody(const Name& name) - { - return ClassType::create(name, { }, { }, { }); - } - - - - - - - // various - std::string ClassType::str() - { - return "class(" + this->className.name + ")"; - } - - std::string ClassType::encodedStr() - { - return this->className.str(); - } - - - bool ClassType::isTypeEqual(Type* other) - { - if(other->kind != TypeKind::Class) - return false; - - return this->className == other->toClassType()->className; - } - - - - // struct stuff - Name ClassType::getTypeName() - { - return this->className; - } - - size_t ClassType::getElementCount() - { - return this->typeList.size(); - } - - Type* ClassType::getElement(const std::string& name) - { - auto cls = this; - while(cls->classMembers.find(name) == cls->classMembers.end()) - cls = cls->baseClass; - - iceAssert(cls && "no such member"); - return cls->classMembers[name]; - } - - size_t ClassType::getAbsoluteElementIndex(const std::string& name) - { - auto cls = this; - while(cls->classMembers.find(name) == cls->classMembers.end()) - cls = cls->baseClass; - - iceAssert(cls && "no such member"); - - return cls->indexMap[name]; - } - - void ClassType::setMembers(const std::vector>& members) - { - size_t i = 0; - { - auto cls = this->baseClass; - while(cls) - { - i += cls->getElementCount(); - cls = cls->baseClass; - } - } - - for(const auto& [ name, ty ] : members) - { - this->classMembers[name] = ty; - this->indexMap[name] = i; - - this->nameList.push_back(name); - this->typeList.push_back(ty); - - i++; - } - } - - bool ClassType::hasElementWithName(const std::string& name) - { - auto cls = this; - while(cls && cls->classMembers.find(name) == cls->classMembers.end()) - cls = cls->baseClass; - - return cls != 0; - } - - - - const std::vector& ClassType::getElements() - { - return this->typeList; - } - - const std::vector& ClassType::getNameList() - { - return this->nameList; - } - - std::vector ClassType::getAllElementsIncludingBase() - { - std::vector ret; - - std::function*)> - addMembers = [&addMembers](ClassType* cls, std::vector* mems) -> void { - - if(!cls) return; - - addMembers(cls->getBaseClass(), mems); - - for(auto f : cls->getElements()) - mems->push_back(f); - }; - - addMembers(this, &ret); - - return ret; - } - - const util::hash_map& ClassType::getElementNameMap() - { - return this->indexMap; - } - - - - - - - - - const std::vector& ClassType::getInitialiserFunctions() - { - return this->initialiserList; - } - - void ClassType::setDestructor(Function* f) - { - this->destructor = f; - } - - void ClassType::setCopyConstructor(Function* f) - { - this->copyConstructor = f; - } - - void ClassType::setMoveConstructor(Function* f) - { - this->moveConstructor = f; - } - - - Function* ClassType::getDestructor() - { - return this->destructor; - } - - Function* ClassType::getCopyConstructor() - { - return this->copyConstructor; - } - - Function* ClassType::getMoveConstructor() - { - return this->moveConstructor; - } - - - - - const std::vector& ClassType::getMethods() - { - return this->methodList; - } - - std::vector ClassType::getMethodsWithName(const std::string& id) - { - auto l = this->classMethodMap[id]; - - std::vector ret; - ret.reserve(l.size()); - - for(auto f : l) - ret.push_back(f); - - return ret; - } - - Function* ClassType::getMethodWithType(FunctionType* ftype) - { - for(auto f : this->methodList) - { - if(f->getType() == ftype) - return f; - } - - error("no method with type '%s'", ftype); - } - - - bool ClassType::hasParent(Type* base) - { - auto target = dcast(ClassType, base); - if(!target) return false; - - auto cls = this; - while(cls) - { - if(target == cls) return true; - - cls = cls->baseClass; - } - - return false; - } - - - void ClassType::setMethods(const std::vector& methods) - { - for(auto m : methods) - { - this->methodList.push_back(m); - this->classMethodMap[m->getName().name].push_back(m); - } - } - - - void ClassType::setInitialiserFunctions(const std::vector& inits) - { - for(auto m : inits) - { - this->initialiserList.push_back(m); - this->classMethodMap[m->getName().name].push_back(m); - } - } - - - void ClassType::addTraitImpl(TraitType* trt) - { - if(zfu::contains(this->implTraits, trt)) - error("'%s' already implements trait '%s'", this, trt); - - this->implTraits.push_back(trt); - } - - bool ClassType::implementsTrait(TraitType* trt) - { - return zfu::contains(this->implTraits, trt); - } - - std::vector ClassType::getImplementedTraits() - { - return this->implTraits; - } - - - ClassType* ClassType::getBaseClass() - { - return this->baseClass; - } - - void ClassType::setBaseClass(ClassType* ty) - { - this->baseClass = ty; - - //* keeps things simple. - iceAssert(this->virtualMethodMap.empty() || !"cannot set base class after adding virtual methods"); - - this->virtualMethodMap = this->baseClass->virtualMethodMap; - this->virtualMethodCount = this->baseClass->virtualMethodCount; - this->reverseVirtualMethodMap = this->baseClass->reverseVirtualMethodMap; - } - - - void ClassType::addVirtualMethod(Function* method) - { - //* note: the 'reverse' virtual method map is to allow us, at translation time, to easily create the vtable without - //* unnecessary searching. When we set a base class, we copy its 'reverse' map; thus, if we don't override anything, - //* our vtable will just refer to the methods in the base class. - - //* but if we do override something, we just set the method in our 'reverse' map, which is what we'll use to build - //* the vtable. simple? - - auto list = zfu::drop(method->getType()->toFunctionType()->getArgumentTypes(), 1); - - // check every member of the current mapping -- not the fastest method i admit. - bool found = false; - for(const auto& vm : this->virtualMethodMap) - { - if(vm.first.first == method->getName().name && areTypeListsContravariant(vm.first.second, list, /* trait checking: */ false)) - { - found = true; - this->virtualMethodMap[{ method->getName().name, list }] = vm.second; - this->reverseVirtualMethodMap[vm.second] = method; - break; - } - } - - if(!found) - { - // just make a new one. - this->virtualMethodMap[{ method->getName().name, list }] = this->virtualMethodCount; - this->reverseVirtualMethodMap[this->virtualMethodCount] = method; - this->virtualMethodCount++; - } - } - - size_t ClassType::getVirtualMethodIndex(const std::string& name, FunctionType* ft) - { - auto withoutself = [](std::vector p) -> std::vector { - p.erase(p.begin()); - return p; - }; - - auto list = ft->getArgumentTypes(); - - if(auto it = this->virtualMethodMap.find({ name, withoutself(list) }); it != this->virtualMethodMap.end()) - { - return it->second; - } - else - { - error("no method named '%s' matching signature '%s' in virtual method table of class '%s'", - name, ft, this->getTypeName().name); - } - } - - size_t ClassType::getVirtualMethodCount() - { - return this->virtualMethodCount; - } - - - Function* ClassType::getInlineInitialiser() - { - return this->inlineInitialiser; - } - - void ClassType::setInlineInitialiser(Function* fn) - { - this->inlineInitialiser = fn; - } - - - Function* ClassType::getInlineDestructor() - { - return this->inlineDestructor; - } - - void ClassType::setInlineDestructor(Function* fn) - { - this->inlineDestructor = fn; - } - - - fir::Type* ClassType::substitutePlaceholders(const util::hash_map& subst) - { - if(this->containsPlaceholders()) - error("not supported!"); - - return this; - } -} - - - - - - - - - - - - - diff --git a/source/fir/Types/DynamicArrayType.cpp b/source/fir/Types/DynamicArrayType.cpp deleted file mode 100644 index 823ddbe4..00000000 --- a/source/fir/Types/DynamicArrayType.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// DynamicArrayType.cpp -// Copyright (c) 2014 - 2016, zhiayang -// Licensed under the Apache License Version 2.0. - -#include "ir/type.h" -#include "errors.h" - -namespace fir -{ - DynamicArrayType::DynamicArrayType(Type* elmType) : Type(TypeKind::DynamicArray) - { - this->arrayElementType = elmType; - } - - Type* DynamicArrayType::getElementType() - { - return this->arrayElementType; - } - - std::string DynamicArrayType::str() - { - return strprintf("[%s]", this->arrayElementType->str()); - } - - std::string DynamicArrayType::encodedStr() - { - return strprintf("[%s]", this->arrayElementType->encodedStr()); - } - - bool DynamicArrayType::isTypeEqual(Type* other) - { - if(other->kind != TypeKind::DynamicArray) - return false; - - return this->arrayElementType->isTypeEqual(other->toDynamicArrayType()->arrayElementType); - } - - DynamicArrayType* DynamicArrayType::get(Type* elementType) - { - return TypeCache::get().getOrAddCachedType(new DynamicArrayType(elementType)); - } - - fir::Type* DynamicArrayType::substitutePlaceholders(const util::hash_map& subst) - { - return DynamicArrayType::get(this->arrayElementType->substitutePlaceholders(subst)); - } -} - - - - - - - - - - - - - - - - - - - - - - - diff --git a/source/fir/Types/PrimitiveType.cpp b/source/fir/Types/PrimitiveType.cpp index c049ce1e..a76009d3 100644 --- a/source/fir/Types/PrimitiveType.cpp +++ b/source/fir/Types/PrimitiveType.cpp @@ -154,8 +154,8 @@ namespace fir if(this->primKind == Kind::Integer) { - if(this->isSigned()) ret = "i"; - else ret = "u"; + if(this->isSigned()) ret = "i"; + else ret = "u"; ret += std::to_string(this->getIntegerBitWidth()); } diff --git a/source/fir/Types/SingleTypes.cpp b/source/fir/Types/SingleTypes.cpp index c1e295da..737e76bb 100644 --- a/source/fir/Types/SingleTypes.cpp +++ b/source/fir/Types/SingleTypes.cpp @@ -9,15 +9,6 @@ namespace fir { using PolySubst = util::hash_map; - static AnyType* singleAny = 0; - AnyType::AnyType() : Type(TypeKind::Any) { } - std::string AnyType::str() { return "any"; } - std::string AnyType::encodedStr() { return "any"; } - bool AnyType::isTypeEqual(Type* other) { return other && other->isAnyType(); } - AnyType* AnyType::get() { return singleAny = (singleAny ? singleAny : new AnyType()); } - fir::Type* AnyType::substitutePlaceholders(const PolySubst&) { return this; } - - static BoolType* singleBool = 0; BoolType::BoolType() : Type(TypeKind::Bool) { } std::string BoolType::str() { return "bool"; } @@ -54,98 +45,6 @@ namespace fir fir::Type* RangeType::substitutePlaceholders(const PolySubst&) { return this; } - static StringType* singleString = 0; - StringType::StringType() : Type(TypeKind::String) { } - std::string StringType::str() { return "string"; } - std::string StringType::encodedStr() { return "string"; } - bool StringType::isTypeEqual(Type* other) { return other && other->isStringType(); } - StringType* StringType::get() { return singleString = (singleString ? singleString : new StringType()); } - fir::Type* StringType::substitutePlaceholders(const PolySubst&) { return this; } - - - - - - - std::string ConstantNumberType::encodedStr() { return "number"; } - bool ConstantNumberType::isSigned() { return this->_signed; } - bool ConstantNumberType::isFloating() { return this->_floating; } - size_t ConstantNumberType::getMinBits() { return this->_bits; } - bool ConstantNumberType::isTypeEqual(Type* other) - { - return other && other->isConstantNumberType() - && other->toConstantNumberType()->_bits == this->_bits - && other->toConstantNumberType()->_signed == this->_signed - && other->toConstantNumberType()->_floating == this->_floating; - } - ConstantNumberType* ConstantNumberType::get(bool neg, bool flt, size_t bits) - { - return TypeCache::get().getOrAddCachedType(new ConstantNumberType(neg, flt, bits)); - } - ConstantNumberType::ConstantNumberType(bool neg, bool flt, size_t bits) : Type(TypeKind::ConstantNumber) - { - this->_bits = bits; - this->_signed = neg; - this->_floating = flt; - } - fir::Type* ConstantNumberType::substitutePlaceholders(const PolySubst& subst) - { - return this; - } - std::string ConstantNumberType::str() - { - // return strprintf("number(sgn: %s, flt: %s, bits: %d)", _signed, _floating, _bits); - return strprintf("number"); - } - - - - - ConstantNumberType* unifyConstantTypes(ConstantNumberType* a, ConstantNumberType* b) - { - auto sgn = a->isSigned() || b->isSigned(); - auto flt = a->isFloating() || b->isFloating(); - auto bit = std::max(a->getMinBits(), b->getMinBits()); - - return ConstantNumberType::get(sgn, flt, bit); - } - - Type* getBestFitTypeForConstant(ConstantNumberType* cnt) - { - if(cnt->isFloating()) - { - if(cnt->getMinBits() > 64) - error("constant number type '%s' requires too many bits", cnt); - - return fir::Type::getFloat64(); - } - else - { - if(cnt->getMinBits() < fir::Type::getNativeWord()->getBitWidth()) - { - return fir::Type::getNativeWord(); - } - else if(cnt->isSigned()) - { - error("constant number type '%s' requires too many bits", cnt); - } - else - { - if(cnt->getMinBits() > fir::Type::getNativeUWord()->getBitWidth()) - error("constant number type '%s' requires too many bits", cnt); - - return fir::Type::getNativeUWord(); - } - } - } - - - - - - - - std::string PolyPlaceholderType::str() { return strprintf("$%s/%d", this->name, this->group); } std::string PolyPlaceholderType::encodedStr() { return strprintf("$%s/%d", this->name, this->group); } @@ -167,9 +66,6 @@ namespace fir bool PolyPlaceholderType::isTypeEqual(Type* other) { - // return other && other->isPolyPlaceholderType() && other->toPolyPlaceholderType()->name == this->name - // && other->toPolyPlaceholderType()->group == this->group; - //! ACHTUNG ! // performance optimisation: since all polys go through ::get, and we already guarantee interning // from that function, we should be able to just compare pointers. diff --git a/source/fir/Types/Type.cpp b/source/fir/Types/Type.cpp index b39d5c9d..acd035e6 100644 --- a/source/fir/Types/Type.cpp +++ b/source/fir/Types/Type.cpp @@ -42,22 +42,7 @@ namespace fir { if(from == to) return 0; - if(from->isConstantNumberType() && to->isPrimitiveType()) - { - auto cty = from->toConstantNumberType(); - if(!cty->isFloating() && to->isIntegerType()) - return 0; - - else if(!cty->isFloating() && to->isFloatingPointType()) - return 1; - - else if(cty->isFloating()) // not isint means isfloat, so if we're doing float -> float the cost is 0 - return 0; - - else // if we reach here, we're trying to do float -> int, which is a no-go. - return -1; - } - else if(from->isIntegerType() && to->isIntegerType()) + if(from->isIntegerType() && to->isIntegerType()) { if(from->isSignedIntType() == to->isSignedIntType()) { @@ -66,16 +51,16 @@ namespace fir switch(bitdiff) { - case 0: return 0; // same - case 8: return 1; // i16 - i8 - case 16: return 1; // i32 - i16 - case 32: return 1; // i64 - i32 + case 0: return 0; // same + case 8: return 1; // i16 - i8 + case 16: return 1; // i32 - i16 + case 32: return 1; // i64 - i32 - case 24: return 2; // i32 - i8 - case 48: return 2; // i64 - i16 + case 24: return 2; // i32 - i8 + case 48: return 2; // i64 - i16 - case 56: return 3; // i64 - i8 - default: iceAssert(0); + case 56: return 3; // i64 - i8 + default: iceAssert(0); } } else @@ -87,26 +72,10 @@ namespace fir return -1; } } - else if(from->isDynamicArrayType() && to->isArraySliceType() && from->getArrayElementType() == to->getArrayElementType()) - { - return 2; - } - else if(from->isDynamicArrayType() && from->getArrayElementType()->isVoidType() && (to->isDynamicArrayType() || to->isArraySliceType() || to->isArrayType())) - { - return 2; - } else if(from->isFloatingPointType() && to->isFloatingPointType()) { return 1; } - else if(from->isStringType() && to == fir::Type::getInt8Ptr()) - { - return 5; - } - else if(from->isStringType() && to->isCharSliceType()) - { - return 3; - } else if(from->isCharSliceType() && to == fir::Type::getInt8Ptr()) { return 3; @@ -127,13 +96,6 @@ namespace fir // same with slices -- cast from mutable slice to immut slice can be implicit. return 1; } - //* note: we don't need to check that 'to' is a class type, because if it's not then the parent check will fail anyway. - else if(from->isPointerType() && to->isPointerType() && from->getPointerElementType()->isClassType() - && from->getPointerElementType()->toClassType()->hasParent(to->getPointerElementType())) - { - // cast from a derived class pointer to a base class pointer - return 2; - } else if(from->isNullType() && to->isPointerType()) { return 1; @@ -156,11 +118,6 @@ namespace fir return sum; } - else if(to->isAnyType()) - { - // lol. completely arbitrary. - return 15; - } return -1; } @@ -331,8 +288,6 @@ namespace fir else if(copy == FLOAT64_TYPE_STRING) real = Type::getFloat64(); else if(copy == FLOAT128_TYPE_STRING) real = Type::getFloat128(); - else if(copy == STRING_TYPE_STRING) real = Type::getString(); - else if(copy == CHARACTER_SLICE_TYPE_STRING) real = ArraySliceType::get(Type::getInt8(), false); else if(copy == BOOL_TYPE_STRING) real = Type::getBool(); @@ -345,8 +300,6 @@ namespace fir else if(copy == FLOAT_TYPE_STRING) real = Type::getFloat32(); else if(copy == DOUBLE_TYPE_STRING) real = Type::getFloat64(); - else if(copy == ANY_TYPE_STRING) real = Type::getAny(); - else return 0; iceAssert(real); @@ -359,10 +312,9 @@ namespace fir Type* Type::getArrayElementType() { - if(this->isDynamicArrayType()) return this->toDynamicArrayType()->getElementType(); - else if(this->isArrayType()) return this->toArrayType()->getElementType(); - else if(this->isArraySliceType()) return this->toArraySliceType()->getElementType(); - else error("'%s' is not an array type", this); + if(this->isArrayType()) return this->toArrayType()->getElementType(); + else if(this->isArraySliceType()) return this->toArraySliceType()->getElementType(); + else error("'%s' is not an array type", this); } @@ -398,7 +350,6 @@ namespace fir else if(ty->isPointerType()) return _containsPlaceholders(ty->getPointerElementType(), seen, found); else if(ty->isArrayType()) return _containsPlaceholders(ty->getArrayElementType(), seen, found); else if(ty->isArraySliceType()) return _containsPlaceholders(ty->getArrayElementType(), seen, found); - else if(ty->isDynamicArrayType()) return _containsPlaceholders(ty->getArrayElementType(), seen, found); else if(ty->isArrayType()) return _containsPlaceholders(ty->getArrayElementType(), seen, found); else if(ty->isUnionVariantType()) return _containsPlaceholders(ty->toUnionVariantType()->getInteriorType(), seen, found); else if(ty->isTupleType()) @@ -409,14 +360,6 @@ namespace fir return res; } - else if(ty->isClassType()) - { - bool res = false; - for(auto t : ty->toClassType()->getElements()) - res |= _containsPlaceholders(t, seen, found); - - return res; - } else if(ty->isStructType()) { bool res = false; @@ -500,12 +443,6 @@ namespace fir return static_cast(this); } - ClassType* Type::toClassType() - { - if(this->kind != TypeKind::Class) error("not class type"); - return static_cast(this); - } - TupleType* Type::toTupleType() { if(this->kind != TypeKind::Tuple) error("not tuple type"); @@ -518,12 +455,6 @@ namespace fir return static_cast(this); } - DynamicArrayType* Type::toDynamicArrayType() - { - if(this->kind != TypeKind::DynamicArray) error("not dynamic array type"); - return static_cast(this); - } - ArraySliceType* Type::toArraySliceType() { if(this->kind != TypeKind::ArraySlice) error("not array slice type"); @@ -536,12 +467,6 @@ namespace fir return static_cast(this); } - StringType* Type::toStringType() - { - if(this->kind != TypeKind::String) error("not string type"); - return static_cast(this); - } - EnumType* Type::toEnumType() { if(this->kind != TypeKind::Enum) error("not enum type"); @@ -560,24 +485,12 @@ namespace fir return static_cast(this); } - AnyType* Type::toAnyType() - { - if(this->kind != TypeKind::Any) error("not any type"); - return static_cast(this); - } - NullType* Type::toNullType() { if(this->kind != TypeKind::Null) error("not null type"); return static_cast(this); } - ConstantNumberType* Type::toConstantNumberType() - { - if(this->kind != TypeKind::ConstantNumber) error("not constant number type"); - return static_cast(this); - } - PolyPlaceholderType* Type::toPolyPlaceholderType() { if(this->kind != TypeKind::PolyPlaceholder) error("not poly placeholder type"); @@ -609,11 +522,6 @@ namespace fir - bool Type::isConstantNumberType() - { - return this->kind == TypeKind::ConstantNumber; - } - bool Type::isStructType() { return this->kind == TypeKind::Struct; @@ -624,11 +532,6 @@ namespace fir return this->kind == TypeKind::Tuple; } - bool Type::isClassType() - { - return this->kind == TypeKind::Class; - } - bool Type::isPackedStruct() { return this->isStructType() && (this->toStructType()->isTypePacked); @@ -679,11 +582,6 @@ namespace fir return this->kind == TypeKind::Void; } - bool Type::isDynamicArrayType() - { - return this->kind == TypeKind::DynamicArray; - } - bool Type::isVariadicArrayType() { return this->isArraySliceType() && this->toArraySliceType()->isVariadicType(); @@ -699,11 +597,6 @@ namespace fir return this->kind == TypeKind::Range; } - bool Type::isStringType() - { - return this->kind == TypeKind::String; - } - bool Type::isCharType() { return this == fir::Type::getInt8(); @@ -724,11 +617,6 @@ namespace fir return this->kind == TypeKind::RawUnion; } - bool Type::isAnyType() - { - return this->kind == TypeKind::Any; - } - bool Type::isNullType() { return this->kind == TypeKind::Null; @@ -979,17 +867,6 @@ namespace fir return RangeType::get(); } - StringType* Type::getString() - { - return StringType::get(); - } - - AnyType* Type::getAny() - { - return AnyType::get(); - } - - @@ -1012,11 +889,6 @@ namespace fir if(packed) { - // gg - // return util::foldl(0, tys, [](Type* a, Type* b) -> size_t { - // return getSizeOfType(a) + getSizeOfType(b); - // }); - size_t ret = 0; for(const auto& t : tys) ret += getSizeOfType(t); @@ -1054,7 +926,6 @@ namespace fir else if(type->isBoolType()) return 1; else if(type->isPrimitiveType()) return type->getBitWidth() / 8; else if(type->isArraySliceType()) return getAggregateSize({ ptrt, wordty }); - else if(type->isStringType() || type->isDynamicArrayType()) return getAggregateSize({ ptrt, wordty, wordty, ptrt }); else if(type->isRangeType()) return getAggregateSize({ wordty, wordty, wordty }); else if(type->isPointerType() || type->isFunctionType() || type->isNullType()) { @@ -1068,21 +939,12 @@ namespace fir { return getAggregateSize({ wordty, type->toEnumType()->getCaseType() }); } - else if(type->isAnyType()) - { - return getAggregateSize({ wordty, ptrt, fir::ArrayType::get(fir::Type::getInt8(), BUILTIN_ANY_DATA_BYTECOUNT) }); - } - else if(type->isClassType() || type->isStructType() || type->isTupleType()) + else if(type->isStructType() || type->isTupleType()) { bool packed = false; std::vector tys; - if(type->isClassType()) - { - tys = type->toClassType()->getAllElementsIncludingBase(); - tys.insert(tys.begin(), fir::Type::getInt8Ptr()); - } - else if(type->isStructType()) + if(type->isStructType()) { packed = type->toStructType()->isPackedStruct(); tys = type->toStructType()->getElements(); @@ -1144,50 +1006,6 @@ namespace fir if(type->isArrayType()) return getAlignmentOfType(type->getArrayElementType()); else return getSizeOfType(type); } - - - bool isRefCountedType(Type* type) - { - // strings, and structs with rc inside - if(type->isStructType()) - { - for(auto m : type->toStructType()->getElements()) - { - if(isRefCountedType(m)) - return true; - } - - return false; - } - else if(type->isClassType()) - { - for(auto m : type->toClassType()->getElements()) - { - if(isRefCountedType(m)) - return true; - } - - return false; - } - else if(type->isTupleType()) - { - for(auto m : type->toTupleType()->getElements()) - { - if(isRefCountedType(m)) - return true; - } - - return false; - } - else if(type->isArrayType()) // note: no slices, because slices don't own memory - { - return isRefCountedType(type->getArrayElementType()); - } - else - { - return type->isStringType() || type->isAnyType() || type->isDynamicArrayType(); - } - } } diff --git a/source/fir/Types/TypeUtils.cpp b/source/fir/Types/TypeUtils.cpp index e455ac16..d97aab13 100644 --- a/source/fir/Types/TypeUtils.cpp +++ b/source/fir/Types/TypeUtils.cpp @@ -8,65 +8,14 @@ namespace fir { - static bool _checkTypeVariance(Type* base, Type* derv, bool contra, bool trait) - { - if(base == derv) - return true; - - // for now, we only support inheritance and stuff on pointers. - if(!base->isPointerType() || !derv->isPointerType()) - return false; - - auto baseelm = base->getPointerElementType(); - auto dervelm = derv->getPointerElementType(); - - if(baseelm->isClassType() && dervelm->isClassType()) - { - // if contravariant, then derv must be more general than base. - if(contra) return baseelm->toClassType()->hasParent(dervelm); - else return dervelm->toClassType()->hasParent(baseelm); - } - else - { - // if contra, check if base implements derv as a trait - // else check if derv implements base as a trait. of course, if the thing that - // is supposed to be a trait isn't a trait, it doesn't work. - if(contra) - { - // if contra *BUT* we are checking traits, then we should allow the case where the - // derived type is covariant (ie. implements the trait!) - - if(trait) - { - // TODO: this might not be correct? - std::swap(baseelm, dervelm); - } - - if(!dervelm->isTraitType()) - return false; - - return (baseelm->isStructType() && baseelm->toStructType()->implementsTrait(dervelm->toTraitType())) - || (dervelm->isStructType() && dervelm->toStructType()->implementsTrait(baseelm->toTraitType())); - } - else - { - if(!baseelm->isTraitType()) - return false; - - return (dervelm->isStructType() && dervelm->toStructType()->implementsTrait(baseelm->toTraitType())) - || (baseelm->isStructType() && baseelm->toStructType()->implementsTrait(dervelm->toTraitType())); - } - } - } - bool areTypesCovariant(Type* base, Type* derv) { - return _checkTypeVariance(base, derv, false, false); + return false; } bool areTypesContravariant(Type* base, Type* derv, bool traitChecking) { - return _checkTypeVariance(base, derv, true, traitChecking); + return false; } bool areTypeListsContravariant(const std::vector& base, const std::vector& derv, bool traitChecking) diff --git a/source/fir/interp/interpreter.cpp b/source/fir/interp/interpreter.cpp index 84d2b18a..f834b781 100644 --- a/source/fir/interp/interpreter.cpp +++ b/source/fir/interp/interpreter.cpp @@ -21,15 +21,6 @@ #define SLICE_DATA_INDEX 0 #define SLICE_LENGTH_INDEX 1 -#define SAA_DATA_INDEX 0 -#define SAA_LENGTH_INDEX 1 -#define SAA_CAPACITY_INDEX 2 -#define SAA_REFCOUNTPTR_INDEX 3 - -#define ANY_TYPEID_INDEX 0 -#define ANY_REFCOUNTPTR_INDEX 1 -#define ANY_DATA_ARRAY_INDEX 2 - #ifdef _MSC_VER #pragma warning(push, 0) @@ -334,67 +325,6 @@ namespace interp return (cachedConstants[c] = ret); } - else if(auto cds = dcast(fir::ConstantDynamicString, c)) - { - auto str = makeGlobalString(is, cds->getValue()); - auto ptr = fir::ConstantBitcast::get(fir::ConstantInt::getUNative(reinterpret_cast(str)), fir::Type::getInt8Ptr()); - auto len = fir::ConstantInt::getNative(cds->getValue().size()); - - auto bytecount = getSizeOfType(cds->getType()); - - // add -1 for capacity and 0 for refcountptr. - auto ret = constructStructThingy(cds, bytecount, { ptr, len, - fir::ConstantInt::getNative(-1), fir::ConstantInt::getNative(0) }); - - return (cachedConstants[c] = ret); - } - else if(auto cda = dcast(fir::ConstantDynamicArray, c)) - { - std::vector mems; - auto bytecount = getSizeOfType(cda->getType()); - - if(cda->getArray()) - { - auto theArray = cda->getArray(); - auto sz = getSizeOfType(theArray->getType()); - - void* buffer = new uint8_t[sz]; memset(buffer, 0, sz); - is->globalAllocs.push_back(buffer); - - uint8_t* ofs = reinterpret_cast(buffer); - for(auto x : theArray->getValues()) - { - auto v = makeConstant(is, x); - - if(v.dataSize > LARGE_DATA_SIZE) memmove(ofs, v.ptr, v.dataSize); - else memmove(ofs, &v.data[0], v.dataSize); - - ofs += v.dataSize; - } - - interp::Value fakeptr; - fakeptr.val = 0; - fakeptr.type = cda->getType()->getArrayElementType()->getMutablePointerTo(); - fakeptr.dataSize = sizeof(void*); - - setValueRaw(is, &fakeptr, &buffer, sizeof(void*)); - - mems = { - fakeptr, makeConstant(is, fir::ConstantInt::getNative(theArray->getValues().size())), - makeConstant(is, fir::ConstantInt::getNative(-1)), makeConstant(is, fir::ConstantInt::getNative(0)) - }; - } - else - { - mems = { - makeConstant(is, cda->getData()), makeConstant(is, cda->getLength()), - makeConstant(is, cda->getCapacity()), makeConstant(is, fir::ConstantInt::getNative(0)) - }; - } - - auto ret = constructStructThingy2(cda, bytecount, mems); - return (cachedConstants[c] = ret); - } else if(auto fn = dcast(fir::Function, c)) { // ok -- when we get a "function" as a constant, what really happened in the source code is that we referred to a function @@ -629,14 +559,6 @@ namespace interp { return ty->toStructType()->getElements(); } - else if(ty->isClassType()) - { - auto ret = ty->toClassType()->getAllElementsIncludingBase(); - if(ty->toClassType()->getVirtualMethodCount() > 0) - ret.insert(ret.begin(), fir::Type::getInt8Ptr()); - - return ret; - } else if(ty->isTupleType()) { return ty->toTupleType()->getElements(); @@ -649,13 +571,6 @@ namespace interp else return { ty->getArrayElementType()->getPointerTo(), fir::Type::getNativeWord() }; } - else if(ty->isAnyType()) - { - return { - fir::Type::getNativeUWord(), fir::Type::getNativeWordPtr(), - fir::ArrayType::get(fir::Type::getInt8(), BUILTIN_ANY_DATA_BYTECOUNT) - }; - } else if(ty->isRangeType()) { return { @@ -668,19 +583,6 @@ namespace interp fir::Type::getNativeWord(), ty->toEnumType()->getCaseType() }; } - else if(ty->isStringType() || ty->isDynamicArrayType()) - { - std::vector mems(4); - - if(ty->isDynamicArrayType()) mems[SAA_DATA_INDEX] = ty->getArrayElementType()->getMutablePointerTo(); - else mems[SAA_DATA_INDEX] = fir::Type::getMutInt8Ptr(); - - mems[SAA_LENGTH_INDEX] = fir::Type::getNativeWord(); - mems[SAA_CAPACITY_INDEX] = fir::Type::getNativeWord(); - mems[SAA_REFCOUNTPTR_INDEX] = fir::Type::getNativeWordPtr(); - - return mems; - } else { error("interp: unsupported type '%s' for insert/extractvalue", ty); @@ -1055,7 +957,7 @@ namespace interp void* ret_buffer = new uint8_t[std::max(ffi_retty->size, size_t(8))]; ffi_call(&fn_cif, reinterpret_cast(fnptr), ret_buffer, arg_pointers); - interp::Value ret = { 0 }; + interp::Value ret = { }; ret.type = fnty->getReturnType(); ret.dataSize = ffi_retty->size; @@ -1330,7 +1232,7 @@ namespace interp iceAssert(str.type->isPointerType()); auto strty = str.type->getPointerElementType(); - if(!strty->isStructType() && !strty->isClassType() && !strty->isTupleType()) + if(!strty->isStructType() && !strty->isTupleType()) error("interp: unsupported type '%s' for struct gep", strty); std::vector elms = getTypeListOfType(strty); @@ -1918,35 +1820,6 @@ namespace interp } - case OpKind::Value_CallVirtualMethod: - { - // args are: 0. classtype, 1. index, 2. functiontype, 3...N args - auto clsty = inst.args[0]->getType()->toClassType(); - auto fnty = inst.args[2]->getType()->toFunctionType(); - iceAssert(clsty); - - std::vector args; - for(size_t i = 3; i < inst.args.size(); i++) - args.push_back(getArg(is, inst, i)); - - //* this is very hacky! we rely on these things not using ::val, because it's null!! - auto vtable = loadFromPtr(performStructGEP(is, fir::Type::getInt8Ptr(), args[0], 0), fir::Type::getInt8Ptr()); - auto vtablety = fir::ArrayType::get(fir::FunctionType::get({ }, fir::Type::getVoid())->getPointerTo(), clsty->getVirtualMethodCount()); - vtable.type = vtablety->getPointerTo(); - - vtable = performGEP2(is, vtablety->getPointerTo(), vtable, makeConstant(is, fir::ConstantInt::getNative(0)), getArg(is, inst, 1)); - - auto fnptr = loadFromPtr(vtable, fnty->getPointerTo()); - - instrRes->callArguments = args; - instrRes->virtualCallTarget = fnptr; - instrRes->callResultValue = inst.result; - - return FLOW_DYCALL; - } - - - case OpKind::Cast_IntSize: @@ -2212,59 +2085,6 @@ namespace interp } - case OpKind::SAA_GetData: - case OpKind::SAA_GetLength: - case OpKind::SAA_GetCapacity: - case OpKind::SAA_GetRefCountPtr: - { - iceAssert(inst.args.size() == 1); - auto str = getArg(is, inst, 0); - - interp::Value ret; - - if(ok == OpKind::SAA_GetData) - ret = doExtractValue(is, inst.result, str, SAA_DATA_INDEX); - - else if(ok == OpKind::SAA_GetLength) - ret = doExtractValue(is, inst.result, str, SAA_LENGTH_INDEX); - - else if(ok == OpKind::SAA_GetCapacity) - ret = doExtractValue(is, inst.result, str, SAA_CAPACITY_INDEX); - - else if(ok == OpKind::SAA_GetRefCountPtr) - ret = doExtractValue(is, inst.result, str, SAA_REFCOUNTPTR_INDEX); - - setRet(is, inst, ret); - break; - } - - case OpKind::SAA_SetData: - case OpKind::SAA_SetLength: - case OpKind::SAA_SetCapacity: - case OpKind::SAA_SetRefCountPtr: - { - iceAssert(inst.args.size() == 2); - auto str = getArg(is, inst, 0); - auto elm = getArg(is, inst, 1); - - interp::Value ret; - - if(ok == OpKind::SAA_SetData) - ret = doInsertValue(is, inst.result, str, elm, SAA_DATA_INDEX); - - else if(ok == OpKind::SAA_SetLength) - ret = doInsertValue(is, inst.result, str, elm, SAA_LENGTH_INDEX); - - else if(ok == OpKind::SAA_SetCapacity) - ret = doInsertValue(is, inst.result, str, elm, SAA_CAPACITY_INDEX); - - else if(ok == OpKind::SAA_SetRefCountPtr) - ret = doInsertValue(is, inst.result, str, elm, SAA_REFCOUNTPTR_INDEX); - - setRet(is, inst, ret); - break; - } - case OpKind::ArraySlice_GetData: case OpKind::ArraySlice_GetLength: { @@ -2304,52 +2124,6 @@ namespace interp break; } - case OpKind::Any_GetData: - case OpKind::Any_GetTypeID: - case OpKind::Any_GetRefCountPtr: - { - iceAssert(inst.args.size() == 1); - auto str = getArg(is, inst, 0); - - interp::Value ret; - - if(ok == OpKind::Any_GetTypeID) - ret = doExtractValue(is, inst.result, str, ANY_TYPEID_INDEX); - - else if(ok == OpKind::Any_GetRefCountPtr) - ret = doExtractValue(is, inst.result, str, ANY_REFCOUNTPTR_INDEX); - - else if(ok == OpKind::Any_GetData) - ret = doExtractValue(is, inst.result, str, ANY_DATA_ARRAY_INDEX); - - setRet(is, inst, ret); - break; - } - - case OpKind::Any_SetData: - case OpKind::Any_SetTypeID: - case OpKind::Any_SetRefCountPtr: - { - iceAssert(inst.args.size() == 2); - auto str = getArg(is, inst, 0); - auto elm = getArg(is, inst, 1); - - interp::Value ret; - - if(ok == OpKind::Any_SetTypeID) - ret = doInsertValue(is, inst.result, str, elm, ANY_TYPEID_INDEX); - - else if(ok == OpKind::Any_SetRefCountPtr) - ret = doInsertValue(is, inst.result, str, elm, ANY_REFCOUNTPTR_INDEX); - - else if(ok == OpKind::Any_SetData) - ret = doInsertValue(is, inst.result, str, elm, ANY_DATA_ARRAY_INDEX); - - setRet(is, inst, ret); - break; - } - - case OpKind::Range_GetLower: case OpKind::Range_GetUpper: @@ -2627,13 +2401,6 @@ namespace interp return fir::ConstantCharSlice::get(std::string(ptr, len)); } - else if(ty->isStringType()) - { - char* ptr = gav(extractOneValue(val, SAA_DATA_INDEX, fir::Type::getMutInt8Ptr())); - int64_t len = gav(extractOneValue(val, SAA_LENGTH_INDEX, fir::Type::getInt64())); - - return fir::ConstantDynamicString::get(std::string(ptr, len)); - } else if(ty->isArraySliceType()) { auto ptr = this->unwrapInterpValueIntoConstant(extractOneValue(val, SLICE_DATA_INDEX, @@ -2644,16 +2411,6 @@ namespace interp return fir::ConstantArraySlice::get(ty->toArraySliceType(), ptr, len); } - else if(ty->isDynamicArrayType()) - { - auto ptr = this->unwrapInterpValueIntoConstant(extractOneValue(val, SAA_DATA_INDEX, - ty->getArrayElementType()->getMutablePointerTo())); - - auto len = this->unwrapInterpValueIntoConstant(extractOneValue(val, SAA_LENGTH_INDEX, fir::Type::getInt64())); - auto cap = this->unwrapInterpValueIntoConstant(extractOneValue(val, SAA_CAPACITY_INDEX, fir::Type::getInt64())); - - return fir::ConstantDynamicArray::get(ty->toDynamicArrayType(), ptr, len, cap); - } else if(ty->isStructType()) { auto sty = ty->toStructType(); diff --git a/source/frontend/arguments.cpp b/source/frontend/arguments.cpp index 8ff7be0b..0e49dc9e 100644 --- a/source/frontend/arguments.cpp +++ b/source/frontend/arguments.cpp @@ -635,10 +635,10 @@ namespace frontend { switch(argv[i][2]) { - case '0': frontend::_optLevel = OptimisationLevel::None; break; - case '1': frontend::_optLevel = OptimisationLevel::Minimal; break; - case '2': frontend::_optLevel = OptimisationLevel::Normal; break; - case '3': frontend::_optLevel = OptimisationLevel::Aggressive; break; + case '0': frontend::_optLevel = OptimisationLevel::None; break; + case '1': frontend::_optLevel = OptimisationLevel::Minimal; break; + case '2': frontend::_optLevel = OptimisationLevel::Normal; break; + case '3': frontend::_optLevel = OptimisationLevel::Aggressive; break; default: _error_and_exit("error: '%c' is not a valid optimisation level (must be between 0 and 3)\n", argv[i][2]); diff --git a/source/frontend/import.cpp b/source/frontend/import.cpp index a90d0de4..7278cdde 100644 --- a/source/frontend/import.cpp +++ b/source/frontend/import.cpp @@ -19,10 +19,6 @@ namespace frontend if(auto it = importCache.find({ imp, fullPath }); it != importCache.end()) return it->second; - // std::string ext = ".flx"; - // if(imp.size() > ext.size() && imp.find(".flx") == imp.size() - ext.size()) - // ext = ""; - std::string curpath = getPathFromFile(fullPath); std::string fullname = curpath + "/" + imp; diff --git a/source/frontend/lexer.cpp b/source/frontend/lexer.cpp index b486a1a5..a2d99945 100644 --- a/source/frontend/lexer.cpp +++ b/source/frontend/lexer.cpp @@ -44,37 +44,15 @@ namespace lexer return true; } + template + static constexpr size_t constexpr_strlen(char const (&literal)[N]) + { + return N - 1; + } - static TokenType prevType = TokenType::Invalid; - static size_t prevID = 0; - static bool shouldConsiderUnaryLiteral(string_view& stream, Location& pos) - { - // check the previous token - bool should = (prevType != TokenType::Invalid && prevID == pos.fileID && ( - prevType != TokenType::RParen && - prevType != TokenType::RSquare && - prevType != TokenType::Identifier && - prevType != TokenType::Number && - prevType != TokenType::Dollar && - prevType != TokenType::StringLiteral - )); - - if(!should) return false; - - // check if the current char is a + or - - if(stream.length() == 0) return false; - if(stream[0] != '+' && stream[0] != '-') return false; - - // check if there's only spaces between this and the number itself - for(size_t i = 1; i < stream.length(); i++) - { - if(isdigit(stream[i])) return true; - else if(stream[i] != ' ') return false; - } - return false; - } + static TokenType prevType = TokenType::Invalid; static util::hash_map keywordMap; @@ -101,7 +79,6 @@ namespace lexer keywordMap["false"] = TokenType::False; keywordMap["while"] = TokenType::While; keywordMap["break"] = TokenType::Break; - keywordMap["class"] = TokenType::Class; keywordMap["using"] = TokenType::Using; keywordMap["union"] = TokenType::Union; keywordMap["struct"] = TokenType::Struct; @@ -163,6 +140,21 @@ namespace lexer tok.loc = pos; tok.type = TokenType::Invalid; + #define CHECK_TOKEN(str, ty) \ + else if(hasPrefix(stream, str)) { \ + tok.type = TokenType::ty; \ + tok.text = str; \ + read = constexpr_strlen(str); \ + } + + #define CHECK_TOKEN_UNICODE(str, ty, ul)\ + else if(hasPrefix(stream, str)) { \ + tok.type = TokenType::ty; \ + tok.text = str; \ + read = constexpr_strlen(str); \ + unicodeLength = ul; \ + } + // check compound symbols first. if(hasPrefix(stream, "//")) { @@ -179,144 +171,45 @@ namespace lexer flag = false; tok.text = ""; } - else if(hasPrefix(stream, "==")) - { - tok.type = TokenType::EqualsTo; - tok.text = "=="; - read = 2; - } - else if(hasPrefix(stream, ">=")) - { - tok.type = TokenType::GreaterEquals; - tok.text = ">="; - read = 2; - } - else if(hasPrefix(stream, "<=")) - { - tok.type = TokenType::LessThanEquals; - tok.text = "<="; - read = 2; - } - else if(hasPrefix(stream, "!=")) - { - tok.type = TokenType::NotEquals; - tok.text = "!="; - read = 2; - } - else if(hasPrefix(stream, "||")) - { - tok.type = TokenType::LogicalOr; - tok.text = "||"; - read = 2; - } - else if(hasPrefix(stream, "&&")) - { - tok.type = TokenType::LogicalAnd; - tok.text = "&&"; - read = 2; - } - else if(hasPrefix(stream, "<-")) - { - tok.type = TokenType::LeftArrow; - tok.text = "<-"; - read = 2; - } - else if(hasPrefix(stream, "->")) - { - tok.type = TokenType::RightArrow; - tok.text = "->"; - read = 2; - } - else if(hasPrefix(stream, "<=")) - { - tok.type = TokenType::FatLeftArrow; - tok.text = "<="; - read = 2; - } - else if(hasPrefix(stream, "=>")) - { - tok.type = TokenType::FatRightArrow; - tok.text = "=>"; - read = 2; - } - else if(hasPrefix(stream, "++")) - { - tok.type = TokenType::DoublePlus; - tok.text = "++"; - read = 2; - } - else if(hasPrefix(stream, "--")) - { - tok.type = TokenType::DoubleMinus; - tok.text = "--"; - read = 2; - } - else if(hasPrefix(stream, "+=")) - { - tok.type = TokenType::PlusEq; - tok.text = "+="; - read = 2; - } - else if(hasPrefix(stream, "-=")) - { - tok.type = TokenType::MinusEq; - tok.text = "-="; - read = 2; - } - else if(hasPrefix(stream, "*=")) - { - tok.type = TokenType::MultiplyEq; - tok.text = "*="; - read = 2; - } - else if(hasPrefix(stream, "/=")) - { - tok.type = TokenType::DivideEq; - tok.text = "/="; - read = 2; - } - else if(hasPrefix(stream, "%=")) - { - tok.type = TokenType::ModEq; - tok.text = "%="; - read = 2; - } - else if(hasPrefix(stream, "&=")) - { - tok.type = TokenType::AmpersandEq; - tok.text = "&="; - read = 2; - } - else if(hasPrefix(stream, "|=")) - { - tok.type = TokenType::PipeEq; - tok.text = "|="; - read = 2; - } - else if(hasPrefix(stream, "^=")) - { - tok.type = TokenType::CaretEq; - tok.text = "^="; - read = 2; - } - else if(hasPrefix(stream, "::")) - { - tok.type = TokenType::DoubleColon; - tok.text = "::"; - read = 2; - } - else if(hasPrefix(stream, "...")) - { - tok.type = TokenType::Ellipsis; - tok.text = "..."; - read = 3; - } - else if(hasPrefix(stream, "..<")) - { - tok.type = TokenType::HalfOpenEllipsis; - tok.text = "..<"; - read = 3; - } + CHECK_TOKEN("==", EqualsTo) + CHECK_TOKEN("!=", EqualsTo) + CHECK_TOKEN(">=", GreaterEquals) + CHECK_TOKEN("<=", LessThanEquals) + CHECK_TOKEN("||", LogicalOr) + CHECK_TOKEN("&&", LogicalAnd) + CHECK_TOKEN("<-", LeftArrow) + CHECK_TOKEN("->", RightArrow) + CHECK_TOKEN("<=", FatLeftArrow) + CHECK_TOKEN("=>", FatRightArrow) + CHECK_TOKEN("++", DoublePlus) + CHECK_TOKEN("--", DoubleMinus) + CHECK_TOKEN("+=", PlusEq) + CHECK_TOKEN("-=", MinusEq) + CHECK_TOKEN("*=", MultiplyEq) + CHECK_TOKEN("/=", DivideEq) + CHECK_TOKEN("%=", ModEq) + CHECK_TOKEN("&=", AmpersandEq) + CHECK_TOKEN("|=", PipeEq) + CHECK_TOKEN("^=", CaretEq) + CHECK_TOKEN("::", DoubleColon) + CHECK_TOKEN("...", Ellipsis) + CHECK_TOKEN("..<", HalfOpenEllipsis) + + CHECK_TOKEN("@nomangle", Attr_NoMangle) + CHECK_TOKEN("@entry", Attr_EntryFn) + CHECK_TOKEN("@packed", Attr_Packed) + CHECK_TOKEN("@raw", Attr_Raw) + CHECK_TOKEN("@operator", Attr_Operator) + + CHECK_TOKEN("#if", Directive_If) + CHECK_TOKEN("#run", Directive_Run) + + CHECK_TOKEN_UNICODE("ƒ", Func, 1) + CHECK_TOKEN_UNICODE("÷", Divide, 1) + CHECK_TOKEN_UNICODE("≠", NotEquals, 1) + CHECK_TOKEN_UNICODE("≤", LessThanEquals, 1) + CHECK_TOKEN_UNICODE("≥", GreaterEquals, 1) + else if(hasPrefix(stream, "/*")) { int currentNest = 1; @@ -385,109 +278,6 @@ namespace lexer - // attrs - else if(hasPrefix(stream, "@nomangle")) - { - tok.type = TokenType::Attr_NoMangle; - tok.text = "@nomangle"; - read = 9; - } - else if(hasPrefix(stream, "@entry")) - { - tok.type = TokenType::Attr_EntryFn; - tok.text = "@entry"; - read = 6; - } - else if(hasPrefix(stream, "@packed")) - { - tok.type = TokenType::Attr_Packed; - tok.text = "@packed"; - read = 7; - } - else if(hasPrefix(stream, "@raw")) - { - tok.type = TokenType::Attr_Raw; - tok.text = "@raw"; - read = 4; - } - else if(hasPrefix(stream, "@operator")) - { - tok.type = TokenType::Attr_Operator; - tok.text = "@operator"; - read = 9; - } - else if(hasPrefix(stream, "@platform")) - { - tok.type = TokenType::Attr_Platform; - tok.text = "@platform"; - read = 9; - } - - // directives - else if(hasPrefix(stream, "#if")) - { - tok.type = TokenType::Directive_If; - tok.text = "#if"; - read = 3; - } - else if(hasPrefix(stream, "#run")) - { - tok.type = TokenType::Directive_Run; - tok.text = "#run"; - read = 4; - } - - - // unicode stuff - else if(hasPrefix(stream, "ƒ")) - { - tok.type = TokenType::Func; - read = std::string("ƒ").length(); - tok.text = "ƒ"; - - unicodeLength = 1; - } - else if(hasPrefix(stream, "fi")) - { - tok.type = TokenType::ForeignFunc; - read = std::string("fi").length(); - tok.text = "fi"; - - unicodeLength = 1; - } - else if(hasPrefix(stream, "÷")) - { - tok.type = TokenType::Divide; - read = std::string("÷").length(); - tok.text = "÷"; - - unicodeLength = 1; - } - else if(hasPrefix(stream, "≠")) - { - tok.type = TokenType::NotEquals; - read = std::string("≠").length(); - tok.text = "≠"; - - unicodeLength = 1; - } - else if(hasPrefix(stream, "≤")) - { - tok.type = TokenType::LessThanEquals; - read = std::string("≤").length(); - tok.text = "≤"; - - unicodeLength = 1; - } - else if(hasPrefix(stream, "≥")) - { - tok.type = TokenType::GreaterEquals; - read = std::string("≥").length(); - tok.text = "≥"; - - unicodeLength = 1; - } - else if(hasPrefix(stream, "'") && stream.size() > 2) { tok.type = TokenType::CharacterLiteral; @@ -526,16 +316,11 @@ namespace lexer // so in every other case we want unary +/-. // note: a sane implementation would just return false if isdigit() was passed something weird, like a negative number // (because we tried to dissect a UTF-8 codepoint). so we just check if it's ascii first, which would solve the issue. - else if((!stream.empty() && ((isascii(stream[0]) && isdigit(stream[0])) || shouldConsiderUnaryLiteral(stream, pos))) - /* handle cases like '+ 3' or '- 14' (ie. space between sign and number) */ - && ((isascii(stream[0]) && isdigit(stream[0]) ? true : false) || (stream.size() > 1 && isascii(stream[1]) && isdigit(stream[1])))) + else if(!stream.empty() && isascii(stream[0]) && isdigit(stream[0])) { // copy it. auto tmp = stream; - if(tmp.find('-') == 0 || tmp.find('+') == 0) - tmp.remove_prefix(1); - int base = 10; if(tmp.find("0x") == 0 || tmp.find("0X") == 0) base = 16, tmp.remove_prefix(2); @@ -543,12 +328,11 @@ namespace lexer else if(tmp.find("0b") == 0 || tmp.find("0B") == 0) base = 2, tmp.remove_prefix(2); - // find that shit auto end = std::find_if_not(tmp.begin(), tmp.end(), [base](const char& c) -> bool { - if(base == 10) return isdigit(c); - if(base == 16) return isdigit(c) || (toupper(c) >= 'A' && toupper(c) <= 'F'); - else return (c == '0' || c == '1'); + if(base == 10) return isdigit(c); + if(base == 16) return isdigit(c) || (toupper(c) >= 'A' && toupper(c) <= 'F'); + else return (c == '0' || c == '1'); }); tmp.remove_prefix((end - tmp.begin())); @@ -569,6 +353,7 @@ namespace lexer hadExp = true; } + bool is_floating = false; size_t didRead = stream.size() - tmp.size(); auto post = stream.substr(didRead); @@ -595,7 +380,7 @@ namespace lexer while(post.size() > 0 && isdigit(post.front())) post.remove_prefix(1), didRead++; - // ok. + is_floating = true; } else { @@ -605,10 +390,11 @@ namespace lexer } tok.text = stream.substr(0, didRead); - - tok.type = TokenType::Number; tok.loc.len = didRead; + if(is_floating) tok.type = TokenType::FloatingNumber; + else tok.type = TokenType::IntegerNumber; + read = didRead; } else if(!stream.empty() && (stream[0] == '_' || utf8iscategory(stream.data(), stream.size(), UTF8_CATEGORY_LETTER) > 0)) @@ -825,7 +611,7 @@ namespace lexer prevType = tok.type; - prevID = tok.loc.fileID; + return prevType; } diff --git a/source/frontend/parser/controlflow.cpp b/source/frontend/parser/controlflow.cpp index 7fe55c51..7312c7e0 100644 --- a/source/frontend/parser/controlflow.cpp +++ b/source/frontend/parser/controlflow.cpp @@ -212,9 +212,9 @@ namespace parser PResult parseWhileLoop(State& st) { - // 1. do { } -- body = block, cond = 0, doVariant = true - // 2. while x { } -- body = block, cond = x, doVariant = false - // 3. do { } while x -- body = block, cond = x, doVariant = true + // 1. do { } -- body = block, cond = 0, doVariant = true + // 2. while x { } -- body = block, cond = x, doVariant = false + // 3. do { } while x -- body = block, cond = x, doVariant = true auto loc = st.loc(); diff --git a/source/frontend/parser/expr.cpp b/source/frontend/parser/expr.cpp index 20ee6429..ea470150 100644 --- a/source/frontend/parser/expr.cpp +++ b/source/frontend/parser/expr.cpp @@ -23,9 +23,9 @@ namespace parser auto vis = VisibilityLevel::Invalid; switch(st.front()) { - case TT::Public: vis = VisibilityLevel::Public; break; - case TT::Private: vis = VisibilityLevel::Private; break; - case TT::Internal: vis = VisibilityLevel::Internal; break; + case TT::Public: vis = VisibilityLevel::Public; break; + case TT::Private: vis = VisibilityLevel::Private; break; + case TT::Internal: vis = VisibilityLevel::Internal; break; default: iceAssert(0); } @@ -88,7 +88,6 @@ namespace parser else { return PResult(parseFunction(st)).mutate([&](auto ret) -> void { - ret->isVirtual = virt; ret->isOverride = ovrd; ret->isMutating = mut; }); @@ -162,9 +161,6 @@ namespace parser case TT::Struct: return enforceAttrs(parseStruct(st, /* nameless: */ false), AttribSet::of(attr::PACKED)); - case TT::Class: - return enforceAttrs(parseClass(st)); - case TT::Enum: return enforceAttrs(parseEnum(st)); @@ -247,22 +243,6 @@ namespace parser return parseDefer(st); default: { - if(st.isInStructBody() && tok.type == TT::Identifier) - { - if(tok.str() == "init") - { - return parseInitFunction(st); - } - else if(tok.str() == "deinit") - { - return parseDeinitFunction(st); - } - else if(tok.str() == "copy" || tok.str() == "move") - { - return parseCopyOrMoveInitFunction(st, tok.str()); - } - } - // we want to error on invalid tokens first. so, we parse the expression regardless, // then if they're not allowed we error. return PResult(parseExpr(st)).mutate([&](auto expr) -> void { @@ -1171,7 +1151,6 @@ namespace parser case TT::Val: case TT::Func: case TT::Enum: - case TT::Class: case TT::Using: case TT::Union: case TT::Static: @@ -1232,9 +1211,6 @@ namespace parser case TT::Alloc: return parseAlloc(st, false); - // case TT::Typeof: - // return parseTypeof(ps); - case TT::Typeid: return parseTypeid(st); @@ -1258,7 +1234,8 @@ namespace parser case TT::StringLiteral: return parseString(st, false); - case TT::Number: + case TT::IntegerNumber: + case TT::FloatingNumber: return parseNumber(st); case TT::LSquare: diff --git a/source/frontend/parser/function.cpp b/source/frontend/parser/function.cpp index 016fbe8a..eb290028 100644 --- a/source/frontend/parser/function.cpp +++ b/source/frontend/parser/function.cpp @@ -216,97 +216,6 @@ namespace parser } - InitFunctionDefn* parseInitFunction(State& st) - { - Token tok = st.pop(); - iceAssert(tok.str() == "init"); - - auto [ params, generics, retty, isvar, varloc ] = parseFunctionLookingDecl(st); - if(generics.size() > 0) - error(st.ploc(), "class initialiser functions cannot be generic"); - - else if(retty != 0) - error(st.ploc(), "class initialisers cannot have a return type"); - - else if(isvar) - error(varloc, "C-style variadic arguments are not supported on non-foreign functions"); - - // ok loh - auto ret = util::pool(tok.loc); - ret->name = "init"; - ret->params = params; - - // check for super-class args. - if(st.front() == TT::Colon) - { - st.eat(); - if(st.eat().str() != "super") - expectedAfter(st.ploc(), "'super'", "':' in init function definition", st.prev().str()); - - if(st.eat() != TT::LParen) - expectedAfter(st.ploc(), "'('", "'super' in call to base-class initialiser", st.prev().str()); - - ret->superArgs = parseCallArgumentList(st); - ret->didCallSuper = true; - } - - st.enterFunctionBody(); - { - ret->body = parseBracedBlock(st).val(); - } - st.leaveFunctionBody(); - - return ret; - } - - - InitFunctionDefn* parseCopyOrMoveInitFunction(State& st, const std::string& name) - { - Token tok = st.pop(); - iceAssert(tok.str() == name); - - auto [ params, generics, retty, isvar, varloc ] = parseFunctionLookingDecl(st); - if(generics.size() > 0) - error(st.ploc(), "class initialiser functions cannot be generic"); - - else if(retty != 0) - error(st.ploc(), "class initialisers cannot have a return type"); - - else if(isvar) - error(varloc, "C-style variadic arguments are not supported on non-foreign functions"); - - // ok loh - auto ret = util::pool(tok.loc); - ret->name = name; - ret->params = params; - - st.enterFunctionBody(); - { - ret->body = parseBracedBlock(st).val(); - } - st.leaveFunctionBody(); - - return ret; - } - - - InitFunctionDefn* parseDeinitFunction(State& st) - { - Token tok = st.pop(); - iceAssert(tok.str() == "deinit"); - - auto ret = util::pool(tok.loc); - ret->name = "deinit"; - - st.enterFunctionBody(); - { - ret->body = parseBracedBlock(st).val(); - } - st.leaveFunctionBody(); - - return ret; - } - diff --git a/source/frontend/parser/literal.cpp b/source/frontend/parser/literal.cpp index 46a650a7..43f2adc6 100644 --- a/source/frontend/parser/literal.cpp +++ b/source/frontend/parser/literal.cpp @@ -21,10 +21,10 @@ namespace parser { LitNumber* parseNumber(State& st) { - iceAssert(st.front() == TT::Number); + iceAssert(st.front() == TT::IntegerNumber || st.front() == TT::FloatingNumber); auto t = st.eat(); - return util::pool(st.ploc(), t.str()); + return util::pool(st.ploc(), t.str(), /* floating: */ t == TT::FloatingNumber); } static std::string parseHexEscapes(const Location& loc, std::string_view sv, size_t* ofs) diff --git a/source/frontend/parser/misc.cpp b/source/frontend/parser/misc.cpp index bf793343..e0ac34c6 100644 --- a/source/frontend/parser/misc.cpp +++ b/source/frontend/parser/misc.cpp @@ -154,7 +154,6 @@ namespace parser case TT::Attr_Packed: ret.set(attr::PACKED); st.pop(); break; case TT::Attr_NoMangle: ret.set(attr::NO_MANGLE); st.pop(); break; case TT::Attr_EntryFn: ret.set(attr::FN_ENTRYPOINT); st.pop(); break; - case TT::Attr_Platform: unexpected(st.loc(), "@platform definition"); case TT::Attr_Operator: unexpected(st.loc(), "@operator declaration"); case TT::At: @@ -167,128 +166,9 @@ namespace parser } // sue me - out: + out: return ret; } - - - // TODO: switch this to the new attribute system. after the whole cddc19 shitshow @platform functionality - // TODO: remains unused. - PlatformDefn* parsePlatformDefn(State& st) - { - iceAssert(st.front() == TT::Attr_Platform); - auto l = st.loc(); - - st.eat(); - - if(st.eat() != TT::LSquare) - expectedAfter(st.ploc(), "'['", "@platform definition", st.prev().str()); - - PlatformDefn* pd = util::pool(l); - - // see what the thing is. - if(st.front() == TT::Identifier && st.front().str() == "intrinsic") - { - st.eat(); - pd->defnType = PlatformDefn::Type::Intrinsic; - - if(st.eat() != TT::Comma) - expected(st.ploc(), "',' in argument list to @platform", st.prev().str()); - - if(st.front() != TT::StringLiteral) - expected(st.loc(), "string literal to specify intrinsic name", st.front().str()); - - auto realname = st.eat().str(); - - if(st.eat() != TT::RSquare) - expectedAfter(st.ploc(), "']'", "@platform definition", st.prev().str()); - - if(st.front() != TT::Func) - expectedAfter(st.loc(), "function declaration", "@platform", st.front().str()); - - auto [ defn, isvar, varloc ] = parseFunctionDecl(st); - (void) varloc; - - if(!defn->generics.empty()) - error(defn->loc, "platform intrinsics cannot be generic"); - - auto ffn = util::pool(st.loc()); - ffn->realName = realname; - - ffn->loc = defn->loc; - ffn->isVarArg = isvar; - ffn->name = defn->name; - ffn->params = defn->params; - ffn->visibility = defn->visibility; - ffn->returnType = defn->returnType; - - - pd->intrinsicDefn = ffn; - } - else if(st.front() == TT::Identifier && st.front().str() == "integer_type") - { - st.eat(); - pd->defnType = PlatformDefn::Type::IntegerType; - - if(st.eat() != TT::Comma) - expected(st.ploc(), "',' in argument list to @platform", st.prev().str()); - - auto num = st.front().str(); - if(st.front() != TT::Number || num.find('.') != std::string::npos) - expected(st.ploc(), "integer value to specify type size (in bits)", st.front().str()); - - st.eat(); - - int sz = std::stoi(num); - if(sz <= 0) expected(st.ploc(), "non-zero and non-negative size", num); - else if(sz < 8) error(st.ploc(), "types less than 8-bits wide are currently not supported"); - - pd->typeSizeInBits = sz; - - if(st.eat() != TT::RSquare) - expectedAfter(st.ploc(), "']'", "@platform definition", st.prev().str()); - - if(st.front() != TT::Identifier) - expectedAfter(st.loc(), "identifier as type name", "@platform definition", st.front().str()); - - pd->typeName = st.eat().str(); - } - else if(st.front() == TT::Identifier && st.front().str() == "native_word_size") - { - if(!st.nativeWordSizeStillValid) - { - SimpleError::make(st.loc(), "setting the native word size is no longer possible at this point")->append( - BareError::make(MsgType::Note, "@platform[native_word_size] must appear before any code declarations, " - "and be the first '@platform' declaration"))->postAndQuit(); - } - - st.eat(); - - if(st.eat() != TT::RSquare) - expectedAfter(st.ploc(), "']'", "@platform definition", st.prev().str()); - - auto num = st.front().str(); - if(st.front() != TT::Number || num.find('.') != std::string::npos) - expected(st.ploc(), "integer value to specify word size (in bits)", st.front().str()); - - st.eat(); - - int sz = std::stoi(num); - if(sz <= 0) expected(st.ploc(), "non-zero and non-negative size", num); - else if(sz < 8) error(st.ploc(), "types less than 8-bits wide are currently not supported"); - - //? should we warn if it was already set? - st.cState->nativeWordSize = sz; - - return 0; - } - else - { - error(st.loc(), "invalid platform declaration of type '%s'", st.front().str()); - } - - return pd; - } } diff --git a/source/frontend/parser/operators.cpp b/source/frontend/parser/operators.cpp index 36943a49..cd55436b 100644 --- a/source/frontend/parser/operators.cpp +++ b/source/frontend/parser/operators.cpp @@ -195,7 +195,7 @@ namespace parser { auto num = tokens[idx].str(); - if(tokens[idx] != TT::Number || num.find('.') != std::string::npos) + if(tokens[idx] != TT::IntegerNumber) expected(tokens[idx].loc, "integer value for precedence", num); int prec = std::stoi(num); @@ -260,9 +260,9 @@ namespace parser i = parseOperatorDecl(tokens, i, &kind, &oper); - if(kind == 1) infix[oper.symbol] = oper; - else if(kind == 2) prefix[oper.symbol] = oper; - else if(kind == 3) postfix[oper.symbol] = oper; + if(kind == 1) infix[oper.symbol] = oper; + else if(kind == 2) prefix[oper.symbol] = oper; + else if(kind == 3) postfix[oper.symbol] = oper; } else if(tok == TT::Export || tok == TT::Import) { diff --git a/source/frontend/parser/toplevel.cpp b/source/frontend/parser/toplevel.cpp index c2bf85d9..f722171e 100644 --- a/source/frontend/parser/toplevel.cpp +++ b/source/frontend/parser/toplevel.cpp @@ -146,17 +146,6 @@ namespace parser st.nativeWordSizeStillValid = false; } break; - case TT::Attr_Platform: { - - auto ret = parsePlatformDefn(st); - - if(ret) // sometimes we set a setting, but it doesn't need to have an AST node. - root->statements.push_back(ret); - - st.importsStillValid = false; - st.nativeWordSizeStillValid = false; - } break; - case TT::Namespace: { st.eat(); Token tok = st.front(); diff --git a/source/frontend/parser/type.cpp b/source/frontend/parser/type.cpp index 679eca32..cd1a632a 100644 --- a/source/frontend/parser/type.cpp +++ b/source/frontend/parser/type.cpp @@ -35,135 +35,6 @@ namespace parser - ClassDefn* parseClass(State& st) - { - iceAssert(st.front() == TT::Class); - st.eat(); - - if(st.front() != TT::Identifier) - expectedAfter(st, "identifier", "'struct'", st.front().str()); - - ClassDefn* defn = util::pool(st.loc()); - defn->name = st.eat().str(); - - // check for generic function - if(st.front() == TT::LAngle) - { - st.eat(); - // parse generic - if(st.front() == TT::RAngle) - error(st, "empty type parameter lists are not allowed"); - - defn->generics = parseGenericTypeList(st); - } - - st.skipWS(); - if(st.front() == TT::Colon) - { - // the inheritance list. - st.eat(); - - while(true) - { - defn->bases.push_back(parseType(st)); - if(st.front() == TT::Comma) - { - st.pop(); - continue; - } - else - { - break; - } - } - } - - st.skipWS(); - if(st.front() != TT::LBrace) - expectedAfter(st, "'{'", "'class'", st.front().str()); - - st.enterStructBody(); - - auto blk = parseBracedBlock(st).val(); - for(auto s : blk->statements) - { - if(auto v = dcast(VarDefn, s)) - { - if(v->type == pts::InferredType::get()) - error(v, "class fields must have types explicitly specified"); - - v->isField = true; - defn->fields.push_back(v); - } - else if(auto f = dcast(FuncDefn, s)) - { - addSelfToMethod(f, f->isMutating); - defn->methods.push_back(f); - } - else if(auto t = dcast(TypeDefn, s)) - { - defn->nestedTypes.push_back(t); - } - else if(auto sd = dcast(StaticDecl, s)) - { - if(auto fn = dcast(FuncDefn, sd->actual)) - defn->staticMethods.push_back(fn); - - else if(auto vr = dcast(VarDefn, sd->actual)) - defn->staticFields.push_back(vr); - - else - error(st, "unsupported static statement in class body"); - } - else if(auto init = dcast(InitFunctionDefn, s)) - { - addSelfToMethod(init, /* mutating: */ true); - - if(init->name == "init") - { - defn->initialisers.push_back(init); - } - else if(init->name == "deinit") - { - if(defn->deinitialiser) - error(init, "deinitialisers cannot be overloaded"); - - defn->deinitialiser = init; - } - else if(init->name == "copy") - { - if(defn->copyInitialiser) - error(init, "copy initialisers cannot be overloaded"); - - defn->copyInitialiser = init; - } - else if(init->name == "move") - { - if(defn->moveInitialiser) - error(init, "move initialisers cannot be overloaded"); - - defn->moveInitialiser = init; - } - else - { - error(s, "wtf? '%s'", init->name); - } - } - else - { - error(s, "unsupported expression or statement in class body"); - } - } - - if(!blk->deferredStatements.empty()) - error(blk->deferredStatements[0], "unsupported expression or statement in class body"); - - st.leaveStructBody(); - return defn; - } - - - @@ -710,9 +581,9 @@ namespace parser return util::pool(loc, elm); } - else if(st.front() != TT::Number) + else if(st.front() != TT::IntegerNumber) { - expected(st, "positive, non-zero size for fixed array", st.front().str()); + expected(st, "positive, non-zero integer size for fixed array", st.front().str()); } else { @@ -731,16 +602,6 @@ namespace parser return util::pool(loc, elm, sz); } } - else if(st.front() == TT::RSquare) - { - // dynamic array. - if(mut) error(st.loc(), "dynamic arrays are always mutable, specifying 'mut' is unnecessary"); - - loc.len = st.loc().col - loc.col + st.loc().len; - - st.pop(); - return util::pool(loc, elm); - } else { expected(st.loc(), "']' in array type specifier", st.front().str()); @@ -867,10 +728,6 @@ namespace parser return pts::NamedType::create(unn->loc, unn->name); } - else if(st.front() == TT::Class) - { - error(st, "classes cannot be defined anonymously"); - } else { error(st, "unexpected token '%s' while parsing type", st.front().str()); diff --git a/source/frontend/pts.cpp b/source/frontend/pts.cpp index 81cd5b29..70bddd22 100644 --- a/source/frontend/pts.cpp +++ b/source/frontend/pts.cpp @@ -51,11 +51,6 @@ namespace pts return dcast(FixedArrayType, this); } - DynamicArrayType* Type::toDynamicArrayType() - { - return dcast(DynamicArrayType, this); - } - VariadicArrayType* Type::toVariadicArrayType() { return dcast(VariadicArrayType, this); @@ -92,11 +87,6 @@ namespace pts return dcast(FixedArrayType, this) != 0; } - bool Type::isDynamicArrayType() - { - return dcast(DynamicArrayType, this) != 0; - } - bool Type::isVariadicArrayType() { return dcast(VariadicArrayType, this) != 0; @@ -189,15 +179,6 @@ namespace pts return strprintf("[%s: %d]", b, std::to_string(this->size)); } - std::string DynamicArrayType::str() - { - std::string b = this->base->str(); - if(this->base->isFunctionType()) - b = "(" + b + ")"; - - return strprintf("[%s]", b); - } - std::string VariadicArrayType::str() { std::string b = this->base->str(); diff --git a/source/include/ast.h b/source/include/ast.h index 15a79117..03f97700 100644 --- a/source/include/ast.h +++ b/source/include/ast.h @@ -159,32 +159,9 @@ namespace ast Block* body = 0; bool isMutating = false; - - bool isVirtual = false; bool isOverride = false; }; - struct InitFunctionDefn : Parameterisable - { - InitFunctionDefn(const Location& l) : Parameterisable(l) { this->readableName = "class initialiser definition"; } - ~InitFunctionDefn() { } - - virtual std::string getKind() override { return "initialiser"; } - virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; - virtual TCResult generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; - - using Param = FuncDefn::Param; - - std::vector params; - - bool didCallSuper = false; - std::vector> superArgs; - - Block* body = 0; - FuncDefn* actualDefn = 0; - }; - - struct ForeignFuncDefn : Stmt { ForeignFuncDefn(const Location& l) : Stmt(l) { this->readableName = "foreign function definition"; } @@ -263,33 +240,6 @@ namespace ast }; - struct PlatformDefn : Stmt - { - PlatformDefn(const Location& l) : Stmt(l) { this->readableName = "platform-specific definition"; } - ~PlatformDefn() { } - - virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; - - enum class Type - { - Invalid, - Intrinsic, - IntegerType - }; - - Type defnType = Type::Invalid; - - // only valid if defnType == Intrinsic - ForeignFuncDefn* intrinsicDefn = 0; - - // only valid if defnType == IntegerType - std::string typeName; - size_t typeSizeInBits = 0; - }; - - - - @@ -436,31 +386,6 @@ namespace ast std::vector methods; }; - struct ClassDefn : TypeDefn - { - ClassDefn(const Location& l) : TypeDefn(l) { this->readableName = "class definition"; } - ~ClassDefn() { } - - virtual std::string getKind() override { return "class"; } - virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; - virtual TCResult generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) override; - - std::vector bases; - - std::vector initialisers; - InitFunctionDefn* deinitialiser = 0; - InitFunctionDefn* copyInitialiser = 0; - InitFunctionDefn* moveInitialiser = 0; - - std::vector fields; - std::vector methods; - - std::vector staticFields; - std::vector staticMethods; - - std::vector nestedTypes; - }; - struct EnumDefn : TypeDefn { EnumDefn(const Location& l) : TypeDefn(l) { this->readableName = "enum definition"; } @@ -747,12 +672,14 @@ namespace ast struct LitNumber : Expr { - LitNumber(const Location& l, const std::string& n) : Expr(l), num(n) { this->readableName = "number literal"; } + LitNumber(const Location& l, const std::string& n, bool flt) + : Expr(l), num(n), is_floating(flt) { this->readableName = "number literal"; } ~LitNumber() { } virtual TCResult typecheck(sst::TypecheckState* fs, fir::Type* infer = 0) override; std::string num; + bool is_floating; }; struct LitChar : Expr diff --git a/source/include/codegen.h b/source/include/codegen.h index 29fac0bc..2c61c09a 100644 --- a/source/include/codegen.h +++ b/source/include/codegen.h @@ -52,8 +52,6 @@ namespace cgn BlockPoint(sst::Block* b) : block(b) { } sst::Block* block = 0; - - std::vector refCountedValues; std::vector raiiValues; }; @@ -138,13 +136,6 @@ namespace cgn fir::Value* getDefaultValue(fir::Type* type); fir::Value* getConstructedStructValue(fir::StructType* str, const std::vector& args); - fir::Value* constructClassWithArguments(fir::ClassType* cls, sst::FunctionDefn* constr, const std::vector& args); - - fir::Value* callVirtualMethod(sst::FunctionCall* call); - - fir::ConstantValue* unwrapConstantNumber(fir::ConstantValue* cv); - fir::ConstantValue* unwrapConstantNumber(fir::ConstantNumber* cv, fir::Type* target); - CGResult getStructFieldImplicitly(std::string name); fir::Function* getOrDeclareLibCFunction(std::string name); @@ -183,16 +174,7 @@ namespace cgn std::pair getOperatorFunctionForTypes(fir::Type* a, fir::Type* b, std::string op); - bool isRefCountedType(fir::Type* type); - void incrementRefCount(fir::Value* val); - void decrementRefCount(fir::Value* val); - - void addRefCountedValue(fir::Value* val); - void removeRefCountedValue(fir::Value* val); - - std::vector getRefCountedValues(); - - void autoAssignRefCountedValue(fir::Value* lhs, fir::Value* rhs, bool isInitial); + void performAssignment(fir::Value* lhs, fir::Value* rhs, bool isInitial); void addRAIIOrRCValueIfNecessary(fir::Value* val, fir::Type* typeOverride = 0); diff --git a/source/include/gluecode.h b/source/include/gluecode.h index e2236881..179c2211 100644 --- a/source/include/gluecode.h +++ b/source/include/gluecode.h @@ -37,7 +37,6 @@ namespace fir struct ClassType; struct UnionType; struct ArraySliceType; - struct DynamicArrayType; } namespace sst @@ -53,106 +52,14 @@ namespace cgn { void printRuntimeError(CodegenState* cs, fir::Value* pos, const std::string& msg, const std::vector& args); - namespace string - { - fir::Function* getCloneFunction(CodegenState* cs); - fir::Function* getAppendFunction(CodegenState* cs); - fir::Function* getCompareFunction(CodegenState* cs); - fir::Function* getCharAppendFunction(CodegenState* cs); - fir::Function* getUnicodeLengthFunction(CodegenState* cs); - fir::Function* getConstructFromTwoFunction(CodegenState* cs); - fir::Function* getConstructWithCharFunction(CodegenState* cs); - fir::Function* getRefCountIncrementFunction(CodegenState* cs); - fir::Function* getRefCountDecrementFunction(CodegenState* cs); - fir::Function* getBoundsCheckFunction(CodegenState* cs, bool isDecomp); - } - namespace array { - fir::Function* getCloneFunction(CodegenState* cs, fir::Type* arrtype); - fir::Function* getAppendFunction(CodegenState* cs, fir::DynamicArrayType* arrtype); - fir::Function* getPopElementFromBackFunction(CodegenState* cs, fir::Type* arrtype); - fir::Function* getBoundsCheckFunction(CodegenState* cs, bool isPerformingDecomposition); - fir::Function* getElementAppendFunction(CodegenState* cs, fir::DynamicArrayType* arrtype); fir::Function* getCompareFunction(CodegenState* cs, fir::Type* arrtype, fir::Function* opf); - fir::Function* getConstructFromTwoFunction(CodegenState* cs, fir::DynamicArrayType* arrtype); - fir::Function* getIncrementArrayRefCountFunction(CodegenState* cs, fir::Type* arrtype); - fir::Function* getDecrementArrayRefCountFunction(CodegenState* cs, fir::Type* arrtype); - - fir::Function* getReserveExtraFunction(CodegenState* cs, fir::DynamicArrayType* arrtype); - fir::Function* getReserveAtLeastFunction(CodegenState* cs, fir::DynamicArrayType* arrtype); - - fir::Function* getSetElementsToValueFunction(CodegenState* cs, fir::Type* elmType); - fir::Function* getSetElementsToDefaultValueFunction(CodegenState* cs, fir::Type* elmType); - - fir::Function* getCallClassConstructorOnElementsFunction(CodegenState* cs, fir::ClassType* cls, sst::FunctionDefn* constr, - const std::vector& args); - } - - namespace saa_common - { - fir::Function* generateCloneFunction(CodegenState* cs, fir::Type* saa); - fir::Function* generateAppendFunction(CodegenState* cs, fir::Type* saa); - fir::Function* generateElementAppendFunction(CodegenState* cs, fir::Type* saa); - fir::Function* generateConstructFromTwoFunction(CodegenState* cs, fir::Type* saa); - fir::Function* generateConstructWithElementFunction(CodegenState* cs, fir::Type* saa); - - fir::Function* generateAppropriateAppendFunction(CodegenState* cs, fir::Type* saa, fir::Type* appendee); - - fir::Function* generateBoundsCheckFunction(CodegenState* cs, bool isstring, bool isDecomp); - - fir::Function* generateReserveExtraFunction(CodegenState* cs, fir::Type* saa); - fir::Function* generateReserveAtLeastFunction(CodegenState* cs, fir::Type* saa); - - fir::Value* makeNewRefCountPointer(CodegenState* cs, fir::Value* rc); - fir::Value* initSAAWithRefCount(CodegenState* cs, fir::Value* str, fir::Value* rc); - } - - namespace any - { - fir::Function* getRefCountIncrementFunction(CodegenState* cs); - fir::Function* getRefCountDecrementFunction(CodegenState* cs); - - fir::Function* generateCreateAnyWithValueFunction(CodegenState* cs, fir::Type* type); - fir::Function* generateGetValueFromAnyFunction(CodegenState* cs, fir::Type* type); } namespace misc { - fir::Function* getMallocWrapperFunction(CodegenState* cs); - fir::Function* getRangeSanityCheckFunction(CodegenState* cs); - fir::Name getCompare_FName(fir::Type* t); - fir::Name getSetElements_FName(fir::Type* t); - fir::Name getSetElementsDefault_FName(fir::Type* t); - fir::Name getCallClassConstructor_FName(fir::Type* t); - - fir::Name getClone_FName(fir::Type* t); - fir::Name getAppend_FName(fir::Type* t); - fir::Name getPopBack_FName(fir::Type* t); - fir::Name getMakeFromTwo_FName(fir::Type* t); - fir::Name getMakeFromOne_FName(fir::Type* t); - fir::Name getReserveExtra_FName(fir::Type* t); - fir::Name getAppendElement_FName(fir::Type* t); - fir::Name getReserveEnough_FName(fir::Type* t); - fir::Name getRecursiveRefcount_FName(fir::Type* t, bool incr); - - fir::Name getIncrRefcount_FName(fir::Type* t); - fir::Name getDecrRefcount_FName(fir::Type* t); - - fir::Name getLoopIncrRefcount_FName(fir::Type* t); - fir::Name getLoopDecrRefcount_FName(fir::Type* t); - - fir::Name getCreateAnyOf_FName(fir::Type* t); - fir::Name getGetValueFromAny_FName(fir::Type* t); - - fir::Name getBoundsCheck_FName(); - fir::Name getDecompBoundsCheck_FName(); - - fir::Name getMallocWrapper_FName(); - fir::Name getRangeSanityCheck_FName(); - - fir::Name getUtf8Length_FName(); } } } diff --git a/source/include/ir/constant.h b/source/include/ir/constant.h index 9a1238bd..6487d914 100644 --- a/source/include/ir/constant.h +++ b/source/include/ir/constant.h @@ -9,7 +9,6 @@ #include #include "value.h" -#include "mpreal/mpreal.h" namespace fir { @@ -28,36 +27,10 @@ namespace fir virtual std::string str(); - protected: + protected: ConstantValue(Type* type); }; - struct ConstantNumber : ConstantValue - { - friend struct Module; - - static ConstantNumber* get(ConstantNumberType* cnt, const mpfr::mpreal& n); - - int8_t getInt8() { return static_cast(this->number.toLLong()); } - int16_t getInt16() { return static_cast(this->number.toLLong()); } - int32_t getInt32() { return static_cast(this->number.toLLong()); } - int64_t getInt64() { return static_cast(this->number.toLLong()); } - uint8_t getUint8() { return static_cast(this->number.toULLong()); } - uint16_t getUint16() { return static_cast(this->number.toULLong()); } - uint32_t getUint32() { return static_cast(this->number.toULLong()); } - uint64_t getUint64() { return static_cast(this->number.toULLong()); } - - float getFloat() { return this->number.toFloat(); } - double getDouble() { return this->number.toDouble(); } - - virtual std::string str() override; - - protected: - ConstantNumber(ConstantNumberType* cnt, const mpfr::mpreal& n); - - mpfr::mpreal number; - }; - struct ConstantBool : ConstantValue { friend struct Module; @@ -67,7 +40,7 @@ namespace fir virtual std::string str() override; - protected: + protected: ConstantBool(bool val); bool value; @@ -96,7 +69,7 @@ namespace fir virtual std::string str() override; - protected: + protected: ConstantInt(Type* type, int64_t val); ConstantInt(Type* type, uint64_t val); @@ -118,7 +91,7 @@ namespace fir virtual std::string str() override; - protected: + protected: ConstantFP(Type* type, float val); ConstantFP(Type* type, double val); @@ -135,7 +108,7 @@ namespace fir virtual std::string str() override; - protected: + protected: ConstantArray(Type* type, const std::vector& vals); std::vector values; @@ -149,7 +122,7 @@ namespace fir virtual std::string str() override; - protected: + protected: ConstantStruct(StructType* st, const std::vector& members); std::vector members; }; @@ -165,7 +138,7 @@ namespace fir virtual std::string str() override; - protected: + protected: ConstantEnumCase(EnumType* en, ConstantInt* index, ConstantValue* value); ConstantInt* index = 0; @@ -181,7 +154,7 @@ namespace fir virtual std::string str() override; - protected: + protected: ConstantCharSlice(const std::string& str); std::string value; @@ -196,53 +169,11 @@ namespace fir virtual std::string str() override; - protected: + protected: ConstantTuple(const std::vector& mems); std::vector values; }; - struct ConstantDynamicArray : ConstantValue - { - friend struct Module; - - static ConstantDynamicArray* get(DynamicArrayType* type, ConstantValue* data, ConstantValue* length, ConstantValue* capacity); - static ConstantDynamicArray* get(ConstantArray* arr); - - ConstantValue* getData() { return this->data; } - ConstantValue* getLength() { return this->length; } - ConstantValue* getCapacity() { return this->capacity; } - - ConstantArray* getArray() { return this->arr; } - - virtual std::string str() override; - - protected: - ConstantDynamicArray(DynamicArrayType* type); - - ConstantValue* data = 0; - ConstantValue* length = 0; - ConstantValue* capacity = 0; - - ConstantArray* arr = 0; - }; - - // this is the 'string' type!! - struct ConstantDynamicString : ConstantValue - { - friend struct Module; - - static ConstantDynamicString* get(const std::string& s); - std::string getValue(); - - virtual std::string str() override; - - protected: - ConstantDynamicString(const std::string& s); - - std::string value; - }; - - struct ConstantArraySlice : ConstantValue { friend struct Module; @@ -254,7 +185,7 @@ namespace fir virtual std::string str() override; - protected: + protected: ConstantArraySlice(ArraySliceType* type); ConstantValue* data = 0; @@ -271,7 +202,7 @@ namespace fir virtual std::string str() override; - protected: + protected: ConstantBitcast(ConstantValue* v, Type* target); ConstantValue* value = 0; @@ -289,7 +220,7 @@ namespace fir virtual std::string str() override; - protected: + protected: GlobalValue(Module* mod, Type* type, LinkageType linkage, bool mut = false); Module* parentModule = 0; @@ -305,7 +236,7 @@ namespace fir virtual std::string str() override; - protected: + protected: ConstantValue* initValue = 0; }; } diff --git a/source/include/ir/instruction.h b/source/include/ir/instruction.h index 56c0faa4..90f5ecfe 100644 --- a/source/include/ir/instruction.h +++ b/source/include/ir/instruction.h @@ -99,7 +99,6 @@ namespace fir Value_StackAlloc, Value_CallFunction, Value_CallFunctionPointer, - Value_CallVirtualMethod, Value_Return, Value_GetPointerToStructMember, // equivalent to GEP(ptr*, ptrIndex, memberIndex) -- for structs. Value_GetStructMember, // equivalent to GEP(ptr*, 0, memberIndex) @@ -120,29 +119,11 @@ namespace fir Value_Store, Value_CreateLVal, - - // string-specific things - SAA_GetData, - SAA_SetData, - SAA_GetLength, - SAA_SetLength, - SAA_GetCapacity, - SAA_SetCapacity, - SAA_GetRefCountPtr, - SAA_SetRefCountPtr, - ArraySlice_GetData, ArraySlice_SetData, ArraySlice_GetLength, ArraySlice_SetLength, - Any_GetData, - Any_SetData, - Any_GetTypeID, - Any_SetTypeID, - Any_GetRefCountPtr, - Any_SetRefCountPtr, - Range_GetLower, Range_SetLower, Range_GetUpper, diff --git a/source/include/ir/irbuilder.h b/source/include/ir/irbuilder.h index 335847bd..5667e2c4 100644 --- a/source/include/ir/irbuilder.h +++ b/source/include/ir/irbuilder.h @@ -84,8 +84,6 @@ namespace fir Value* CallToFunctionPointer(Value* fn, FunctionType* ft, const std::vector& args, const std::string& vname = ""); - Value* CallVirtualMethod(ClassType* cls, FunctionType* ft, size_t index, const std::vector& args, const std::string& vname = ""); - Value* Return(Value* v); Value* ReturnVoid(); @@ -113,8 +111,6 @@ namespace fir Value* GEP2(Value* ptr, Value* ptrIndex, Value* elmIndex, const std::string& vname = ""); Value* ConstGEP2(Value* ptr, size_t ptrIndex, size_t elmIndex, const std::string& vname = ""); - void SetVtable(Value* ptr, Value* table); - void CondBranch(Value* condition, IRBlock* trueBlock, IRBlock* falseBlock); void UnCondBranch(IRBlock* target); @@ -134,46 +130,12 @@ namespace fir [[nodiscard]] Value* InsertValue(Value* val, const std::vector& inds, Value* elm, const std::string& vname = ""); - //! ACHTUNG ! - //* 'generic' function that works for both strings and dynamic arrays, - //* since they now function almost exactly the same. - //? SAA -- String Array Analogue - Value* GetSAAData(Value* str, const std::string& vname = ""); - Value* GetSAALength(Value* str, const std::string& vname = ""); - Value* GetSAACapacity(Value* str, const std::string& vname = ""); - Value* GetSAARefCount(Value* str, const std::string& vname = ""); - Value* GetSAARefCountPointer(Value* str, const std::string& vname = ""); - - [[nodiscard]] Value* SetSAARefCountPointer(Value* str, Value* val, const std::string& vname = ""); - [[nodiscard]] Value* SetSAACapacity(Value* str, Value* val, const std::string& vname = ""); - [[nodiscard]] Value* SetSAALength(Value* str, Value* val, const std::string& vname = ""); - [[nodiscard]] Value* SetSAAData(Value* str, Value* val, const std::string& vname = ""); - void SetSAARefCount(Value* str, Value* val); - - - Value* CreateSliceFromSAA(Value* str, bool mut, const std::string& vname = ""); - - - - Value* GetArraySliceData(Value* arr, const std::string& vname = ""); Value* GetArraySliceLength(Value* arr, const std::string& vname = ""); [[nodiscard]] Value* SetArraySliceData(Value* arr, Value* val, const std::string& vname = ""); [[nodiscard]] Value* SetArraySliceLength(Value* arr, Value* val, const std::string& vname = ""); - - Value* GetAnyData(Value* any, const std::string& vname = ""); - Value* GetAnyTypeID(Value* any, const std::string& vname = ""); - Value* GetAnyRefCount(Value* str, const std::string& vname = ""); - Value* GetAnyRefCountPointer(Value* any, const std::string& vname = ""); - - void SetAnyRefCount(Value* str, Value* val); - [[nodiscard]] Value* SetAnyData(Value* any, Value* val, const std::string& vname = ""); - [[nodiscard]] Value* SetAnyTypeID(Value* any, Value* val, const std::string& vname = ""); - [[nodiscard]] Value* SetAnyRefCountPointer(Value* str, Value* val, const std::string& vname = ""); - - Value* GetRangeLower(Value* range, const std::string& vname = ""); Value* GetRangeUpper(Value* range, const std::string& vname = ""); Value* GetRangeStep(Value* range, const std::string& vname = ""); diff --git a/source/include/ir/module.h b/source/include/ir/module.h index 3cd45960..cd25a09a 100644 --- a/source/include/ir/module.h +++ b/source/include/ir/module.h @@ -27,8 +27,6 @@ namespace fir GlobalVariable* tryGetGlobalVariable(const Name& id); GlobalVariable* getGlobalVariable(const Name& id); - GlobalVariable* getOrCreateVirtualTableForClass(ClassType* cls); - GlobalVariable* createGlobalString(const std::string& str); std::vector getGlobalVariables(); @@ -60,7 +58,6 @@ namespace fir void finaliseGlobalConstructors(); - const util::hash_map, GlobalVariable*>>& _getVtables() { return this->vtables; } const util::hash_map& _getIntrinsicFunctions() { return this->intrinsicFunctions; } const util::hash_map& _getGlobalStrings() { return this->globalStrings; } const util::hash_map& _getGlobals() { return this->globals; } @@ -70,7 +67,6 @@ namespace fir private: std::string moduleName; - util::hash_map, GlobalVariable*>> vtables; util::hash_map globalStrings; util::hash_map globals; diff --git a/source/include/ir/type.h b/source/include/ir/type.h index 2dc633b7..08da9ebd 100644 --- a/source/include/ir/type.h +++ b/source/include/ir/type.h @@ -93,18 +93,15 @@ namespace fir struct Type; struct Module; - struct AnyType; struct BoolType; struct EnumType; struct NullType; struct VoidType; struct ArrayType; - struct ClassType; struct RangeType; struct TraitType; struct TupleType; struct UnionType; - struct StringType; struct StructType; struct OpaqueType; struct PointerType; @@ -112,20 +109,14 @@ namespace fir struct RawUnionType; struct PrimitiveType; struct ArraySliceType; - struct DynamicArrayType; struct UnionVariantType; - struct ConstantNumberType; struct PolyPlaceholderType; struct ConstantValue; struct ConstantArray; struct Function; - ConstantNumberType* unifyConstantTypes(ConstantNumberType* a, ConstantNumberType* b); - Type* getBestFitTypeForConstant(ConstantNumberType* cnt); - int getCastDistance(Type* from, Type* to); - bool isRefCountedType(Type* ty); void setNativeWordSizeInBits(size_t sz); size_t getNativeWordSizeInBits(); @@ -144,14 +135,12 @@ namespace fir { Invalid, - Any, Null, Void, Enum, Bool, Array, Tuple, - Class, Range, Union, Trait, @@ -163,9 +152,7 @@ namespace fir RawUnion, Primitive, ArraySlice, - DynamicArray, UnionVariant, - ConstantNumber, PolyPlaceholder, }; @@ -197,8 +184,6 @@ namespace fir Type* getArrayElementType(); PolyPlaceholderType* toPolyPlaceholderType(); - ConstantNumberType* toConstantNumberType(); - DynamicArrayType* toDynamicArrayType(); UnionVariantType* toUnionVariantType(); ArraySliceType* toArraySliceType(); PrimitiveType* toPrimitiveType(); @@ -207,17 +192,14 @@ namespace fir PointerType* toPointerType(); OpaqueType* toOpaqueType(); StructType* toStructType(); - StringType* toStringType(); TraitType* toTraitType(); RangeType* toRangeType(); - ClassType* toClassType(); UnionType* toUnionType(); TupleType* toTupleType(); ArrayType* toArrayType(); BoolType* toBoolType(); EnumType* toEnumType(); NullType* toNullType(); - AnyType* toAnyType(); bool isPointerTo(Type* other); bool isPointerElementOf(Type* other); @@ -225,7 +207,6 @@ namespace fir bool isTraitType(); bool isUnionType(); bool isTupleType(); - bool isClassType(); bool isStructType(); bool isPackedStruct(); bool isRawUnionType(); @@ -234,11 +215,9 @@ namespace fir bool isRangeType(); bool isCharType(); - bool isStringType(); bool isOpaqueType(); - bool isAnyType(); bool isEnumType(); bool isArrayType(); bool isIntegerType(); @@ -248,7 +227,6 @@ namespace fir bool isFloatingPointType(); bool isArraySliceType(); - bool isDynamicArrayType(); bool isVariadicArrayType(); bool isCharSliceType(); @@ -261,7 +239,6 @@ namespace fir bool isMutablePointer(); bool isImmutablePointer(); - bool isConstantNumberType(); bool isPolyPlaceholderType(); bool containsPlaceholders(); @@ -323,11 +300,8 @@ namespace fir static PointerType* getMutUint128Ptr(); static ArraySliceType* getCharSlice(bool mut); - static StringType* getString(); static RangeType* getRange(); - static AnyType* getAny(); - static PrimitiveType* getNativeWord(); static PrimitiveType* getNativeUWord(); @@ -434,36 +408,6 @@ namespace fir static NullType* get(); }; - - // special case -- the type also needs to store the number, to know things like - // whether it's signed, negative, an integer, and other stuff. - struct ConstantNumberType : Type - { - friend struct Type; - - bool isSigned(); - bool isFloating(); - size_t getMinBits(); - - virtual std::string str() override; - virtual std::string encodedStr() override; - virtual bool isTypeEqual(Type* other) override; - virtual Type* substitutePlaceholders(const util::hash_map& subst) override; - - static ConstantNumberType* get(bool neg, bool flt, size_t bits); - - virtual ~ConstantNumberType() override { } - - - protected: - ConstantNumberType(bool neg, bool floating, size_t bits); - - bool _floating = false; - bool _signed = false; - size_t _bits = 0; - }; - - struct PolyPlaceholderType : Type { friend struct Type; @@ -806,114 +750,6 @@ namespace fir - struct ClassType : Type - { - friend struct Type; - friend struct Module; - - // methods - Name getTypeName(); - size_t getElementCount(); - // Type* getElementN(size_t n); - Type* getElement(const std::string& name); - bool hasElementWithName(const std::string& name); - size_t getAbsoluteElementIndex(const std::string& name); - const std::vector& getElements(); - std::vector getAllElementsIncludingBase(); - const std::vector& getNameList(); - - const util::hash_map& getElementNameMap(); - - const std::vector& getMethods(); - std::vector getMethodsWithName(const std::string& id); - Function* getMethodWithType(FunctionType* ftype); - - const std::vector& getInitialiserFunctions(); - void setInitialiserFunctions(const std::vector& list); - - Function* getInlineInitialiser(); - void setInlineInitialiser(Function* fn); - - Function* getInlineDestructor(); - void setInlineDestructor(Function* fn); - - void setMembers(const std::vector>& members); - void setMethods(const std::vector& methods); - - ClassType* getBaseClass(); - void setBaseClass(ClassType* ty); - - void setDestructor(Function* f); - void setCopyConstructor(Function* f); - void setMoveConstructor(Function* f); - - Function* getDestructor(); - Function* getCopyConstructor(); - Function* getMoveConstructor(); - - void addTraitImpl(TraitType* trt); - bool implementsTrait(TraitType* trt); - std::vector getImplementedTraits(); - - bool hasParent(Type* base); - - void addVirtualMethod(Function* method); - size_t getVirtualMethodIndex(const std::string& name, FunctionType* ft); - - size_t getVirtualMethodCount(); - - virtual std::string str() override; - virtual std::string encodedStr() override; - virtual bool isTypeEqual(Type* other) override; - virtual Type* substitutePlaceholders(const util::hash_map& subst) override; - - // protected constructor - virtual ~ClassType() override { } - protected: - ClassType(const Name& name, const std::vector>& mems, const std::vector& methods, - const std::vector& inits); - - - // fields (protected) - Name className; - std::vector typeList; - std::vector nameList; - std::vector methodList; - std::vector initialiserList; - - std::vector implTraits; - - util::hash_map indexMap; - util::hash_map classMembers; - util::hash_map> classMethodMap; - - //* how it works is that we will add in the mappings from the base class, - //* and for our own matching virtual methods, we'll map to the same index. - - - size_t virtualMethodCount = 0; - // util::hash_map virtualMethodMap; - util::hash_map reverseVirtualMethodMap; - - //* note: we do it this way (where we *EXCLUDE THE SELF POINTER*), because it's just easier -- to compare, and everything. - //* we really don't have a use for mapping a Function to an index, only the other way. - std::map>, size_t> virtualMethodMap; - - ClassType* baseClass = 0; - - Function* inlineInitialiser = 0; - Function* inlineDestructor = 0; - - Function* destructor = 0; - Function* copyConstructor = 0; - Function* moveConstructor = 0; - - // static funcs - public: - static ClassType* createWithoutBody(const Name& name); - static ClassType* create(const Name& name, const std::vector>& members, - const std::vector& methods, const std::vector& inits); - }; struct EnumType : Type @@ -984,31 +820,6 @@ namespace fir }; - struct DynamicArrayType : Type - { - friend struct Type; - - // methods - Type* getElementType(); - - virtual std::string str() override; - virtual std::string encodedStr() override; - virtual bool isTypeEqual(Type* other) override; - virtual Type* substitutePlaceholders(const util::hash_map& subst) override; - - // protected constructor - virtual ~DynamicArrayType() override { } - protected: - DynamicArrayType(Type* elmType); - - // fields - Type* arrayElementType; - - // static funcs - public: - static DynamicArrayType* get(Type* elementType); - }; - struct ArraySliceType : Type { @@ -1110,46 +921,8 @@ namespace fir }; - struct StringType : Type - { - friend struct Type; - - virtual std::string str() override; - virtual std::string encodedStr() override; - virtual bool isTypeEqual(Type* other) override; - virtual Type* substitutePlaceholders(const util::hash_map& subst) override; - - - // protected constructor - virtual ~StringType() override { } - protected: - StringType(); - - public: - static StringType* get(); - }; - - struct AnyType : Type - { - friend struct Type; - - virtual std::string str() override; - virtual std::string encodedStr() override; - virtual bool isTypeEqual(Type* other) override; - virtual Type* substitutePlaceholders(const util::hash_map& subst) override; - - - // protected constructor - virtual ~AnyType() override { } - protected: - AnyType(); - - public: - static AnyType* get(); - }; - struct OpaqueType : Type { diff --git a/source/include/lexer.h b/source/include/lexer.h index 6e580498..8c27cbde 100644 --- a/source/include/lexer.h +++ b/source/include/lexer.h @@ -12,7 +12,6 @@ namespace lexer { Invalid, Func, - Class, Import, Var, Val, @@ -111,7 +110,8 @@ namespace lexer DoubleColon, Identifier, UnicodeSymbol, - Number, + IntegerNumber, + FloatingNumber, StringLiteral, CharacterLiteral, NewLine, @@ -125,7 +125,6 @@ namespace lexer Attr_EntryFn, Attr_NoMangle, Attr_Operator, - Attr_Platform, Attr_ATTRS_END, diff --git a/source/include/parser_internal.h b/source/include/parser_internal.h index 56acfaa8..5f44e5d4 100644 --- a/source/include/parser_internal.h +++ b/source/include/parser_internal.h @@ -447,13 +447,11 @@ namespace parser DecompMapping parseTupleDecomp(State& st); std::tuple parseFunctionDecl(State& st); - ast::PlatformDefn* parsePlatformDefn(State& st); ast::RunDirective* parseRunDirective(State& st); ast::TraitDefn* parseTrait(State& st); ast::EnumDefn* parseEnum(State& st); - ast::ClassDefn* parseClass(State& st); ast::StaticDecl* parseStaticDecl(State& st); PResult parseStruct(State& st, bool nameless); @@ -461,10 +459,6 @@ namespace parser ast::Expr* parseDollarExpr(State& st); - ast::InitFunctionDefn* parseInitFunction(State& st); - ast::InitFunctionDefn* parseDeinitFunction(State& st); - ast::InitFunctionDefn* parseCopyOrMoveInitFunction(State& st, const std::string& name); - ast::DeallocOp* parseDealloc(State& st); ast::SizeofOp* parseSizeof(State& st); diff --git a/source/include/platform.h b/source/include/platform.h index 6ff8e832..a97db091 100644 --- a/source/include/platform.h +++ b/source/include/platform.h @@ -66,8 +66,6 @@ #define PLATFORM_EXPORT_FUNCTION extern "C" __attribute__((visibility("default"))) #endif - #define REFCOUNT_SIZE 8 - namespace platform { extern filehandle_t InvalidFileHandle; diff --git a/source/include/polymorph.h b/source/include/polymorph.h index aa017f0c..c342df16 100644 --- a/source/include/polymorph.h +++ b/source/include/polymorph.h @@ -109,7 +109,6 @@ namespace sst Slice, Pointer, FixedArray, - DynamicArray, VariadicArray, }; diff --git a/source/include/pts.h b/source/include/pts.h index e8ef20eb..73fd77da 100644 --- a/source/include/pts.h +++ b/source/include/pts.h @@ -21,7 +21,6 @@ namespace pts struct TupleType; struct ArraySliceType; struct FixedArrayType; - struct DynamicArrayType; struct VariadicArrayType; struct FunctionType; @@ -38,7 +37,6 @@ namespace pts FunctionType* toFunctionType(); FixedArrayType* toFixedArrayType(); ArraySliceType* toArraySliceType(); - DynamicArrayType* toDynamicArrayType(); VariadicArrayType* toVariadicArrayType(); bool isNamedType(); @@ -47,7 +45,6 @@ namespace pts bool isFunctionType(); bool isArraySliceType(); bool isFixedArrayType(); - bool isDynamicArrayType(); bool isVariadicArrayType(); Location loc; @@ -119,16 +116,6 @@ namespace pts }; - // int[x], where x is *not* a literal - struct DynamicArrayType : Type - { - virtual ~DynamicArrayType() { } - explicit DynamicArrayType(const Location& l, pts::Type* b) : Type(l), base(b) { } - virtual std::string str() override; - - pts::Type* base = 0; - }; - struct VariadicArrayType : Type { diff --git a/source/include/repl.h b/source/include/repl.h deleted file mode 100644 index d2d144dd..00000000 --- a/source/include/repl.h +++ /dev/null @@ -1,48 +0,0 @@ -// repl.h -// Copyright (c) 2019, zhiayang -// Licensed under the Apache License Version 2.0. - -#pragma once -#include "defs.h" - -#include - - -namespace ztmu -{ - struct State; -} - - -namespace repl -{ - struct State; - - void start(); - void setupEnvironment(); - - bool processLine(const std::string& line); - std::optional parseAndTypecheck(const std::string& line, bool* needmore); - - bool runCommand(const std::string& command, ztmu::State* consoleState); - - // used to save/restore if we wanna do weird things. - void setEnvironment(State* st); - State* getEnvironment(); - - void saveHistory(const std::vector>& history); - std::vector> loadHistory(); - - - template - static void error(const std::string& fmt, Args&&... args) - { - fprintf(stderr, " %s*%s %s\n", COLOUR_RED_BOLD, COLOUR_RESET, zpr::sprint(fmt, args...).c_str()); - } - - template - static void log(const std::string& fmt, Args&&... args) - { - printf(" %s*%s %s\n", COLOUR_GREEN_BOLD, COLOUR_RESET, zpr::sprint(fmt, args...).c_str()); - } -} diff --git a/source/include/sst.h b/source/include/sst.h index 27100488..52b663b2 100644 --- a/source/include/sst.h +++ b/source/include/sst.h @@ -6,11 +6,6 @@ #include "defs.h" #include "sst_expr.h" - -#include "mpreal/mpreal.h" - - - namespace fir { struct Type; @@ -345,7 +340,6 @@ namespace sst struct StructDefn; - struct ClassDefn; struct StructConstructorCall : Expr { StructConstructorCall(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "struct constructor call"; } @@ -357,26 +351,6 @@ namespace sst std::vector arguments; }; - struct ClassConstructorCall : Expr - { - ClassConstructorCall(const Location& l, fir::Type* t) : Expr(l, t) { this->readableName = "class constructor call"; } - ~ClassConstructorCall() { } - - virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; - - ClassDefn* classty = 0; - FunctionDefn* target = 0; - std::vector arguments; - }; - - struct BaseClassConstructorCall : ClassConstructorCall - { - BaseClassConstructorCall(const Location& l, fir::Type* t) : ClassConstructorCall(l, t) { this->readableName = "base class constructor call"; } - ~BaseClassConstructorCall() { } - - virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; - }; - struct VarDefn; struct VarRef : Expr @@ -483,7 +457,11 @@ namespace sst virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; - mpfr::mpreal num; + bool is_floating = false; + union { + uint64_t integer; + double floating; + }; }; struct LiteralString : Expr @@ -636,7 +614,6 @@ namespace sst Block* body = 0; bool needReturnVoid = false; - bool isVirtual = false; bool isOverride = false; bool isMutating = false; @@ -733,27 +710,6 @@ namespace sst }; - struct ClassDefn : StructDefn - { - ClassDefn(const Location& l) : StructDefn(l) { this->readableName = "class definition"; } - ~ClassDefn() { } - - virtual std::string getKind() override { return "class"; } - virtual CGResult _codegen(cgn::CodegenState* cs, fir::Type* inferred = 0) override; - - - ClassDefn* baseClass = 0; - - std::vector nestedTypes; - std::vector staticFields; - std::vector staticMethods; - std::vector initialisers; - - FunctionDefn* deinitialiser = 0; - FunctionDefn* copyInitialiser = 0; - FunctionDefn* moveInitialiser = 0; - }; - struct EnumCaseDefn : Defn { diff --git a/source/include/string_consts.h b/source/include/string_consts.h index a96826bb..d9980b82 100644 --- a/source/include/string_consts.h +++ b/source/include/string_consts.h @@ -14,15 +14,10 @@ namespace strs namespace names { - namespace saa + namespace array { - inline constexpr auto FN_APPEND = "append"; - inline constexpr auto FN_CLONE = "clone"; - inline constexpr auto FIELD_LENGTH = "length"; - inline constexpr auto FIELD_POINTER = "ptr"; - inline constexpr auto FIELD_REFCOUNT = "refcount"; - inline constexpr auto FIELD_CAPACITY = "capacity"; + inline constexpr auto FIELD_POINTER = "data"; } namespace range @@ -40,22 +35,6 @@ namespace strs inline constexpr auto FIELD_NAME = "name"; } - namespace string - { - inline constexpr auto FIELD_COUNT = "count"; - } - - namespace array - { - inline constexpr auto FN_POP = "pop"; - } - - namespace any - { - inline constexpr auto FIELD_TYPEID = "id"; - inline constexpr auto FIELD_REFCOUNT = "refcount"; - } - namespace support { inline constexpr auto RAII_TRAIT_DROP = "raii_trait::drop"; diff --git a/source/include/typecheck.h b/source/include/typecheck.h index 4d73b5d1..87c76c3a 100644 --- a/source/include/typecheck.h +++ b/source/include/typecheck.h @@ -34,11 +34,6 @@ namespace ast struct Parameterisable; } -namespace fir -{ - struct ConstantNumberType; -} - namespace sst { namespace poly @@ -217,8 +212,6 @@ namespace sst DecompMapping typecheckDecompositions(const DecompMapping& bind, fir::Type* rhs, bool immut, bool allowref); }; - fir::Type* inferCorrectTypeForLiteral(fir::ConstantNumberType* lit); - bool isDuplicateOverload(const std::vector& a, const std::vector& b); int getOverloadDistance(const std::vector& a, const std::vector& b); diff --git a/source/main.cpp b/source/main.cpp index 7713ac40..cfc93b31 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -3,7 +3,6 @@ // Licensed under the Apache License Version 2.0. #include "defs.h" -#include "repl.h" #include "errors.h" #include "backend.h" #include "frontend.h" @@ -165,9 +164,7 @@ int main(int argc, char** argv) platform::compiler::performSelfDlOpen(); auto [ input_file, output_file ] = frontend::parseCmdLineOpts(argc, argv); - - if(frontend::getIsReplMode()) repl::start(); - else compile(input_file, output_file); + compile(input_file, output_file); return 0; diff --git a/source/misc/identifier.cpp b/source/misc/identifier.cpp index ef737302..611c938c 100644 --- a/source/misc/identifier.cpp +++ b/source/misc/identifier.cpp @@ -178,10 +178,10 @@ namespace zpr { switch(x) { - case VisibilityLevel::Invalid: return "invalid"; - case VisibilityLevel::Public: return "public"; - case VisibilityLevel::Private: return "private"; - case VisibilityLevel::Internal: return "internal"; + case VisibilityLevel::Invalid: return "invalid"; + case VisibilityLevel::Public: return "public"; + case VisibilityLevel::Private: return "private"; + case VisibilityLevel::Internal: return "internal"; default: return "unknown"; } } diff --git a/source/platform/platform.cpp b/source/platform/platform.cpp index 8950b43e..be4bad23 100644 --- a/source/platform/platform.cpp +++ b/source/platform/platform.cpp @@ -342,11 +342,6 @@ namespace platform { #if OS_WINDOWS { - // auto checkFileExists = [](const TCHAR* szPath) -> bool { - // DWORD dwAttrib = GetFileAttributes(szPath); - // return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); - // }; - std::string p = partial; std::replace(p.begin(), p.end(), '/', '\\'); diff --git a/source/repl/commands.cpp b/source/repl/commands.cpp deleted file mode 100644 index e80450be..00000000 --- a/source/repl/commands.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// commands.cpp -// Copyright (c) 2019, zhiayang -// Licensed under the Apache License Version 2.0. - -#include - -#include "defs.h" -#include "repl.h" -#include "ztmu.h" - -#include "sst.h" -#include "ir/type.h" - -namespace repl -{ - static void print_help(); - static void print_type(const std::string& expr); - - bool runCommand(const std::string& s, ztmu::State* consoleState) - { - if(s == "q") - { - repl::log("exiting repl"); - return true; - } - else if(s == "reset") - { - repl::setupEnvironment(); - repl::log("environment reset"); - } - else if(s == "help" || s == "?") - { - print_help(); - } - else if(s.find("t ") == 0) - { - print_type(s.substr(2)); - } - else if(s.find("clear_history") == 0) - { - // just loading an empty history will effectively clear the history. - consoleState->loadHistory({ }); - } - else - { - repl::error("invalid command '%s'", s); - } - - return false; - } - - - - - - - static void print_type(const std::string& line) - { - bool needmore = false; - auto stmt = repl::parseAndTypecheck(line, &needmore); - if(needmore) - { - repl::error("':t' does not support continuations"); - } - else if(!stmt) - { - repl::error("invalid expression"); - } - else if(auto expr = dcast(sst::Expr, *stmt)) - { - zpr::println("%s%s%s: %s", COLOUR_GREY_BOLD, line, COLOUR_RESET, expr->type); - } - else - { - repl::error("'%s' is not an expression", (*stmt)->readableName); - } - } - - - - static std::vector helpLines = { - zpr::sprint(""), - zpr::sprint("%s*%s overview %s*%s", COLOUR_GREEN_BOLD, COLOUR_RESET, COLOUR_GREEN_BOLD, COLOUR_RESET), - zpr::sprint("\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e"), - zpr::sprint("The repl accepts Flax expressions and statements; press enter to evaluate the currently entered" - " input. If the input was incomplete (eg. ending with a '{'), then the repl will enter a multi-line continuation" - " mode. In either case, use the standard keybindings (arrow keys, home/end, etc.) to navigate."), - zpr::sprint(""), - zpr::sprint("Any definitions (eg. variables, functions) will be treated as if they were declared at global" - " scope, while expressions and statements (eg. loops, arithmetic) will be treated as if they were" - " written in a function body."), - zpr::sprint(""), - zpr::sprint("Expressions with values (eg. 3 + 1) will be given monotonic identifiers (eg. %s_0%s, %s_1%s) that" - " can be used like any other identifier in code.", COLOUR_BLUE, COLOUR_RESET, COLOUR_BLUE, COLOUR_RESET), - zpr::sprint(""), - zpr::sprint("Commands begin with ':', and modify the state of the repl or perform other meta-actions."), - - zpr::sprint(""), - zpr::sprint("%s*%s commands %s*%s", COLOUR_GREEN_BOLD, COLOUR_RESET, COLOUR_GREEN_BOLD, COLOUR_RESET), - zpr::sprint("\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e\u203e"), - zpr::sprint(" :? / :help - display help (this listing)"), - zpr::sprint(" :q - quit the repl"), - zpr::sprint(" :reset - reset the environment, discarding all existing definitions"), - zpr::sprint(" :clear_history - clear the history of things"), - zpr::sprint(" :t - display the type of an expression"), - }; - - static void print_help() - { - auto xs = ztmu::prettyFormatTextBlock(helpLines, " ", " "); - for(const auto& x : xs) - zpr::println(x); - } - -} - - - - - - diff --git a/source/repl/driver.cpp b/source/repl/driver.cpp deleted file mode 100644 index 6bba38b2..00000000 --- a/source/repl/driver.cpp +++ /dev/null @@ -1,149 +0,0 @@ -// driver.cpp -// Copyright (c) 2019, zhiayang -// Licensed under the Apache License Version 2.0. - -#include - -#include "repl.h" -#include "frontend.h" - -#define ZTMU_CREATE_IMPL 1 -#include "ztmu.h" - -namespace repl -{ - static constexpr const char* PROMPT_STRING = COLOUR_BLUE_BOLD " * " COLOUR_GREY_BOLD ">" COLOUR_RESET " "; - static constexpr const char* WRAP_PROMPT_STRING = COLOUR_GREY_BOLD " |" COLOUR_RESET " "; - static constexpr const char* CONT_PROMPT_STRING = COLOUR_YELLOW_BOLD ".. " COLOUR_GREY_BOLD ">" COLOUR_RESET " "; - - static constexpr const char* EXTRA_INDENT = " "; - static constexpr size_t EXTRA_INDENT_LEN = std::char_traits::length(EXTRA_INDENT); - - void start() - { - zpr::println("flax repl -- version %s", frontend::getVersion()); - zpr::println("type %s:?%s for help\n", COLOUR_GREEN_BOLD, COLOUR_RESET); - - repl::setupEnvironment(); - - auto st = ztmu::State(); - st.setPrompt(PROMPT_STRING); - st.setContPrompt(CONT_PROMPT_STRING); - st.setWrappedPrompt(WRAP_PROMPT_STRING); - st.setMessageOnControlC(zpr::sprint("%s(use %s:q%s to quit)%s", COLOUR_GREY_BOLD, COLOUR_GREEN, COLOUR_GREY_BOLD, COLOUR_RESET)); - - // temporary. - st.enableExitOnEmptyControlC(); - - // load the history. - st.loadHistory(repl::loadHistory()); - - // setup the console (on windows, this changes to utf8 codepage.) - st.setupConsole(); - - // we need to put this up here, so the handler can capture it. - int indentLevel = 0; - - st.setKeyHandler(static_cast('}'), [&indentLevel](ztmu::State* st, ztmu::Key k) -> ztmu::HandlerAction { - // a bit dirty, but we just do this -- if we can find the indent at the back, then remove it. - auto line = st->getCurrentLine(); - if(indentLevel > 0 && line.size() >= 2 && line.find(EXTRA_INDENT, line.size() - EXTRA_INDENT_LEN) != -1) - { - st->setCurrentLine(line.substr(0, line.size() - 2)); - indentLevel--; - } - - return ztmu::HandlerAction::CONTINUE; - }); - - while(auto line = st.read()) - { - auto input = std::string(*line); - - if(input.empty()) - continue; - - // commands start with ':', but also allow '::' path-prefix. - if(input[0] == ':' && input.find("::") != 0) - { - auto quit = repl::runCommand(input.substr(1), &st); - if(quit) break; - } - else if(bool needmore = repl::processLine(input); needmore) - { - size_t last_indented_line = 0; - auto calc_indent = [&last_indented_line, &st](char c) -> int { - - // note: we use +1 so that last_indented_line is 1-indexed. this - // entire thing is so we don't get increasing indentation levels if - // we delete and re-enter on a brace. - if(last_indented_line == 0 || st.lineIdx + 1 > last_indented_line) - { - switch(c) - { - case '{': [[fallthrough]]; - case '(': [[fallthrough]]; - case '[': [[fallthrough]]; - case ',': { - last_indented_line = st.lineIdx + 1; - return 1; - } - } - } - - return 0; - }; - - auto join_lines = [](const std::vector& lines) -> std::string { - std::string ret; - for(const auto& l : lines) - ret += "\n" + l; - - return ret; - }; - - indentLevel = calc_indent(input.back()); - - // read more. - while(auto lines = st.readContinuation(std::string(indentLevel * EXTRA_INDENT_LEN, ' '))) - { - auto input = join_lines(*lines); - indentLevel += calc_indent(input.back()); - - needmore = repl::processLine(input); - - if(!needmore) - break; - } - } - - st.addPreviousInputToHistory(); - - // add an extra line - printf("\n"); - } - - // save the history. - repl::saveHistory(st.getHistory()); - - // restore the console. - st.unsetupConsole(); - } -} - - - - - - - - - - - - - - - - - diff --git a/source/repl/execute.cpp b/source/repl/execute.cpp deleted file mode 100644 index 36ec56c3..00000000 --- a/source/repl/execute.cpp +++ /dev/null @@ -1,224 +0,0 @@ -// execute.cpp -// Copyright (c) 2019, zhiayang -// Licensed under the Apache License Version 2.0. - -#include "repl.h" -#include "parser.h" -#include "frontend.h" -#include "parser_internal.h" - -#include "codegen.h" -#include "typecheck.h" - -#include "ir/module.h" -#include "ir/interp.h" -#include "ir/irbuilder.h" - -#include "memorypool.h" - -// defined in codegen/directives.cpp -fir::ConstantValue* magicallyRunExpressionAtCompileTime(cgn::CodegenState* cs, sst::Stmt* stmt, fir::Type* infer, - const fir::Name& fname, fir::interp::InterpState* is = 0); - -namespace repl -{ - struct State - { - State() - { - auto modname = "__repl_mod__"; - - this->module = new fir::Module(modname); - - sst::StateTree* tree = new sst::StateTree(modname, 0); - this->fs = new sst::TypecheckState(tree); - this->cs = new cgn::CodegenState(fir::IRBuilder(this->module)); - this->cs->module = this->module; - - - this->interpState = new fir::interp::InterpState(this->module); - this->interpState->initialise(/* runGlobalInit: */ true); - - // so we don't crash, give us a starting location. - this->cs->pushLoc(Location()); - } - - ~State() - { - delete this->interpState; - delete this->cs; - delete this->fs; - delete this->module; - } - - fir::Module* module; - cgn::CodegenState* cs; - sst::TypecheckState* fs; - fir::interp::InterpState* interpState; - - size_t fnCounter = 0; - size_t varCounter = 0; - }; - - static State* state = 0; - void setupEnvironment() - { - if(state) - delete state; - - state = new State(); - } - - void setEnvironment(State* st) - { - state = st; - } - - State* getEnvironment() - { - return state; - } - - - std::optional parseAndTypecheck(const std::string& line, bool* needmore) - { - std::string replName = ""; - - frontend::CollectorState collector; - - // lex. - platform::cachePreExistingFile(replName, line); - auto lexResult = frontend::lexTokensFromString(replName, line); - - // parse, but first setup the environment. - auto st = parser::State(lexResult.tokens); - auto _stmt = parser::parseStmt(st, /* exprs: */ true); - - *needmore = false; - if(_stmt.needsMoreTokens()) - { - *needmore = true; - return std::nullopt; - } - else if(_stmt.isError()) - { - _stmt.err()->post(); - - return std::nullopt; - } - else - { - auto stmt = _stmt.val(); - - // ugh. - auto tcr = TCResult(reinterpret_cast(0)); - - // there's no need to fiddle with AST-level trees -- once we typecheck it, - // it will store the relevant state into the TypecheckState. - - try - { - // note: usually, visitDeclarables in the top-level typecheck will set the realScope. - // BUT, since we're not doing that, we must set it manually! - if(auto def = dcast(ast::Parameterisable, stmt); def) - def->enclosingScope = state->fs->scope(); - - tcr = stmt->typecheck(state->fs); - } - catch(ErrorException& ee) - { - ee.err->post(); - printf("\n"); - - return std::nullopt; - } - - if(tcr.isError()) - { - tcr.error()->post(); - printf("\n"); - } - else if(!tcr.isParametric() && !tcr.isDummy()) - { - return tcr.stmt(); - } - - return std::nullopt; - } - } - - - bool processLine(const std::string& line) - { - // before we begin, bring us into a new namespace. - state->fs->pushAnonymousTree(); - - bool needmore = false; - auto stmt = repl::parseAndTypecheck(line, &needmore); - if(!stmt) - return needmore; - - - { - // copy some stuff over. - state->cs->typeDefnMap = state->fs->typeDefnMap; - - // so the thing is, all the previous things have already been code-generated, - // and have had their initialisers run. so there's really no need for their - // init pieces to stick around. we need to remove the functions as well for this - // to work properly! - for(auto [ gv, pc ] : state->cs->globalInitPieces) - { - state->module->removeFunction(pc); - delete pc; - } - - state->cs->globalInitPieces.clear(); - - // ok, we have a thing. try to run it. note: this will help us to run is->initialise(true), - // which will call the global inits. this function also calls Stmt::codegen, which will - // (potentially) populate the globalInitPieces, before calling cs->finishGlobalInits(). basically, - // it's all handled. - auto value = magicallyRunExpressionAtCompileTime(state->cs, *stmt, nullptr, - fir::Name::obfuscate("__anon_runner_", state->fnCounter++), - state->interpState); - - state->interpState->finalise(); - - if(value) - { - // if it was an expression, then give it a name so we can refer to it later. - auto init = util::pool(Location(), value->getType()); - init->rawValue = CGResult(value); - - auto vardef = util::pool(Location()); - vardef->type = init->type; - vardef->id = Identifier(zpr::sprint("_%d", state->varCounter++), IdKind::Name); - vardef->global = true; - vardef->init = init; - - state->fs->stree->addDefinition(vardef->id.name, vardef); - - zpr::println("%s: %s = %s", vardef->id.name, value->getType(), value->str()); - } - } - - - return false; - } -} - - - - - - - - - - - - - - - diff --git a/source/repl/history.cpp b/source/repl/history.cpp deleted file mode 100644 index f8329a0e..00000000 --- a/source/repl/history.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// history.cpp -// Copyright (c) 2019, zhiayang -// Licensed under the Apache License Version 2.0. - -#include -#include - -#include - -#include "repl.h" -#include "platform.h" - -namespace repl -{ - static std::string getConfigPath() - { - auto home = platform::getEnvironmentVar("HOME"); - - // do some checks so we don't try to write stuff into the root directory. - return (home + ((home.empty() || home.back() == '/') ? "" : "/")) + ".flax-repl-history"; - } - - - void saveHistory(const std::vector>& history) - { - auto path = getConfigPath(); - auto file = std::ofstream(path, std::ios::out | std::ios::binary | std::ios::trunc); - if(!file.is_open() || !file.good()) - { - repl::log("failed to open file to load history (tried '%s')", path); - - char buf[128] = { 0 }; - #if OS_WINDOWS - strerror_s(buf, 127, errno); - #else - strerror_r(errno, buf, 127); - #endif - repl::log("error was: '%s'", buf); - return; - } - - - // the format is that each "entry" is NULL-terminated, while each line in each entry is just - // newline-terminated. - - for(const auto& lines : history) - { - for(const auto& line : lines) - { - file.write(line.c_str(), line.size()); - file.put('\n'); - } - - // write the null-terminator - file.put('\0'); - } - - // ok. - file.close(); - } - - std::vector> loadHistory() - { - auto path = getConfigPath(); - auto file = std::ifstream(path, std::ios::in | std::ios::binary); - if(!file.is_open() || !file.good()) - return { }; - - std::vector> history; - - while(file.good()) - { - std::vector current; - for(std::string line; std::getline(file, line, '\n'); ) - { - current.push_back(line); - if(file.peek() == '\0') - { - file.get(); - break; - } - } - - if(!current.empty()) - history.push_back(current); - } - - - file.close(); - return history; - } -} - - - - - - - - - - - - diff --git a/source/typecheck/alloc.cpp b/source/typecheck/alloc.cpp index 8a26d621..ff3b3faa 100644 --- a/source/typecheck/alloc.cpp +++ b/source/typecheck/alloc.cpp @@ -17,87 +17,7 @@ TCResult ast::AllocOp::typecheck(sst::TypecheckState* fs, fir::Type* infer) fs->pushLoc(this); defer(fs->popLoc()); - fir::Type* elm = fs->convertParserTypeToFIR(this->allocTy); - iceAssert(elm); - - if(this->attrs.has(attr::RAW) && this->counts.size() > 1) - error(this, "only one length dimension is supported for raw memory allocation (have %d)", this->counts.size()); - - std::vector counts = zfu::map(this->counts, [fs](ast::Expr* e) -> auto { - auto c = e->typecheck(fs, fir::Type::getNativeWord()).expr(); - if(!c->type->isIntegerType()) - error(c, "expected integer type ('i64') for alloc count, found '%s' instead", c->type); - - return c; - }); - - // check for initialiser. - if(!elm->isClassType() && !elm->isStructType() && this->args.size() > 0) - error(this, "cannot provide arguments to non-struct type '%s'", elm); - - - fir::Type* resType = (this->attrs.has(attr::RAW) || counts.empty() ? - (this->isMutable ? elm->getMutablePointerTo() : elm->getPointerTo()) : fir::DynamicArrayType::get(elm)); - - auto ret = util::pool(this->loc, resType); - - - // ok, check if we're a struct. - if((elm->isStructType() || elm->isClassType())) - { - auto cdf = fs->typeDefnMap[elm]; - iceAssert(cdf); - - auto arguments = sst::resolver::misc::typecheckCallArguments(fs, this->args); - auto constructor = sst::resolver::resolveConstructorCall(fs, this->loc, cdf, arguments, PolyArgMapping_t::none()); - - ret->constructor = constructor.defn(); - ret->arguments = arguments; - } - else if(!this->args.empty()) - { - if(this->args.size() > 1) error(this, "expected 1 argument in alloc expression for non-struct type '%s' (for value-copy-initialisation), but found %d arguments instead", this->args.size()); - - auto args = sst::resolver::misc::typecheckCallArguments(fs, this->args); - if(args[0].value->type != elm) - error(this, "expected argument of type '%s' for value-copy-initialisation in alloc expression, but found '%s' instead", elm, args[0].value->type); - - // ok loh - ret->arguments = args; - } - - if(this->initBody) - { - iceAssert(!this->attrs.has(attr::RAW) && this->counts.size() > 0); - - // ok, make a fake vardefn and insert it first. - auto fake = util::pool(this->initBody->loc); - fake->type = this->allocTy; - fake->name = "it"; - - auto fake2 = util::pool(this->initBody->loc); - fake2->type = pts::NamedType::create(this->initBody->loc, INTUNSPEC_TYPE_STRING); - fake2->name = "i"; - - // make a temp scope to enclose it, I guess - fs->pushAnonymousTree(); - { - ret->initBlockVar = dcast(sst::VarDefn, fake->typecheck(fs).defn()); - ret->initBlockIdx = dcast(sst::VarDefn, fake2->typecheck(fs).defn()); - ret->initBlock = dcast(sst::Block, this->initBody->typecheck(fs).stmt()); - - iceAssert(ret->initBlockVar && ret->initBlockIdx && ret->initBlock); - } - fs->popTree(); - } - - - ret->elmType = elm; - ret->counts = counts; - ret->attrs = this->attrs; - ret->isMutable = this->isMutable; - - return TCResult(ret); + error("no"); } TCResult ast::DeallocOp::typecheck(sst::TypecheckState* fs, fir::Type* infer) @@ -105,17 +25,7 @@ TCResult ast::DeallocOp::typecheck(sst::TypecheckState* fs, fir::Type* infer) fs->pushLoc(this); defer(fs->popLoc()); - auto ex = this->expr->typecheck(fs).expr(); - if(ex->type->isDynamicArrayType()) - error(ex, "dynamic arrays are reference-counted, and cannot be manually freed"); - - else if(!ex->type->isPointerType()) - error(ex, "expected pointer or dynamic array type to deallocate; found '%s' instead", ex->type); - - auto ret = util::pool(this->loc); - ret->expr = ex; - - return TCResult(ret); + error("no"); } diff --git a/source/typecheck/arithmetic.cpp b/source/typecheck/arithmetic.cpp index 5ebe56ec..549d91d8 100644 --- a/source/typecheck/arithmetic.cpp +++ b/source/typecheck/arithmetic.cpp @@ -74,8 +74,7 @@ fir::Type* sst::TypecheckState::getBinaryOpResultType(fir::Type* left, fir::Type } else if(op == Operator::CompareEQ || op == Operator::CompareNEQ) { - if(left == right || fir::getCastDistance(left, right) >= 0 || fir::getCastDistance(right, left) >= 0 - || (left->isConstantNumberType() && right->isConstantNumberType())) + if(left == right || fir::getCastDistance(left, right) >= 0 || fir::getCastDistance(right, left) >= 0) { return fir::Type::getBool(); } @@ -83,11 +82,10 @@ fir::Type* sst::TypecheckState::getBinaryOpResultType(fir::Type* left, fir::Type else if(op == Operator::CompareLT || op == Operator::CompareGT || op == Operator::CompareLEQ || op == Operator::CompareGEQ) { // we handle this separately because we only want to check for number types and string types. - bool ty_compat = (left == right || fir::getCastDistance(left, right) >= 0 || fir::getCastDistance(right, left) >= 0 - || (left->isConstantNumberType() && right->isConstantNumberType())); + bool ty_compat = (left == right || fir::getCastDistance(left, right) >= 0 || fir::getCastDistance(right, left) >= 0); - bool ty_comparable = (left->isStringType() || left->isArraySliceType() || left->isArrayType() || left->isDynamicArrayType() - || left->isPrimitiveType() || left->isEnumType() || left->isConstantNumberType()); + bool ty_comparable = (left->isArraySliceType() || left->isArrayType() + || left->isPrimitiveType() || left->isEnumType()); if(ty_compat && ty_comparable) { @@ -107,77 +105,39 @@ fir::Type* sst::TypecheckState::getBinaryOpResultType(fir::Type* left, fir::Type } else if(op == Operator::Plus) { - if(left->isConstantNumberType() && right->isConstantNumberType()) - return fir::unifyConstantTypes(left->toConstantNumberType(), right->toConstantNumberType()); - - else if(left->isPrimitiveType() && right->isPrimitiveType() && left == right) - return left; - - else if(left->isStringType() && (right->isStringType() || right->isCharSliceType() || right->isCharType())) - return fir::Type::getString(); - - else if(left->isDynamicArrayType() && right->isDynamicArrayType() && left == right) + if(left->isPrimitiveType() && right->isPrimitiveType() && left == right) return left; - else if(left->isDynamicArrayType() && left->getArrayElementType() == right) + else if(left->isPointerType() && right->isIntegerType()) return left; - else if((left->isConstantNumberType() && right->isPrimitiveType()) || (left->isPrimitiveType() && right->isConstantNumberType())) - return (left->isConstantNumberType() ? right : left); - - else if(left->isPointerType() && (right->isIntegerType() || right->isConstantNumberType())) - return left; - - else if(right->isPointerType() && (left->isIntegerType() || left->isConstantNumberType())) + else if(right->isPointerType() && left->isIntegerType()) return right; } else if(op == Operator::Minus) { - if(left->isConstantNumberType() && right->isConstantNumberType()) - return fir::unifyConstantTypes(left->toConstantNumberType(), right->toConstantNumberType()); - - else if(left->isPrimitiveType() && right->isPrimitiveType() && left == right) + if(left->isPrimitiveType() && right->isPrimitiveType() && left == right) return left; - else if((left->isConstantNumberType() && right->isPrimitiveType()) || (left->isPrimitiveType() && right->isConstantNumberType())) - return (left->isConstantNumberType() ? right : left); - - else if(left->isPointerType() && (right->isIntegerType() || right->isConstantNumberType())) + else if(left->isPointerType() && right->isIntegerType()) return left; - else if(right->isPointerType() && (left->isIntegerType() || left->isConstantNumberType())) + else if(right->isPointerType() && left->isIntegerType()) return right; } else if(op == Operator::Multiply) { - if(left->isConstantNumberType() && right->isConstantNumberType()) - return fir::unifyConstantTypes(left->toConstantNumberType(), right->toConstantNumberType()); - - else if(left->isPrimitiveType() && right->isPrimitiveType() && left == right) + if(left->isPrimitiveType() && right->isPrimitiveType() && left == right) return left; - - else if((left->isConstantNumberType() && right->isPrimitiveType()) || (left->isPrimitiveType() && right->isConstantNumberType())) - return (left->isConstantNumberType() ? right : left); - } else if(op == Operator::Divide) { - if(left->isConstantNumberType() && right->isConstantNumberType()) - return fir::unifyConstantTypes(left->toConstantNumberType(), right->toConstantNumberType()); - - else if(left->isPrimitiveType() && right->isPrimitiveType() && left == right) + if(left->isPrimitiveType() && right->isPrimitiveType() && left == right) return left; - - else if((left->isConstantNumberType() && right->isPrimitiveType()) || (left->isPrimitiveType() && right->isConstantNumberType())) - return (left->isConstantNumberType() ? right : left); } else if(op == Operator::Modulo) { - if(left->isConstantNumberType() && right->isConstantNumberType()) - { - return fir::unifyConstantTypes(left->toConstantNumberType(), right->toConstantNumberType()); - } - else if((left->isIntegerType() && right->isIntegerType()) || (left->isFloatingPointType() && right->isFloatingPointType())) + if((left->isIntegerType() && right->isIntegerType()) || (left->isFloatingPointType() && right->isFloatingPointType())) { return (left->getBitWidth() > right->getBitWidth()) ? left : right; } @@ -185,10 +145,6 @@ fir::Type* sst::TypecheckState::getBinaryOpResultType(fir::Type* left, fir::Type { return (left->isFloatingPointType() ? left : right); } - else if((left->isConstantNumberType() && right->isPrimitiveType()) || (left->isPrimitiveType() && right->isConstantNumberType())) - { - return (left->isConstantNumberType() ? right : left); - } else { return left; @@ -337,12 +293,7 @@ TCResult ast::UnaryOp::typecheck(sst::TypecheckState* fs, fir::Type* inferred) } else if(this->op == Operator::UnaryPlus || this->op == Operator::UnaryMinus) { - if(t->isConstantNumberType()) - { - out = (op == "-" ? fir::ConstantNumberType::get(t->toConstantNumberType()->isSigned(), - t->toConstantNumberType()->isFloating(), t->toConstantNumberType()->getMinBits()) : t); - } - else if(!t->isIntegerType() && !t->isFloatingPointType()) + if(!t->isIntegerType() && !t->isFloatingPointType()) { error(this, "invalid use of unary plus/minus operator '+'/'-' on non-numerical type '%s'", t); } @@ -354,10 +305,7 @@ TCResult ast::UnaryOp::typecheck(sst::TypecheckState* fs, fir::Type* inferred) } else if(this->op == Operator::BitwiseNot) { - if(t->isConstantNumberType()) - error(this, "bitwise operations are not supported on literal numbers"); - - else if(!t->isIntegerType()) + if(!t->isIntegerType()) error(this, "invalid use of bitwise not operator '~' on non-integer type '%s'", t); else if(t->isSignedIntType()) diff --git a/source/typecheck/assign.cpp b/source/typecheck/assign.cpp index b1fef46d..74ee81a3 100644 --- a/source/typecheck/assign.cpp +++ b/source/typecheck/assign.cpp @@ -17,7 +17,8 @@ TCResult ast::AssignOp::typecheck(sst::TypecheckState* fs, fir::Type* infer) auto l = this->left->typecheck(fs).expr(); auto r = this->right->typecheck(fs, l->type).expr(); - if(r->type->isVoidType()) error(this->right, "value has void type"); + if(r->type->isVoidType()) + error(this->right, "value has void type"); // check if we can do it first auto lt = l->type; diff --git a/source/typecheck/call.cpp b/source/typecheck/call.cpp index bb9c39bb..63895443 100644 --- a/source/typecheck/call.cpp +++ b/source/typecheck/call.cpp @@ -61,24 +61,6 @@ sst::Expr* ast::FunctionCall::typecheckWithArguments(sst::TypecheckState* fs, co { iceAssert(target->type->isFunctionType()); - //* note: we check for this->name != "init" because when we explicitly call an init function, we don't want the extra stuff that - //* comes with that -- we'll just treat it as a normal function call. - if(auto fnd = dcast(sst::FunctionDefn, target); this->name != "init" && fnd && fnd->id.name == "init" && fnd->parentTypeForMethod && fnd->parentTypeForMethod->isClassType()) - { - // ok, great... I guess? - auto ret = util::pool(this->loc, fnd->parentTypeForMethod); - - ret->target = fnd; - ret->arguments = ts; - ret->classty = dcast(sst::ClassDefn, fs->typeDefnMap[fnd->parentTypeForMethod]); - - iceAssert(ret->target); - - return ret; - } - - - auto call = util::pool(this->loc, target->type->toFunctionType()->getReturnType()); call->name = this->name; call->target = target; diff --git a/source/typecheck/classes.cpp b/source/typecheck/classes.cpp deleted file mode 100644 index 05684c63..00000000 --- a/source/typecheck/classes.cpp +++ /dev/null @@ -1,584 +0,0 @@ -// classes.cpp -// Copyright (c) 2017, zhiayang -// Licensed under the Apache License Version 2.0. - -#include "ast.h" -#include "defs.h" -#include "pts.h" -#include "errors.h" - -#include "ir/type.h" -#include "resolver.h" - -#include "typecheck.h" - -#include "memorypool.h" - -// defined in typecheck/structs.cpp -void checkFieldRecursion(sst::TypecheckState* fs, fir::Type* strty, fir::Type* field, const Location& floc); - - - - -TCResult ast::ClassDefn::generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) -{ - fs->pushLoc(this); - defer(fs->popLoc()); - - - auto [ success, ret ] = this->checkForExistingDeclaration(fs, gmaps); - if(!success) return TCResult::getParametric(); - else if(ret) return TCResult(ret); - - auto defnname = util::typeParamMapToString(this->name, gmaps); - - auto defn = util::pool(this->loc); - defn->bareName = this->name; - defn->attrs = this->attrs; - - defn->id = Identifier(defnname, IdKind::Type); - defn->id.scope = this->enclosingScope; - defn->visibility = this->visibility; - defn->original = this; - defn->enclosingScope = this->enclosingScope; - defn->innerScope = this->enclosingScope.appending(defnname); - - - // make all our methods be methods - for(auto m : this->methods) - { - m->parentType = this; - m->enclosingScope = defn->innerScope; - } - - for(auto m : this->initialisers) - { - m->parentType = this; - m->enclosingScope = defn->innerScope; - } - - for(auto m : this->staticMethods) - { - m->enclosingScope = defn->innerScope; - } - - - auto cls = fir::ClassType::createWithoutBody(defn->id.convertToName()); - defn->type = cls; - - - // why do we do this when generating the declaration instead of only when we typecheck? - // as it currently stands, this means that our base class + any traits must appear before - // this class definition in the source code, which is kinda dumb. - for(auto base : zfu::map(this->bases, [fs](auto t) -> auto { return fs->convertParserTypeToFIR(t); })) - { - if(base->isClassType()) - { - if(defn->baseClass) - error(this, "cannot inherit from more than one class (already inherited from '%s')", defn->baseClass->id.name); - - else if(!defn->traits.empty()) - error(this, "base class must come before any traits in the inheritance list"); - - auto basedef = dcast(sst::ClassDefn, fs->typeDefnMap[base]); - iceAssert(basedef); - - defn->baseClass = basedef; - cls->setBaseClass(base->toClassType()); - } - else if(base->isTraitType()) - { - auto tdef = dcast(sst::TraitDefn, fs->typeDefnMap[base]); - iceAssert(tdef); - - defn->traits.push_back(tdef); - cls->addTraitImpl(tdef->type->toTraitType()); - } - else - { - error(this, "invalid type '%s' in inheritance list of class", base); - } - } - - if(auto err = fs->checkForShadowingOrConflictingDefinition(defn, [](auto, auto) -> bool { return true; })) - return TCResult(err); - - // add it first so we can use it in the method bodies, - // and make pointers to it - { - defn->enclosingScope.stree->addDefinition(defnname, defn, gmaps); - fs->typeDefnMap[cls] = defn; - } - - fs->teleportInto(defn->innerScope); - { - for(auto t : this->nestedTypes) - { - t->enclosingScope = defn->innerScope; - t->generateDeclaration(fs, 0, { }); - } - } - fs->teleportOut(); - - this->genericVersions.push_back({ defn, fs->getGenericContextStack() }); - return TCResult(defn); -} - -TCResult ast::ClassDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) -{ - fs->pushLoc(this); - defer(fs->popLoc()); - - auto tcr = this->generateDeclaration(fs, infer, gmaps); - if(tcr.isParametric()) return tcr; - else if(!tcr.isDefn()) error(this, "failed to generate declaration for function '%s'", this->name); - - auto defn = dcast(sst::ClassDefn, tcr.defn()); - iceAssert(defn); - - if(this->finishedTypechecking.find(defn) != this->finishedTypechecking.end()) - return TCResult(defn); - - auto cls = defn->type->toClassType(); - iceAssert(cls); - - fs->teleportInto(defn->innerScope); - - if(this->initialisers.empty()) - error(this, "class must have at least one initialiser"); - - - - - for(auto t : this->nestedTypes) - { - auto tcr = t->typecheck(fs); - if(tcr.isParametric()) continue; - if(tcr.isError()) error(t, "failed to generate declaration for nested type '%s' in struct '%s'", t->name, this->name); - - auto st = dcast(sst::TypeDefn, tcr.defn()); - iceAssert(st); - - defn->nestedTypes.push_back(st); - } - - - - fs->pushSelfContext(cls); - { - std::vector> tys; - for(auto f : this->fields) - { - auto v = dcast(sst::StructFieldDefn, f->typecheck(fs).defn()); - iceAssert(v); - - defn->fields.push_back(v); - tys.push_back({ v->id.name, v->type }); - - checkFieldRecursion(fs, cls, v->type, v->loc); - - std::function checkDupe = [](sst::ClassDefn* cls, sst::StructFieldDefn* fld) -> auto { - while(cls) - { - for(auto bf : cls->fields) - { - if(bf->id.name == fld->id.name) - { - SimpleError::make(fld->loc, "redefinition of field '%s' (with type '%s'), that exists in the base class '%s'", - fld->id.name, fld->type, cls->id) - ->append(SimpleError::make(MsgType::Note, bf->loc, "'%s' was previously defined in the base class here:", fld->id.name)) - ->append(SimpleError::make(MsgType::Note, cls->loc, "base class '%s' was defined here:", cls->id)) - ->postAndQuit(); - } - } - - cls = cls->baseClass; - } - }; - - checkDupe(defn->baseClass, v); - } - cls->setMembers(tys); - - - { - //* check for what would be called 'method hiding' in c++, and also valid overrides. - // TODO: make an error note about co/contra-variance for param/return types. right now it just complains and it's vague af. - auto checkAgainstBaseClasses = [](sst::ClassDefn* cls, sst::FunctionDefn* meth) -> auto { - - auto checkSingleMethod = [](sst::ClassDefn* cls, sst::FunctionDefn* self, sst::FunctionDefn* bf, bool* matchedName) -> bool { - - if(bf->id.name == self->id.name) - { - *matchedName |= true; - - if(!fir::areMethodsVirtuallyCompatible(bf->type->toFunctionType(), self->type->toFunctionType(), - /* trait checking: */ false)) - { - return false; - } - - // check for virtual functions. - //* note: we don't need to care if 'bf' is the base method, because if we are 'isOverride', then we are also - //* 'isVirtual'. - - // nice comprehensive error messages, I hope. - if(!self->isOverride) - { - auto err = SimpleError::make(self->loc, "redefinition of method '%s' (with type '%s'), that exists in" - " the base class '%s'", self->id.name, self->type, cls->id); - - if(bf->isVirtual) - { - err->append(SimpleError::make(MsgType::Note, bf->loc, "'%s' was defined as a virtual method; to override it, use the 'override' keyword", bf->id.name)); - } - else - { - err->append( - SimpleError::make(MsgType::Note, bf->loc, "'%s' was previously defined in the base class '%s'" - " as a non-virtual method here:", bf->id.name, cls->id.name - )->append(BareError::make(MsgType::Note, "to override it, define '%s' as a virtual method", - bf->id.name) - ) - ); - } - - err->postAndQuit(); - } - else if(!bf->isVirtual) - { - SimpleError::make(self->loc, "cannot override non-virtual method '%s'", bf->id.name) - ->append(SimpleError::make(MsgType::Note, bf->loc, - "'%s' was previously defined in the base class '%s' as a non-virtual method here:", bf->id.name, cls->id.name) - )->append(BareError::make(MsgType::Note, "to override it, define '%s' as a virtual method", bf->id.name)) - ->postAndQuit(); - } - - return true; - } - - return false; - }; - - bool matchedSig = false; - bool matchedName = false; - while(cls) - { - for(auto bf : cls->methods) - matchedSig |= checkSingleMethod(cls, meth, bf, &matchedName); - - cls = cls->baseClass; - } - - if(meth->isOverride && !matchedSig) - { - if(matchedName && !matchedSig) - { - error(meth, "invalid override: no method named '%s' in any base class with a signature matching" - " (or compatible with) '%s'", meth->id.name, meth->type->str()); - } - else if(!matchedName) - { - error(meth, "invalid override: no method in any base class named '%s'", meth->id.name); - } - } - }; - - for(auto m : this->methods) - { - if(m->name == "init") - error(m, "cannot have methods named 'init' in a class; to create an initialiser, omit the 'fn' keyword."); - - auto res = m->generateDeclaration(fs, cls, { }); - if(res.isParametric()) - continue; - - auto decl = dcast(sst::FunctionDefn, res.defn()); - iceAssert(decl); - - defn->methods.push_back(decl); - - checkAgainstBaseClasses(defn->baseClass, decl); - } - } - - - { - // make the constructors - for(auto it : this->initialisers) - { - auto decl = dcast(sst::FunctionDefn, it->generateDeclaration(fs, cls, { }).defn()); - iceAssert(decl); - - defn->methods.push_back(decl); - defn->initialisers.push_back(decl); - } - - // and the destructor - if(this->deinitialiser) - { - auto decl = dcast(sst::FunctionDefn, this->deinitialiser->generateDeclaration(fs, cls, { }).defn()); - iceAssert(decl); - - defn->methods.push_back(decl); - defn->deinitialiser = decl; - } - if(this->copyInitialiser) - { - auto decl = dcast(sst::FunctionDefn, this->copyInitialiser->generateDeclaration(fs, cls, { }).defn()); - iceAssert(decl); - - defn->methods.push_back(decl); - defn->copyInitialiser = decl; - } - if(this->moveInitialiser) - { - auto decl = dcast(sst::FunctionDefn, this->moveInitialiser->generateDeclaration(fs, cls, { }).defn()); - iceAssert(decl); - - defn->methods.push_back(decl); - defn->moveInitialiser = decl; - } - } - - - - // copy all the things from the superclass into ourselves. - if(defn->baseClass) - { - // basically, the only things we want to import from the base class are fields and methods -- not initialisers. - // base-class-constructors must be called using `super(...)` syntax. - - auto tree = defn->baseClass->innerScope.stree; - iceAssert(tree); - - std::function recursivelyImport = [&](sst::StateTree* from, sst::StateTree* to) -> void { - - for(auto def : from->getAllDefinitions()) - { - if(!dcast(sst::ClassInitialiserDefn, def)) - to->addDefinition(def->id.name, def); - } - - for(auto sub : from->subtrees) - { - if(to->subtrees.find(sub.first) == to->subtrees.end()) - to->findOrCreateSubtree(sub.first); - - recursivelyImport(sub.second, to->subtrees[sub.first]); - } - }; - - recursivelyImport(tree, fs->stree); - } - - for(auto f : this->staticFields) - { - auto v = dcast(sst::VarDefn, f->typecheck(fs).defn()); - iceAssert(v); - - defn->staticFields.push_back(v); - } - - for(auto m : this->staticMethods) - { - // infer is 0 because this is a static thing - auto res = m->generateDeclaration(fs, 0, { }); - if(res.isParametric()) - continue; - - auto decl = dcast(sst::FunctionDefn, res.defn()); - iceAssert(decl); - - defn->staticMethods.push_back(decl); - } - - - - - // once we get all the proper declarations and such, create the function bodies. - if(!cls->containsPlaceholders()) - { - for(auto m : this->methods) - m->typecheck(fs, cls, { }); - - for(auto m : this->initialisers) - m->typecheck(fs, cls, { }); - - for(auto m : this->staticMethods) - m->typecheck(fs, 0, { }); - - if(this->deinitialiser) this->deinitialiser->typecheck(fs, cls, { }); - if(this->copyInitialiser) this->copyInitialiser->typecheck(fs, cls, { }); - if(this->moveInitialiser) this->moveInitialiser->typecheck(fs, cls, { }); - } - } - fs->popSelfContext(); - - - fs->teleportOut(); - - this->finishedTypechecking.insert(defn); - return TCResult(defn); -} - - - - - - - - - - - - -TCResult ast::InitFunctionDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) -{ - iceAssert(infer && infer->isClassType()); - auto cls = infer->toClassType(); - - auto ret = dcast(sst::FunctionDefn, this->actualDefn->typecheck(fs, cls, gmaps).defn()); - - // if the initialiser was polymorphic, then don't generate bodies! - if(ret->type->containsPlaceholders()) - return TCResult::getParametric(); - - // only check this stuff for the real constructor. - if(this->name == "init") - { - if(cls->getBaseClass() && !this->didCallSuper) - { - error(this, "initialiser for class '%s' must explicitly call an initialiser of the base class '%s'", cls->getTypeName().name, - cls->getBaseClass()->getTypeName().name); - } - else if(!cls->getBaseClass() && this->didCallSuper) - { - error(this, "cannot call base class initialiser for class '%s' when it does not inherit from a base class", - cls->getTypeName().name); - } - else if(cls->getBaseClass() && this->didCallSuper) - { - auto base = cls->getBaseClass(); - auto call = util::pool(this->loc, base); - - call->classty = dcast(sst::ClassDefn, fs->typeDefnMap[base]); - iceAssert(call->classty); - - std::vector baseargs; - { - auto restore = fs->stree; - fs->stree = ret->insideTree; - - baseargs = sst::resolver::misc::typecheckCallArguments(fs, this->superArgs); - - fs->stree = restore; - } - - auto constr = sst::resolver::resolveConstructorCall(fs, this->loc, call->classty, baseargs, PolyArgMapping_t::none()); - - call->arguments = baseargs; - call->target = dcast(sst::FunctionDefn, constr.defn()); - iceAssert(call->target); - - // insert it as the first thing. - ret->body->statements.insert(ret->body->statements.begin(), call); - } - } - - return TCResult(ret); -} - - -TCResult ast::InitFunctionDefn::generateDeclaration(sst::TypecheckState* fs, fir::Type* infer, const TypeParamMap_t& gmaps) -{ - //* so here's the thing - //* basically this init function thingy is just a normal function definition - //* but due to the way the AST was built, and because it's actually slightly less messy IMO, - //* we return a separate AST type that does not inherit from FuncDefn. - - //* so, to reduce code dupe and make it less stupid, we actually make a fake FuncDefn from ourselves, - //* and typecheck that, returning that as the result. - - //* we don't want to be carrying too many distinct types around in SST nodes. - - iceAssert(infer); - - this->actualDefn = util::pool(this->loc); - - this->actualDefn->name = this->name; - this->actualDefn->body = this->body; - this->actualDefn->params = this->params; - this->actualDefn->parentType = this->parentType; - this->actualDefn->returnType = pts::NamedType::create(this->loc, VOID_TYPE_STRING); - - this->actualDefn->enclosingScope = this->enclosingScope; - - //* note: constructors will always mutate, definitely. - this->actualDefn->isMutating = true; - - auto ret = this->actualDefn->generateDeclaration(fs, infer, gmaps); - if(ret.isDefn()) - { - auto def = dcast(sst::FunctionDefn, ret.defn()); - iceAssert(def); - - // do some checks. - if(this->name == "copy") - { - if(def->params.size() != 2) - { - error(def, "copy initialiser must take exactly one argument, %d were found", def->params.size() - 1); - } - else if(auto ty = def->params[1].type; !ty->isImmutablePointer() || ty->getPointerElementType() != def->parentTypeForMethod) - { - error(def->params[1].loc, "parameter of copy initialiser must have type '&self' (aka '%s'), found '%s' instead", - def->parentTypeForMethod->getPointerTo(), ty); - } - } - else if(this->name == "move") - { - if(def->params.size() != 2) - { - error(def, "move initialiser must take exactly one argument, %d were found", def->params.size() - 1); - } - else if(auto ty = def->params[1].type; !ty->isMutablePointer() || ty->getPointerElementType() != def->parentTypeForMethod) - { - error(def->params[1].loc, "parameter of move initialiser must have type '&mut self' (aka '%s'), found '%s' instead", - def->parentTypeForMethod->getMutablePointerTo(), ty); - } - } - } - - return ret; -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/source/typecheck/destructure.cpp b/source/typecheck/destructure.cpp index efd9da79..600aaf52 100644 --- a/source/typecheck/destructure.cpp +++ b/source/typecheck/destructure.cpp @@ -32,53 +32,28 @@ static void checkArray(sst::TypecheckState* fs, DecompMapping* bind, fir::Type* { iceAssert(bind->array); - if(!rhs->isArrayType() && !rhs->isDynamicArrayType() && !rhs->isArraySliceType() && !rhs->isStringType()) + if(!rhs->isArrayType() && !rhs->isArraySliceType()) error(bind->loc, "expected array type in destructuring declaration; found type '%s' instead", rhs); - if(rhs->isStringType()) - { - //* note: special-case this, because 1. we want to return chars, but 2. strings are supposed to be immutable. - for(auto& b : bind->inner) - checkAndAddBinding(fs, &b, fir::Type::getInt8(), immut, false); + for(auto& b : bind->inner) + checkAndAddBinding(fs, &b, rhs->getArrayElementType(), immut, true); - if(!bind->restName.empty()) - { - auto fake = util::pool(bind->loc); - - fake->id = Identifier(bind->restName, IdKind::Name); - fake->immutable = immut; - - //* note: see typecheck/slices.cpp for mutability rules. - if(bind->restRef) fake->type = fir::Type::getCharSlice(sst::getMutabilityOfSliceOfType(rhs)); - else fake->type = fir::Type::getString(); - - fs->stree->addDefinition(bind->restName, fake); - - bind->restDefn = fake; - } - } - else + if(!bind->restName.empty()) { - for(auto& b : bind->inner) - checkAndAddBinding(fs, &b, rhs->getArrayElementType(), immut, true); - - if(!bind->restName.empty()) - { - auto fake = util::pool(bind->loc); + auto fake = util::pool(bind->loc); - fake->id = Identifier(bind->restName, IdKind::Name); - fake->immutable = immut; + fake->id = Identifier(bind->restName, IdKind::Name); + fake->immutable = immut; - //* note: see typecheck/slices.cpp for mutability rules. - if(bind->restRef || rhs->isArraySliceType()) - fake->type = fir::ArraySliceType::get(rhs->getArrayElementType(), sst::getMutabilityOfSliceOfType(rhs)); + //* note: see typecheck/slices.cpp for mutability rules. + if(bind->restRef || rhs->isArraySliceType()) + fake->type = fir::ArraySliceType::get(rhs->getArrayElementType(), sst::getMutabilityOfSliceOfType(rhs)); - else - fake->type = fir::DynamicArrayType::get(rhs->getArrayElementType()); + else + iceAssert(false); - fs->stree->addDefinition(bind->restName, fake); - bind->restDefn = fake; - } + fs->stree->addDefinition(bind->restName, fake); + bind->restDefn = fake; } } diff --git a/source/typecheck/dotop.cpp b/source/typecheck/dotop.cpp index 60e9a782..61c28ff0 100644 --- a/source/typecheck/dotop.cpp +++ b/source/typecheck/dotop.cpp @@ -39,23 +39,6 @@ static ErrorMsg* wrongDotOpError(ErrorMsg* e, sst::StructDefn* str, const Locati } else { - if(auto cls = dcast(sst::ClassDefn, str)) - { - // check static ones for a better error message. - sst::Defn* found = 0; - for(auto sm : cls->staticMethods) - if(sm->id.name == name) { found = sm; break; } - - if(!found) - { - for(auto sf : cls->staticFields) - if(sf->id.name == name) { found = sf; break; } - } - - - if(found) e->append(SimpleError::make(MsgType::Note, found->loc, "use '::' to refer to the static member '%s'", name)); - } - return e; } }; @@ -228,7 +211,7 @@ static sst::Expr* doExpressionDotOp(sst::TypecheckState* fs, ast::DotOperator* d return ret; } - else if(type->isPointerType() && (type->getPointerElementType()->isStructType() || type->getPointerElementType()->isClassType())) + else if(type->isPointerType() && type->getPointerElementType()->isStructType()) { type = type->getPointerElementType(); @@ -237,97 +220,23 @@ static sst::Expr* doExpressionDotOp(sst::TypecheckState* fs, ast::DotOperator* d // TODO: reevaluate this decision? } - else if(type->isStringType()) + else if(type->isArraySliceType() || type->isArrayType()) { auto rhs = dotop->right; if(auto vr = dcast(ast::Ident, rhs)) { - // TODO: Extension support here fir::Type* res = 0; - if(zfu::match(vr->name, names::saa::FIELD_LENGTH, names::saa::FIELD_CAPACITY, - names::saa::FIELD_REFCOUNT, names::string::FIELD_COUNT)) + if(vr->name == names::array::FIELD_LENGTH) { res = fir::Type::getNativeWord(); } - else if(vr->name == names::saa::FIELD_POINTER) - { - res = fir::Type::getInt8Ptr(); - } - - - if(res) - { - auto tmp = util::pool(dotop->right->loc, res); - tmp->lhs = lhs; - tmp->name = vr->name; - - return tmp; - } - // else: break out below, for extensions - } - else if(auto fc = dcast(ast::FunctionCall, rhs)) - { - fir::Type* res = 0; - std::vector args; - if(fc->name == names::saa::FN_CLONE) - { - res = type; - if(fc->args.size() != 0) - error(fc, "builtin string method 'clone' expects exactly 0 arguments, found %d instead", fc->args.size()); - } - else if(fc->name == names::saa::FN_APPEND) - { - res = fir::Type::getVoid(); - if(fc->args.size() != 1) - error(fc, "builtin string method 'append' expects exactly 1 argument, found %d instead", fc->args.size()); - - else if(!fc->args[0].first.empty()) - error(fc, "argument to builtin method 'append' cannot be named"); - - args.push_back(fc->args[0].second->typecheck(fs).expr()); - if(!args[0]->type->isCharType() && !args[0]->type->isStringType() && !args[0]->type->isCharSliceType()) - { - error(fc, "invalid argument type '%s' to builtin string method 'append'; expected one of '%s', '%s', or '%s'", - args[0]->type, fir::Type::getInt8(), fir::Type::getCharSlice(false), fir::Type::getString()); - } - } - - - if(res) - { - auto tmp = util::pool(dotop->right->loc, res); - tmp->lhs = lhs; - tmp->args = args; - tmp->name = fc->name; - tmp->isFunctionCall = true; - - return tmp; - } - } - } - else if(type->isDynamicArrayType() || type->isArraySliceType() || type->isArrayType()) - { - auto rhs = dotop->right; - if(auto vr = dcast(ast::Ident, rhs)) - { - fir::Type* res = 0; - if(vr->name == names::saa::FIELD_LENGTH || (type->isDynamicArrayType() - && zfu::match(vr->name, names::saa::FIELD_CAPACITY, names::saa::FIELD_REFCOUNT))) - { - res = fir::Type::getNativeWord(); - } - else if(vr->name == names::saa::FIELD_POINTER) + else if(vr->name == names::array::FIELD_POINTER) { res = type->getArrayElementType()->getPointerTo(); - if(type->isDynamicArrayType()) - res = res->getMutablePointerVersion(); - - else if(type->isArraySliceType() && type->toArraySliceType()->isMutable()) + if(type->isArraySliceType() && type->toArraySliceType()->isMutable()) res = res->getMutablePointerVersion(); } - - if(res) { auto tmp = util::pool(dotop->right->loc, res); @@ -336,65 +245,8 @@ static sst::Expr* doExpressionDotOp(sst::TypecheckState* fs, ast::DotOperator* d return tmp; } - // else: break out below, for extensions - } - else if(auto fc = dcast(ast::FunctionCall, rhs)) - { - fir::Type* res = 0; - std::vector args; - - if(fc->name == names::saa::FN_CLONE) - { - res = type; - if(fc->args.size() != 0) - error(fc, "builtin array method 'clone' expects exactly 0 arguments, found %d instead", fc->args.size()); - } - else if(fc->name == names::saa::FN_APPEND) - { - if(type->isArrayType()) - error(fc, "'append' method cannot be called on arrays"); - - res = fir::DynamicArrayType::get(type->getArrayElementType()); - - if(fc->args.size() != 1) - error(fc, "builtin array method 'append' expects exactly 1 argument, found %d instead", fc->args.size()); - else if(!fc->args[0].first.empty()) - error(fc, "argument to builtin method 'append' cannot be named"); - - args.push_back(fc->args[0].second->typecheck(fs).expr()); - if(args[0]->type != type->getArrayElementType() //? vv logic below looks a little sketch. - && ((args[0]->type->isArraySliceType() && args[0]->type->getArrayElementType() != type->getArrayElementType())) - && args[0]->type != type) - { - error(fc, "invalid argument type '%s' to builtin array method 'append'; expected one of '%s', '%s', or '%s'", - args[0]->type, type, type->getArrayElementType(), - fir::ArraySliceType::get(type->getArrayElementType(), false)); - } - } - else if(fc->name == names::array::FN_POP) - { - if(!type->isDynamicArrayType()) - error(fc, "'pop' method can only be called on dynamic arrays"); - - res = type->getArrayElementType(); - - if(fc->args.size() != 0) - error(fc, "builtin array method 'pop' expects no arguments, found %d instead", fc->args.size()); - } - - // fallthrough - - if(res) - { - auto tmp = util::pool(dotop->right->loc, res); - tmp->lhs = lhs; - tmp->args = args; - tmp->name = fc->name; - tmp->isFunctionCall = true; - - return tmp; - } + // else: break out below, for extensions } } else if(type->isEnumType()) @@ -448,31 +300,6 @@ static sst::Expr* doExpressionDotOp(sst::TypecheckState* fs, ast::DotOperator* d // else: fallthrough; } - else if(type->isAnyType()) - { - auto rhs = dotop->right; - if(auto vr = dcast(ast::Ident, rhs)) - { - // TODO: extension support here - fir::Type* res = 0; - if(vr->name == names::any::FIELD_TYPEID) - res = fir::Type::getNativeUWord(); - - else if(vr->name == names::any::FIELD_REFCOUNT) - res = fir::Type::getNativeWord(); - - if(res) - { - auto tmp = util::pool(dotop->right->loc, res); - tmp->lhs = lhs; - tmp->name = vr->name; - - return tmp; - } - } - - // else: fallthrough - } @@ -519,16 +346,6 @@ static sst::Expr* doExpressionDotOp(sst::TypecheckState* fs, ast::DotOperator* d break; } - if(auto cls = dcast(sst::ClassDefn, curstr); cls && cls->baseClass) - { - // teleport out, then back in. - fs->teleportOut(); - fs->teleportInto(cls->baseClass->innerScope); - - curstr = cls->baseClass; - continue; - } - // sighs err = res.error(); break; @@ -593,11 +410,7 @@ static sst::Expr* doExpressionDotOp(sst::TypecheckState* fs, ast::DotOperator* d if(hmm) return hmm; // ok, we didn't find it. - if(auto cls = dcast(sst::ClassDefn, copy); cls) - copy = cls->baseClass; - - else - copy = nullptr; + copy = nullptr; } } @@ -793,7 +606,7 @@ static sst::Expr* doStaticDotOp(sst::TypecheckState* fs, ast::DotOperator* dot, if(auto typdef = dcast(sst::TypeDefn, def)) { - if(dcast(sst::ClassDefn, def) || dcast(sst::StructDefn, def)) + if(dcast(sst::StructDefn, def)) { fs->pushSelfContext(def->type); diff --git a/source/typecheck/enums.cpp b/source/typecheck/enums.cpp index 5cf7bd86..4ea4c06e 100644 --- a/source/typecheck/enums.cpp +++ b/source/typecheck/enums.cpp @@ -73,8 +73,8 @@ TCResult ast::EnumDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer, con fs->teleportInto(defn->innerScope); - if(this->memberType) defn->memberType = fs->convertParserTypeToFIR(this->memberType); - else defn->memberType = fir::Type::getNativeWord(); + if(this->memberType) defn->memberType = fs->convertParserTypeToFIR(this->memberType); + else defn->memberType = fir::Type::getNativeWord(); auto ety = defn->type->toEnumType(); iceAssert(ety); diff --git a/source/typecheck/function.cpp b/source/typecheck/function.cpp index 4af380d8..bc0a5973 100644 --- a/source/typecheck/function.cpp +++ b/source/typecheck/function.cpp @@ -45,15 +45,14 @@ TCResult ast::FuncDefn::generateDeclaration(sst::TypecheckState* fs, fir::Type* fir::Type* retty = sst::poly::internal::convertPtsType(fs, this->generics, this->returnType, polyses); fir::Type* fnType = fir::FunctionType::get(ptys, retty); - auto defn = (infer && infer->isClassType() && this->name == "init" ? util::pool(this->loc) - : util::pool(this->loc)); + auto defn = util::pool(this->loc); defn->type = fnType; if(this->name != "init") defn->original = this; - iceAssert(!infer || (infer->isStructType() || infer->isClassType())); + iceAssert(!infer || infer->isStructType()); defn->parentTypeForMethod = infer; @@ -71,23 +70,14 @@ TCResult ast::FuncDefn::generateDeclaration(sst::TypecheckState* fs, fir::Type* defn->global = !fs->isInFunctionBody(); - defn->isVirtual = this->isVirtual; defn->isOverride = this->isOverride; defn->isMutating = this->isMutating; - if(defn->isVirtual && !defn->parentTypeForMethod) - { - error(defn, "only methods can be marked 'virtual' or 'override' at this point in time"); - } - else if(defn->isVirtual && defn->parentTypeForMethod && !defn->parentTypeForMethod->isClassType()) - { - error(defn, "only methods of a class (which '%s' is not) can be marked 'virtual' or 'override'", - defn->parentTypeForMethod->str()); - } - else if(defn->isMutating && !defn->parentTypeForMethod) - { + if(defn->isOverride && !defn->parentTypeForMethod) + error(defn, "only methods of a type can be marked as mutating with 'override'"); + + if(defn->isMutating && !defn->parentTypeForMethod) error(defn, "only methods of a type can be marked as mutating with 'mut'"); - } auto conflict_err = fs->checkForShadowingOrConflictingDefinition(defn, [defn](sst::TypecheckState* fs, sst::Stmt* other) -> bool { diff --git a/source/typecheck/literals.cpp b/source/typecheck/literals.cpp index 220574d2..6adc90aa 100644 --- a/source/typecheck/literals.cpp +++ b/source/typecheck/literals.cpp @@ -15,48 +15,19 @@ TCResult ast::LitNumber::typecheck(sst::TypecheckState* fs, fir::Type* infer) fs->pushLoc(this); defer(fs->popLoc()); - // i don't think mpfr auto-detects base, LMAO int base = 10; if(this->num.find("0x") == 0 || this->num.find("0X") == 0) base = 16; - auto number = mpfr::mpreal(this->num, mpfr_get_default_prec(), base); - bool sgn = mpfr::signbit(number); - bool flt = ((this->num.find(".") != std::string::npos) || !mpfr::isint(number)); + else if(this->num.find("0b") == 0 || this->num.find("0B") == 0) + base = 2; - size_t bits = 0; - if(flt) - { - // fuck it lah. - bits = sizeof(double) * CHAR_BIT; - } - else - { - auto m_ptr = number.mpfr_ptr(); - auto m_rnd = MPFR_RNDN; - if(mpfr_fits_sshort_p(m_ptr, m_rnd)) - bits = sizeof(short) * CHAR_BIT; - - else if(mpfr_fits_sint_p(m_ptr, m_rnd)) - bits = sizeof(int) * CHAR_BIT; - - else if(mpfr_fits_slong_p(m_ptr, m_rnd)) - bits = sizeof(long) * CHAR_BIT; - - else if(mpfr_fits_intmax_p(m_ptr, m_rnd)) - bits = sizeof(intmax_t) * CHAR_BIT; + // TODO: really broken + auto ret = util::pool(this->loc, (infer && infer->isPrimitiveType()) + ? infer : fir::Type::getNativeWord()); - else if(!sgn && mpfr_fits_uintmax_p(m_ptr, m_rnd)) - bits = sizeof(uintmax_t) * CHAR_BIT; - - else // lmao - bits = sizeof(uintmax_t) * CHAR_BIT; - } - - auto ret = util::pool(this->loc, (infer && infer->isPrimitiveType()) ? infer - : fir::ConstantNumberType::get(sgn, flt, bits)); - - ret->num = number; + if(this->is_floating) ret->floating = std::stod(this->num); + else ret->integer = std::stoull(this->num, nullptr, base); return TCResult(ret); } @@ -119,12 +90,8 @@ TCResult ast::LitTuple::typecheck(sst::TypecheckState* fs, fir::Type* infer) auto inf = (infer ? infer->toTupleType()->getElementN(k) : 0); auto expr = v->typecheck(fs, inf).expr(); - auto ty = expr->type; - if(expr->type->isConstantNumberType() && (!inf || !inf->isPrimitiveType())) - ty = sst::inferCorrectTypeForLiteral(expr->type->toConstantNumberType()); - vals.push_back(expr); - fts.push_back(ty); + fts.push_back(expr->type); k++; } @@ -169,29 +136,16 @@ TCResult ast::LitArray::typecheck(sst::TypecheckState* fs, fir::Type* infer) fir::Type* type = 0; if(this->values.empty()) { - if(this->explicitType) - { - auto explty = fs->convertParserTypeToFIR(this->explicitType); - iceAssert(explty); + iceAssert(infer != nullptr); - type = fir::DynamicArrayType::get(explty); + if(infer->isArrayType()) + { + if(infer->toArrayType()->getArraySize() != 0) + error(this, "array type with non-zero length %d was inferred for empty array literal", infer->toArrayType()->getArraySize()); } - else + else if(!infer->isArraySliceType()) { - if(infer == 0) - { - // facilitate passing empty array literals around (that can be cast to a bunch of things like slices and such) - infer = fir::DynamicArrayType::get(fir::VoidType::get()); - } - else if(infer->isArrayType()) - { - if(infer->toArrayType()->getArraySize() != 0) - error(this, "array type with non-zero length %d was inferred for empty array literal", infer->toArrayType()->getArraySize()); - } - else if(!(infer->isDynamicArrayType() || infer->isArraySliceType())) - { - error(this, "invalid type '%s' inferred for array literal", infer); - } + error(this, "invalid type '%s' inferred for array literal", infer); } type = infer; @@ -202,7 +156,7 @@ TCResult ast::LitArray::typecheck(sst::TypecheckState* fs, fir::Type* infer) if(!elmty && infer) { - if(!infer->isDynamicArrayType() && !infer->isArraySliceType() && !infer->isArrayType()) + if(!infer->isArraySliceType() && !infer->isArrayType()) error(this, "invalid type '%s' inferred for array literal", infer); elmty = infer->getArrayElementType(); @@ -214,11 +168,7 @@ TCResult ast::LitArray::typecheck(sst::TypecheckState* fs, fir::Type* infer) if(!elmty) { - if(e->type->isConstantNumberType() && !infer) - elmty = sst::inferCorrectTypeForLiteral(e->type->toConstantNumberType()); - - else - elmty = e->type; + elmty = e->type; } else if(elmty != e->type) { @@ -252,11 +202,6 @@ TCResult ast::LitArray::typecheck(sst::TypecheckState* fs, fir::Type* infer) // slices from a constant array generally should remain immutable. type = fir::ArraySliceType::get(elmty, false); } - else if(infer->isDynamicArrayType()) - { - // do something - type = fir::DynamicArrayType::get(elmty); - } else { error(this, "invalid type '%s' inferred for array literal", infer); diff --git a/source/typecheck/loops.cpp b/source/typecheck/loops.cpp index 00f02569..02a5c2f1 100644 --- a/source/typecheck/loops.cpp +++ b/source/typecheck/loops.cpp @@ -25,20 +25,17 @@ TCResult ast::ForeachLoop::typecheck(sst::TypecheckState* fs, fir::Type* inferre ret->array = this->array->typecheck(fs).expr(); fir::Type* elmty = 0; - if(ret->array->type->isArrayType() || ret->array->type->isDynamicArrayType() || ret->array->type->isArraySliceType()) + if(ret->array->type->isArrayType() || ret->array->type->isArraySliceType()) elmty = ret->array->type->getArrayElementType(); else if(ret->array->type->isRangeType()) elmty = fir::Type::getNativeWord(); - else if(ret->array->type->isStringType()) - elmty = fir::Type::getInt8(); - else error(this->array, "invalid type '%s' in foreach loop", ret->array->type); iceAssert(elmty); - bool allowref = !(ret->array->type->isStringType() || ret->array->type->isRangeType()); + bool allowref = !ret->array->type->isRangeType(); if(!this->indexVar.empty()) { diff --git a/source/typecheck/misc.cpp b/source/typecheck/misc.cpp deleted file mode 100644 index 8f03e081..00000000 --- a/source/typecheck/misc.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// misc.cpp -// Copyright (c) 2019, zhiayang -// Licensed under the Apache License Version 2.0. - -#include "pts.h" -#include "ast.h" -#include "errors.h" -#include "typecheck.h" -#include "ir/type.h" - -#include "memorypool.h" - - -TCResult ast::PlatformDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer) -{ - fs->pushLoc(this); - defer(fs->popLoc()); - - if(this->defnType == Type::Intrinsic) - { - this->intrinsicDefn->isIntrinsic = true; - return this->intrinsicDefn->typecheck(fs, infer); - } - else if(this->defnType == Type::IntegerType) - { - auto defn = util::pool(this->loc); - // auto opty = fir::OpaqueType::get(this->typeName, this->typeSizeInBits); - auto ty = fir::PrimitiveType::getUintN(this->typeSizeInBits); - - defn->type = ty; - defn->id = Identifier(this->typeName, IdKind::Type); - defn->id.scope = fs->scope(); - - fs->checkForShadowingOrConflictingDefinition(defn, [](sst::TypecheckState* fs, sst::Defn* other) -> bool { return true; }); - - // add it first so we can use it in the method bodies, - // and make pointers to it - { - fs->stree->addDefinition(this->typeName, defn); - fs->typeDefnMap[ty] = defn; - } - - return TCResult(defn); - } - else - { - return TCResult(SimpleError::make(this->loc, "nani?")); - } -} - - - - - - - - - - - - - - - - diff --git a/source/typecheck/operators.cpp b/source/typecheck/operators.cpp index 7327343b..6d7bb255 100644 --- a/source/typecheck/operators.cpp +++ b/source/typecheck/operators.cpp @@ -10,13 +10,10 @@ static bool isBuiltinType(fir::Type* ty) { - return (ty->isConstantNumberType() - || ty->isDynamicArrayType() - || ty->isArraySliceType() + return (ty->isArraySliceType() || ty->isPrimitiveType() || ty->isFunctionType() || ty->isPointerType() - || ty->isStringType() || ty->isRangeType() || ty->isArrayType() || ty->isVoidType() diff --git a/source/typecheck/polymorph/driver.cpp b/source/typecheck/polymorph/driver.cpp index 91e39bc6..d883cfef 100644 --- a/source/typecheck/polymorph/driver.cpp +++ b/source/typecheck/polymorph/driver.cpp @@ -74,42 +74,6 @@ namespace poly return { soln, nullptr }; } } - else if(auto cls = dcast(ast::ClassDefn, td)) - { - util::hash_map paramOrder; - - auto inputcopy = input; - auto selfty = fir::PolyPlaceholderType::get(fir::obfuscateName("self_infer"), getNextSessionId()); - inputcopy.insert(inputcopy.begin(), FnCallArgument(fs->loc(), "", util::pool(fs->loc(), - selfty->getMutablePointerTo()), 0)); - - fs->pushSelfContext(selfty); - defer(fs->popSelfContext()); - - - - std::vector> rets; - for(auto init : cls->initialisers) - { - rets.push_back(inferTypesForPolymorph(fs, init, name, cls->generics, inputcopy, partial, return_infer, type_infer, isFnCall, - problem_infer, ¶mOrder)); - } - - // check the distance of all the solutions... i guess? - std::pair best; - best.first = soln; - best.first.distance = INT_MAX; - best.second = SimpleError::make(fs->loc(), "ambiguous reference to constructor of class '%s'", cls->name); - - for(const auto& r : rets) - { - if(r.first.distance < best.first.distance && r.second == nullptr) - best = r; - } - - *origParamOrder = paramOrder; - return best; - } else if(auto str = dcast(ast::StructDefn, td)) { //* for constructors, we look like a function call, so type_infer is actually return_infer. @@ -218,33 +182,19 @@ namespace poly - static std::pair inferPolymorphicFunction(TypecheckState* fs, ast::Parameterisable* thing, const std::string& name, + static std::pair inferPolymorphicFunction(TypecheckState* fs, ast::FuncDefn* func, + const std::string& name, const ProblemSpace_t& problems, const std::vector& input, const TypeParamMap_t& partial, fir::Type* return_infer, fir::Type* type_infer, bool isFnCall, fir::Type* problem_infer, util::hash_map* origParamOrder) { auto soln = Solution_t(partial); - bool isinit = dcast(ast::InitFunctionDefn, thing) != nullptr; - iceAssert(dcast(ast::FuncDefn, thing) || isinit); - std::vector given; std::vector target; - pts::Type* retty = 0; - std::vector params; - - if(isinit) - { - auto i = dcast(ast::InitFunctionDefn, thing); - params = i->params; - } - else - { - auto i = dcast(ast::FuncDefn, thing); - retty = i->returnType; - params = i->params; - } + auto retty = func->returnType; + auto params =func->params; int session = getNextSessionId(); @@ -252,10 +202,10 @@ namespace poly { target = internal::unwrapFunctionParameters(fs, problems, params, session); - if(!isinit && (!isFnCall || return_infer)) + if(!isFnCall || return_infer) { // add the return type to the fray. it doesn't have a name tho - target.push_back(ArgType("", convertPtsType(fs, thing->generics, retty, session), thing->loc)); + target.push_back(ArgType("", convertPtsType(fs, func->generics, retty, session), func->loc)); } } else @@ -288,13 +238,13 @@ namespace poly return { soln, nullptr }; else if(!type_infer->isFunctionType()) - return { soln, SimpleError::make(fs->loc(), "invalid type '%s' inferred for '%s'", type_infer, thing->name) }; + return { soln, SimpleError::make(fs->loc(), "invalid type '%s' inferred for '%s'", type_infer, func->name) }; // ok, we should have it. iceAssert(type_infer->isFunctionType()); given = zfu::mapIdx(type_infer->toFunctionType()->getArgumentTypes(), [¶ms](fir::Type* t, size_t i) -> ArgType { return ArgType(params[i].name, t, params[i].loc); - }) + ArgType("", type_infer->toFunctionType()->getReturnType(), thing->loc); + }) + ArgType("", type_infer->toFunctionType()->getReturnType(), func->loc); } return solveTypeList(fs->loc(), target, given, soln, isFnCall); @@ -314,9 +264,10 @@ namespace poly { return inferPolymorphicType(fs, td, name, problems, input, partial, return_infer, type_infer, isFnCall, problem_infer, origParamOrder); } - else if(dcast(ast::FuncDefn, thing) || dcast(ast::InitFunctionDefn, thing)) + else if(auto fd = dcast(ast::FuncDefn, thing)) { - return inferPolymorphicFunction(fs, thing, name, problems, input, partial, return_infer, type_infer, isFnCall, problem_infer, origParamOrder); + return inferPolymorphicFunction(fs, fd, name, problems, input, partial, return_infer, type_infer, + isFnCall, problem_infer, origParamOrder); } else { diff --git a/source/typecheck/polymorph/instantiator.cpp b/source/typecheck/polymorph/instantiator.cpp index d0d6376a..0561d5a3 100644 --- a/source/typecheck/polymorph/instantiator.cpp +++ b/source/typecheck/polymorph/instantiator.cpp @@ -119,7 +119,7 @@ namespace poly using the newly-gained arg_infer information, we can re-typecheck the argument with concrete types. - zhiayang - - 06/10/18/2318 + - 06/10/18 */ auto arg_infer = d.defn()->type->toFunctionType()->getArgumentN(arg.name.empty() ? counter : origParamOrder[arg.name]); diff --git a/source/typecheck/polymorph/misc.cpp b/source/typecheck/polymorph/misc.cpp index 261e7e43..66c15f2e 100644 --- a/source/typecheck/polymorph/misc.cpp +++ b/source/typecheck/polymorph/misc.cpp @@ -24,11 +24,7 @@ namespace sst fir::Type* mergeNumberTypes(fir::Type* a, fir::Type* b) { - if(a->isConstantNumberType() && b->isConstantNumberType()) - { - return fir::unifyConstantTypes(a->toConstantNumberType(), b->toConstantNumberType()); - } - else if(a->isFloatingPointType() && b->isIntegerType()) + if(a->isFloatingPointType() && b->isIntegerType()) { return a; } @@ -63,7 +59,7 @@ namespace sst fty = fir::PolyPlaceholderType::get(ty->toNamedType()->name, polysession); } - if(!fty) error("failed to find type '%s'", input->str()); + if(!fty) error(fs->loc(), "failed to find type '%s'", input->str()); } else if(ty->isTupleType()) { diff --git a/source/typecheck/polymorph/solver.cpp b/source/typecheck/polymorph/solver.cpp index 81db0257..9c99b2b6 100644 --- a/source/typecheck/polymorph/solver.cpp +++ b/source/typecheck/polymorph/solver.cpp @@ -62,13 +62,7 @@ namespace sst // check for conflict. if(!ltt->isPolyPlaceholderType() && !gt->isPolyPlaceholderType()) { - if(ltt->isConstantNumberType() || gt->isConstantNumberType()) - { - gt = internal::mergeNumberTypes(ltt, gt); - if(gt != ltt) - soln->addSolution(ptt->getName(), fir::LocatedType(gt, given.loc)); - } - else if(ltt != gt) + if(ltt != gt) { if(int d = fir::getCastDistance(gt, ltt); d >= 0) { @@ -76,7 +70,8 @@ namespace sst } else { - return SimpleError::make(given.loc, "conflicting solutions for type parameter '%s': previous: '%s', current: '%s'", + return SimpleError::make(given.loc, + "conflicting solutions for type parameter '%s': previous: '%s', current: '%s'", ptt->getName(), ltt->str(), gvn); } } @@ -405,12 +400,6 @@ namespace sst } - for(auto& pair : prevSoln.solutions) - { - if(pair.second->isConstantNumberType()) - pair.second = fir::getBestFitTypeForConstant(pair.second->toConstantNumberType()); - } - return { prevSoln, nullptr }; } } diff --git a/source/typecheck/polymorph/transforms.cpp b/source/typecheck/polymorph/transforms.cpp index 4a3649a7..c95f2c63 100644 --- a/source/typecheck/polymorph/transforms.cpp +++ b/source/typecheck/polymorph/transforms.cpp @@ -79,12 +79,7 @@ namespace poly for(size_t i = 0; i < max; i++) { - if(t->isDynamicArrayType()) - { - ret.push_back(Trf(TrfType::DynamicArray)); - t = t->getArrayElementType(); - } - else if(t->isArraySliceType()) + if(t->isArraySliceType()) { if(t->isVariadicArrayType()) ret.push_back(Trf(TrfType::VariadicArray)); else ret.push_back(Trf(TrfType::Slice, t->toArraySliceType()->isMutable())); @@ -116,12 +111,7 @@ namespace poly while(true) { - if(t->isDynamicArrayType()) - { - ret.push_back(Trf(TrfType::DynamicArray)); - t = t->toDynamicArrayType()->base; - } - else if(t->isArraySliceType()) + if(t->isArraySliceType()) { ret.push_back(Trf(TrfType::Slice, t->toArraySliceType()->mut)); t = t->toArraySliceType()->base; @@ -169,9 +159,6 @@ namespace poly case TrfType::FixedArray: base = fir::ArrayType::get(base, it->data); break; - case TrfType::DynamicArray: - base = fir::DynamicArrayType::get(base); - break; case TrfType::VariadicArray: base = fir::ArraySliceType::getVariadic(base); break; diff --git a/source/typecheck/resolver/driver.cpp b/source/typecheck/resolver/driver.cpp index 1e00cd2e..fd353e67 100644 --- a/source/typecheck/resolver/driver.cpp +++ b/source/typecheck/resolver/driver.cpp @@ -32,21 +32,11 @@ namespace resolver { StateTree* tree = fs->stree; - //* the purpose of this 'didVar' flag (because I was fucking confused reading this) - //* is so we only consider the innermost (ie. most local) variable, because variables don't participate in overloading. - //! ACHTUNG ! - // TODO: do we even need this didVar nonsense? variables don't overload yes, but we can't even define more than one - // TODO: variable in a scope with the same name. if we find something with a matching name we quit immediately, so there - // TODO: shouldn't be a point in having 'didVar'!! - // TODO: - zhiayang, 28/10/18 - - //? I can't find any information about this behaviour in languages other than C++, because we need to have a certain set of //? features for it to manifest -- 1. user-defined, explicit namespaces; 2. function overloading. //* how it works in C++, and for now also in Flax, is that once we match *any* names in the current scope, we stop searching upwards //* -- even if it means we will throw an error because of mismatched arguments or whatever. - // bool didVar = false; bool didGeneric = false; @@ -137,10 +127,9 @@ namespace resolver { cands.push_back({ def, ts }); } - else if(dcast(VarDefn, def) && def->type->isFunctionType() /* && !didVar */) + else if(dcast(VarDefn, def) && def->type->isFunctionType()) { cands.push_back({ def, ts }); - // didVar = true; } else { @@ -151,7 +140,9 @@ namespace resolver } } - auto [ res, new_args ] = resolver::internal::resolveFunctionCallFromCandidates(fs, fs->loc(), cands, gmaps, travUp, return_infer); + // auto [ res, new_args ] = resolver::internal::resolveFunctionCallFromCandidates(fs, fs->loc(), cands, gmaps, travUp, return_infer); + auto [ res, new_args ] = resolver::internal::resolveFunctionCallFromCandidates(fs, fs->loc(), cands, { }, travUp, return_infer); + if(res.isDefn()) *arguments = new_args; @@ -164,48 +155,7 @@ namespace resolver TCResult resolveConstructorCall(TypecheckState* fs, const Location& callLoc, TypeDefn* typedf, const std::vector& arguments, const PolyArgMapping_t& pams) { - //! ACHTUNG: DO NOT REARRANGE ! - //* NOTE: ClassDefn inherits from StructDefn * - - if(auto cls = dcast(ClassDefn, typedf)) - { - // class initialisers must be called with named arguments only. - for(const auto& arg : arguments) - { - if(arg.name.empty()) - { - return TCResult(SimpleError::make(arg.loc, "arguments to class initialisers (for class '%s' here) must be named", cls->id.name)); - } - } - - auto copy = arguments; - - //! SELF HANDLING (INSERTION) (CONSTRUCTOR CALL) - copy.insert(copy.begin(), FnCallArgument::make(cls->loc, "this", cls->type->getMutablePointerTo(), - /* ignoreName: */ true)); - - auto copy1 = copy; - - auto cand = resolveFunctionCallFromCandidates(fs, callLoc, zfu::map(cls->initialisers, [](auto e) -> auto { - return dcast(sst::Defn, e); - }), ©, pams, true); - - // TODO: support re-eval of constructor args! - // TODO: support re-eval of constructor args! - // TODO: support re-eval of constructor args! - - if(cand.isError()) - { - cand.error()->prepend(SimpleError::make(fs->loc(), "failed to find matching initialiser for class '%s':", cls->id.name)); - return TCResult(cand.error()); - } - - if(copy1 != copy) - error(fs->loc(), "args changed for constructor call -- fixme!!!"); - - return TCResult(cand); - } - else if(auto str = dcast(StructDefn, typedf)) + if(auto str = dcast(StructDefn, typedf)) { std::vector fieldNames; @@ -289,7 +239,7 @@ namespace resolver } else if(arguments.size() == 1) { - if(int d = getCastDistance(arguments[0].value->type, type); d >= 0 || (type->isStringType() && arguments[0].value->type->isCharSliceType())) + if(int d = getCastDistance(arguments[0].value->type, type); d >= 0) { return type; } @@ -301,46 +251,7 @@ namespace resolver } else { - if(type->isStringType()) - { - // either from a slice, or from a ptr + len - if(arguments.size() == 1) - { - if(!arguments[0].value->type->isCharSliceType()) - { - error(arguments[0].loc, "single argument to string initialiser must be a slice of char, aka '%s', found '%s' instead", - fir::Type::getCharSlice(false), arguments[0].value->type); - } - - return type; - } - else if(arguments.size() == 2) - { - if(auto t1 = arguments[0].value->type; (t1 != fir::Type::getInt8Ptr() && t1 != fir::Type::getMutInt8Ptr())) - { - error(arguments[0].loc, "first argument to two-arg string initialiser (data pointer) must be '%s' or '%s', found '%s' instead", - fir::Type::getInt8Ptr(), fir::Type::getMutInt8Ptr(), t1); - } - else if(auto t2 = arguments[1].value->type; fir::getCastDistance(t2, fir::Type::getNativeWord()) < 0) - { - error(arguments[0].loc, "second argument to two-arg string initialiser (length) must be '%s', found '%s' instead", - fir::Type::getNativeWord(), t2); - } - else - { - return type; - } - } - else - { - error(arguments[2].loc, "string initialiser only takes 1 (from slice) or 2 (from pointer+length)" - " arguments, found '%d' instead", arguments.size()); - } - } - else - { - error(arguments[1].loc, "builtin type '%s' cannot be initialised with more than 1 value", type); - } + error(arguments[1].loc, "builtin type '%s' cannot be initialised with more than 1 value", type); } } diff --git a/source/typecheck/resolver/misc.cpp b/source/typecheck/resolver/misc.cpp index 22e808d1..ba18188a 100644 --- a/source/typecheck/resolver/misc.cpp +++ b/source/typecheck/resolver/misc.cpp @@ -18,7 +18,10 @@ namespace sst std::pair canonicalisePolyArguments(TypecheckState* fs, ast::Parameterisable* thing, const PolyArgMapping_t& pams) { if(thing->generics.empty()) - return { { }, SimpleError::make(fs->loc(), "cannot canonicalise poly arguments for non-generic (or nested) entity '%s'", thing->name) }; + { + return { { }, SimpleError::make(fs->loc(), "cannot canonicalise poly arguments for non-generic (or nested) entity '%s'", + thing->name) }; + } TypeParamMap_t ret; @@ -26,7 +29,8 @@ namespace sst //? to infer stuff. if(thing->generics.size() < pams.maps.size()) { - return { { }, SimpleError::make(fs->loc(), "mismatched number of type arguments to polymorph '%s'; expected %d, found %d instead", + return { { }, SimpleError::make(fs->loc(), + "mismatched number of type arguments to polymorph '%s'; expected %d, found %d instead", thing->name, thing->generics.size(), pams.maps.size()) }; } diff --git a/source/typecheck/resolver/resolver.cpp b/source/typecheck/resolver/resolver.cpp index 5a235002..f1a1edd9 100644 --- a/source/typecheck/resolver/resolver.cpp +++ b/source/typecheck/resolver/resolver.cpp @@ -2,6 +2,7 @@ // Copyright (c) 2017, zhiayang // Licensed under the Apache License Version 2.0. +#include "defs.h" #include "sst.h" #include "errors.h" #include "ir/type.h" @@ -166,6 +167,8 @@ namespace resolver if(fn->type->containsPlaceholders()) { + iceAssert(false && "INVESTIGATE ME: what is this???"); + if(auto fd = dcast(FunctionDefn, fn); !fd) { error(fd, "invalid non-definition of a function with placeholder types"); @@ -209,7 +212,7 @@ namespace resolver if(!pams.empty()) { - fails[fn] = complainAboutExtraneousPAMs("non-polymorphic function", fn, "called", /* printdef: */ true); + fails[fn] = complainAboutExtraneousPAMs("non-polymorphic function", fn, "called", /* printdef: */ false); } else { @@ -312,60 +315,16 @@ namespace resolver { // check if all of the targets we found are virtual, and that they belong to the same class. - bool virt = true; - fir::ClassType* self = 0; - - Defn* ret = std::get<0>(finals[0]); + auto err = SimpleError::make(callLoc, "ambiguous call to function '%s', have %d candidates:", + cands[0].first->id.name, finals.size()); - for(auto def : finals) + for(auto f : finals) { - if(auto fd = dcast(sst::FunctionDefn, std::get<0>(def)); fd && fd->isVirtual) - { - iceAssert(fd->parentTypeForMethod); - iceAssert(fd->parentTypeForMethod->isClassType()); - - if(!self) - { - self = fd->parentTypeForMethod->toClassType(); - } - else - { - // check if they're co/contra variant - auto ty = fd->parentTypeForMethod->toClassType(); - - //* here we're just checking that 'ty' and 'self' are part of the same class hierarchy -- we don't really care about the method - //* that we resolve being at the lowest or highest level of that hierarchy. - - if(!ty->hasParent(self) && !self->hasParent(ty)) - { - virt = false; - break; - } - } - } - else - { - virt = false; - break; - } + err->append(SimpleError::make(MsgType::Note, std::get<0>(f)->loc, + "possible target (overload distance %d):", std::get<2>(f))); } - if(virt) - { - return { TCResult(ret), std::get<1>(finals[0]) }; - } - else - { - auto err = SimpleError::make(callLoc, "ambiguous call to function '%s', have %d candidates:", - cands[0].first->id.name, finals.size()); - - for(auto f : finals) - { - err->append(SimpleError::make(MsgType::Note, std::get<0>(f)->loc, "possible target (overload distance %d):", std::get<2>(f))); - } - - return { TCResult(err), { } }; - } + return { TCResult(err), { } }; } else { diff --git a/source/typecheck/sizeof.cpp b/source/typecheck/sizeof.cpp index c470ab0c..5f5c0c4c 100644 --- a/source/typecheck/sizeof.cpp +++ b/source/typecheck/sizeof.cpp @@ -23,7 +23,7 @@ TCResult ast::SizeofOp::typecheck(sst::TypecheckState* fs, fir::Type* infer) } this->expr->checkAsType = true; - fir::Type* out = this->expr->typecheck(fs).expr()->type; + fir::Type* out = this->expr->typecheck(fs).expr()->type; iceAssert(out); ret->typeToSize = out; @@ -45,7 +45,7 @@ TCResult ast::TypeidOp::typecheck(sst::TypecheckState* fs, fir::Type* inferred) } this->expr->checkAsType = true; - fir::Type* out = this->expr->typecheck(fs).expr()->type; + fir::Type* out = this->expr->typecheck(fs).expr()->type; iceAssert(out); ret->typeToId = out; diff --git a/source/typecheck/slice.cpp b/source/typecheck/slice.cpp index 53462f99..ca1dabeb 100644 --- a/source/typecheck/slice.cpp +++ b/source/typecheck/slice.cpp @@ -12,10 +12,7 @@ bool sst::getMutabilityOfSliceOfType(fir::Type* ty) { - if(ty->isStringType() || ty->isDynamicArrayType()) - return true; - - else if(ty->isArrayType()) + if(ty->isArrayType()) return false; else if(ty->isArraySliceType()) @@ -43,12 +40,9 @@ TCResult ast::SliceOp::typecheck(sst::TypecheckState* fs, fir::Type* inferred) defer(fs->leaveSubscript()); fir::Type* elm = 0; - if(ty->isDynamicArrayType() || ty->isArraySliceType() || ty->isArrayType()) + if(ty->isArraySliceType() || ty->isArrayType()) elm = ty->getArrayElementType(); - else if(ty->isStringType()) - elm = fir::Type::getInt8(); - else if(ty->isPointerType()) elm = ty->getPointerElementType(); diff --git a/source/typecheck/special.cpp b/source/typecheck/special.cpp index 8b8d38d3..d54ebf9d 100644 --- a/source/typecheck/special.cpp +++ b/source/typecheck/special.cpp @@ -33,7 +33,7 @@ TCResult ast::SplatOp::typecheck(sst::TypecheckState* fs, fir::Type* infer) auto inside = this->expr->typecheck(fs, infer).expr(); - if(!inside->type->isArraySliceType() && !inside->type->isArrayType() && !inside->type->isDynamicArrayType() && !inside->type->isTupleType()) + if(!inside->type->isArraySliceType() && !inside->type->isArrayType() && !inside->type->isTupleType()) return TCResult(SimpleError::make(this->loc, "invalid use of splat operator on type '%s'", inside->type)); if(inside->type->isTupleType()) diff --git a/source/typecheck/structs.cpp b/source/typecheck/structs.cpp index 13449908..576d7df3 100644 --- a/source/typecheck/structs.cpp +++ b/source/typecheck/structs.cpp @@ -15,7 +15,7 @@ static void _checkFieldRecursion(sst::TypecheckState* fs, fir::Type* strty, fir: static void _checkTransparentFieldRedefinition(sst::TypecheckState* fs, sst::TypeDefn* defn, const std::vector& fields, util::hash_map& seen); -// used in typecheck/unions.cpp and typecheck/classes.cpp +// used in typecheck/unions.cpp void checkFieldRecursion(sst::TypecheckState* fs, fir::Type* strty, fir::Type* field, const Location& floc) { std::set seeing; @@ -193,11 +193,6 @@ static void _checkFieldRecursion(sst::TypecheckState* fs, fir::Type* strty, fir: ->append(SimpleError::make(MsgType::Note, fs->typeDefnMap[strty]->loc, "type '%s' was defined here:", strty)) ->postAndQuit(); } - else if(field->isClassType()) - { - for(auto f : field->toClassType()->getElements()) - _checkFieldRecursion(fs, field, f, floc, seeing); - } else if(field->isStructType()) { for(auto f : field->toStructType()->getElements()) diff --git a/source/typecheck/subscript.cpp b/source/typecheck/subscript.cpp index ec60fd3f..a4ea5d81 100644 --- a/source/typecheck/subscript.cpp +++ b/source/typecheck/subscript.cpp @@ -27,19 +27,17 @@ TCResult ast::SubscriptOp::typecheck(sst::TypecheckState* fs, fir::Type* infer) auto lt = ls->type; auto rt = rs->type; - if((rt->isConstantNumberType() && rt->toConstantNumberType()->isFloating()) && !rt->isIntegerType()) + if(!rt->isIntegerType()) error(this->inside, "subscript index must be an integer type, found '%s'", rt); fir::Type* res = 0; // check what it is, then - if(lt->isDynamicArrayType()) res = lt->toDynamicArrayType()->getElementType(); - else if(lt->isArraySliceType()) res = lt->toArraySliceType()->getElementType(); - else if(lt->isPointerType()) res = lt->getPointerElementType(); - else if(lt->isArrayType()) res = lt->toArrayType()->getElementType(); - else if(lt->isStringType()) res = fir::Type::getInt8(); - else error(this->expr, "cannot subscript type '%s'", lt); + if(lt->isArraySliceType()) res = lt->toArraySliceType()->getElementType(); + else if(lt->isPointerType()) res = lt->getPointerElementType(); + else if(lt->isArrayType()) res = lt->toArrayType()->getElementType(); + else error(this->expr, "cannot subscript type '%s'", lt); iceAssert(res); auto ret = util::pool(this->loc, res); @@ -59,8 +57,7 @@ TCResult ast::SubscriptDollarOp::typecheck(sst::TypecheckState* fs, fir::Type* i error(this, "invalid use of '$' in non-subscript context"); else if(auto arr = fs->getCurrentSubscriptArray(); - arr->type->isPointerType() || !(arr->type->isArraySliceType() || arr->type->isArrayType() || arr->type->isStringType() - || arr->type->isDynamicArrayType())) + arr->type->isPointerType() || !(arr->type->isArraySliceType() || arr->type->isArrayType())) { SpanError::make(SimpleError::make(this->loc, "invalid use of '$' on subscriptee with %stype '%s'", arr->type->isPointerType() ? "pointer " : "", arr->type)) diff --git a/source/typecheck/traits.cpp b/source/typecheck/traits.cpp index 3e77c850..fc2cbdf1 100644 --- a/source/typecheck/traits.cpp +++ b/source/typecheck/traits.cpp @@ -150,14 +150,7 @@ void checkTraitConformity(sst::TypecheckState* fs, sst::TypeDefn* defn) std::vector traits; util::hash_map> methods; - if(auto cls = dcast(sst::ClassDefn, defn)) - { - for(auto m : cls->methods) - methods[m->id.name].push_back(m); - - error("wait a bit"); - } - else if(auto str = dcast(sst::StructDefn, defn)) + if(auto str = dcast(sst::StructDefn, defn)) { for(auto m : str->methods) methods[m->id.name].push_back(m); diff --git a/source/typecheck/type.cpp b/source/typecheck/type.cpp index e133d2f8..d31800c2 100644 --- a/source/typecheck/type.cpp +++ b/source/typecheck/type.cpp @@ -15,42 +15,11 @@ namespace sst { - fir::Type* inferCorrectTypeForLiteral(fir::ConstantNumberType* type) - { - auto ty = type->toConstantNumberType(); - { - if(ty->isFloating()) - { - if(ty->getMinBits() <= fir::Type::getFloat64()->getBitWidth()) - return fir::Type::getFloat64(); - - else if(ty->getMinBits() <= fir::Type::getFloat128()->getBitWidth()) - return fir::Type::getFloat128(); - - else - error("float overflow"); - } - else - { - if(ty->getMinBits() <= fir::Type::getNativeWord()->getBitWidth() - 1) - return fir::Type::getNativeWord(); - - else if(!ty->isSigned() && ty->getMinBits() <= fir::Type::getNativeUWord()->getBitWidth()) - return fir::Type::getNativeUWord(); - - else - error("int overflow"); - } - } - } - - static ErrorMsg* _complainNoParentScope(TypecheckState* fs, const std::string& top) { return SimpleError::make(fs->loc(), "invalid use of '^' at the topmost scope '%s'", top); } - static StateTree* recursivelyFindTreeUpwards(TypecheckState* fs, const std::string& name) { auto from = fs->stree; @@ -375,10 +344,6 @@ namespace sst { return fir::ArraySliceType::get(this->convertParserTypeToFIR(pt->toArraySliceType()->base), pt->toArraySliceType()->mut); } - else if(pt->isDynamicArrayType()) - { - return fir::DynamicArrayType::get(this->convertParserTypeToFIR(pt->toDynamicArrayType()->base)); - } else if(pt->isVariadicArrayType()) { return fir::ArraySliceType::getVariadic(this->convertParserTypeToFIR(pt->toVariadicArrayType()->base)); diff --git a/source/typecheck/unions.cpp b/source/typecheck/unions.cpp index 3aef2241..35f62ebb 100644 --- a/source/typecheck/unions.cpp +++ b/source/typecheck/unions.cpp @@ -103,9 +103,6 @@ TCResult ast::UnionDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer, co auto sfd = dcast(sst::StructFieldDefn, vdef->typecheck(fs).defn()); iceAssert(sfd); - if(fir::isRefCountedType(sfd->type)) - error(sfd, "reference-counted type '%s' cannot be a member of a raw union", sfd->type); - checkFieldRecursion(fs, unionTy, sfd->type, sfd->loc); return sfd; }; diff --git a/source/typecheck/variable.cpp b/source/typecheck/variable.cpp index d7ac9849..8de25d46 100644 --- a/source/typecheck/variable.cpp +++ b/source/typecheck/variable.cpp @@ -353,11 +353,7 @@ TCResult ast::VarDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer) if(defn->type == 0) { - auto t = defn->init->type; - if(t->isConstantNumberType()) - t = sst::inferCorrectTypeForLiteral(defn->init->type->toConstantNumberType()); - - defn->type = t; + defn->type = defn->init->type; } else if(fir::getCastDistance(defn->init->type, defn->type) < 0) {