https://gcc.gnu.org/g:cb2e6d872e374ee0df02414e1c1f31ed4cb28be8
commit cb2e6d872e374ee0df02414e1c1f31ed4cb28be8 Author: Thomas Koenig <tkoe...@gcc.gnu.org> Date: Mon Jul 22 22:53:27 2024 +0200 Very first program compiles. Diff: --- gcc/fortran/decl.cc | 11 +++++ gcc/fortran/dump-parse-tree.cc | 8 ++++ gcc/fortran/expr.cc | 1 + gcc/fortran/gfortran.h | 20 ++++++++ gcc/fortran/libgfortran.h | 2 +- gcc/fortran/match.cc | 7 +++ gcc/fortran/misc.cc | 6 +++ gcc/fortran/primary.cc | 80 ++++++++++++++++++++++++++++++++ gcc/fortran/trans-const.cc | 11 +++++ gcc/fortran/trans-types.cc | 69 +++++++++++++++++++++++++++ gcc/fortran/trans-types.h | 1 + gcc/testsuite/gfortran.dg/unsigned_1.f90 | 8 ++++ 12 files changed, 223 insertions(+), 1 deletion(-) diff --git a/gcc/fortran/decl.cc b/gcc/fortran/decl.cc index b8308aeee550..cc358f09b838 100644 --- a/gcc/fortran/decl.cc +++ b/gcc/fortran/decl.cc @@ -4342,6 +4342,17 @@ gfc_match_decl_type_spec (gfc_typespec *ts, int implicit_flag) goto get_kind; } + if (flag_unsigned) + { + if ((matched_type && strcmp ("unsigned", name) == 0) + || (!matched_type && gfc_match (" unsigned") == MATCH_YES)) + { + ts->type = BT_UNSIGNED; + ts->kind = gfc_default_integer_kind; + goto get_kind; + } + } + if ((matched_type && strcmp ("character", name) == 0) || (!matched_type && gfc_match (" character") == MATCH_YES)) { diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc index 80aa8ef84e71..e94dc495708a 100644 --- a/gcc/fortran/dump-parse-tree.cc +++ b/gcc/fortran/dump-parse-tree.cc @@ -563,6 +563,14 @@ show_expr (gfc_expr *p) fprintf (dumpfile, "_%d", p->ts.kind); break; + case BT_UNSIGNED: + mpz_out_str (dumpfile, 10, p->value.integer); + fputc('u', dumpfile); + + if (p->ts.kind != gfc_default_integer_kind) + fprintf (dumpfile, "_%d", p->ts.kind); + break; + case BT_LOGICAL: if (p->value.logical) fputs (".true.", dumpfile); diff --git a/gcc/fortran/expr.cc b/gcc/fortran/expr.cc index 8de694e31da7..2c1f965c73a2 100644 --- a/gcc/fortran/expr.cc +++ b/gcc/fortran/expr.cc @@ -159,6 +159,7 @@ gfc_get_constant_expr (bt type, int kind, locus *where) switch (type) { case BT_INTEGER: + case BT_UNSIGNED: mpz_init (e->value.integer); break; diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 3bdf18d6f9bc..d51960ff0d31 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -2732,6 +2732,25 @@ gfc_integer_info; extern gfc_integer_info gfc_integer_kinds[]; +/* Unsigned numbers, experimental. */ + +typedef struct +{ + mpz_t huge; + + int kind, radix, digits, bit_size, range; + + /* True if the C type of the given name maps to this precision. Note that + more than one bit can be set. We will use this later on. */ + unsigned int c_unsigned_char : 1; + unsigned int c_unsigned_short : 1; + unsigned int c_unsigned_int : 1; + unsigned int c_unsigned_long : 1; + unsigned int c_unsigned_long_long : 1; +} +gfc_unsigned_info; + +extern gfc_unsigned_info gfc_unsigned_kinds[]; typedef struct { @@ -3455,6 +3474,7 @@ tree gfc_get_union_type (gfc_symbol *); tree gfc_get_derived_type (gfc_symbol * derived, int codimen = 0); extern int gfc_index_integer_kind; extern int gfc_default_integer_kind; +extern int gfc_default_unsigned_kind; extern int gfc_max_integer_kind; extern int gfc_default_real_kind; extern int gfc_default_double_kind; diff --git a/gcc/fortran/libgfortran.h b/gcc/fortran/libgfortran.h index 2cb4a5a08ffd..895629d6f801 100644 --- a/gcc/fortran/libgfortran.h +++ b/gcc/fortran/libgfortran.h @@ -190,7 +190,7 @@ typedef enum typedef enum { BT_UNKNOWN = 0, BT_INTEGER, BT_LOGICAL, BT_REAL, BT_COMPLEX, BT_DERIVED, BT_CHARACTER, BT_CLASS, BT_PROCEDURE, BT_HOLLERITH, BT_VOID, - BT_ASSUMED, BT_UNION, BT_BOZ + BT_ASSUMED, BT_UNION, BT_BOZ, BT_UNSIGNED } bt; diff --git a/gcc/fortran/match.cc b/gcc/fortran/match.cc index 1851a8f94a54..e206da95bde1 100644 --- a/gcc/fortran/match.cc +++ b/gcc/fortran/match.cc @@ -2131,6 +2131,13 @@ gfc_match_type_spec (gfc_typespec *ts) goto kind_selector; } + if (flag_unsigned && gfc_match ("unsigned") == MATCH_YES) + { + ts->type = BT_UNSIGNED; + ts->kind = gfc_default_integer_kind; + goto kind_selector; + } + if (gfc_match ("double precision") == MATCH_YES) { ts->type = BT_REAL; diff --git a/gcc/fortran/misc.cc b/gcc/fortran/misc.cc index a365cec9b492..991829516efe 100644 --- a/gcc/fortran/misc.cc +++ b/gcc/fortran/misc.cc @@ -70,6 +70,9 @@ gfc_basic_typename (bt type) case BT_INTEGER: p = "INTEGER"; break; + case BT_UNSIGNED: + p = "UNSIGNED"; + break; case BT_REAL: p = "REAL"; break; @@ -145,6 +148,9 @@ gfc_typename (gfc_typespec *ts, bool for_hash) else sprintf (buffer, "INTEGER(%d)", ts->kind); break; + case BT_UNSIGNED: + sprintf (buffer, "UNSIGNED(%d)", ts->kind); + break; case BT_REAL: sprintf (buffer, "REAL(%d)", ts->kind); break; diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc index 76f6bcb8a789..d2a6e69fa428 100644 --- a/gcc/fortran/primary.cc +++ b/gcc/fortran/primary.cc @@ -209,6 +209,24 @@ convert_integer (const char *buffer, int kind, int radix, locus *where) } +/* Convert an unsigned string to an expression node. XXX: + This needs a calculation modulo 2^n. */ +static gfc_expr * +convert_unsigned (const char *buffer, int kind, int radix, locus *where) +{ + gfc_expr *e; + mpz_t tmp; + mpz_init_set_ui (tmp, 1); + /* XXX Change this later. */ + mpz_mul_2exp (tmp, tmp, kind * 8); + mpz_sub_ui (tmp, tmp, 1); + e = gfc_get_constant_expr (BT_UNSIGNED, kind, where); + mpz_set_str (e->value.integer, buffer, radix); + mpz_and (e->value.integer, e->value.integer, tmp); + mpz_clear (tmp); + return e; +} + /* Convert a real string to an expression node. */ static gfc_expr * @@ -296,6 +314,61 @@ match_integer_constant (gfc_expr **result, int signflag) return MATCH_YES; } +/* Match an unsigned constant (an integer with suffixed u). No sign + is currently accepted, in accordance with 24-116.txt, but that + could be changed later. This is very much like the integer + constant matching above, but with enough differences to put it into + its own function. */ + +static match +match_unsigned_constant (gfc_expr **result) +{ + int length, kind, is_iso_c; + locus old_loc; + char *buffer; + gfc_expr *e; + match m; + + old_loc = gfc_current_locus; + gfc_gobble_whitespace (); + + length = match_digits (/* signflag = */ false, 10, NULL); + gfc_current_locus = old_loc; + if (length == -1) + return MATCH_NO; + + buffer = (char *) alloca (length + 1); + memset (buffer, '\0', length + 1); + + gfc_gobble_whitespace (); + + match_digits (false, 10, buffer); + m = gfc_match_char ('u'); + if (m == MATCH_NO) + return m; + + kind = get_kind (&is_iso_c); + if (kind == -2) + kind = gfc_default_unsigned_kind; + if (kind == -1) + return MATCH_ERROR; + + if (kind == 4 && flag_integer4_kind == 8) + kind = 8; + + if (gfc_validate_kind (BT_UNSIGNED, kind, true) < 0) + { + gfc_error ("Unsigned kind %d at %C not available", kind); + return MATCH_ERROR; + } + + e = convert_unsigned (buffer, kind, 10, &gfc_current_locus); + e->ts.is_c_interop = is_iso_c; + + *result = e; + return MATCH_YES; + +} /* Match a Hollerith constant. */ @@ -1549,6 +1622,13 @@ gfc_match_literal_constant (gfc_expr **result, int signflag) if (m != MATCH_NO) return m; + if (flag_unsigned) + { + m = match_unsigned_constant (result); + if (m != MATCH_NO) + return m; + } + m = match_integer_constant (result, signflag); if (m != MATCH_NO) return m; diff --git a/gcc/fortran/trans-const.cc b/gcc/fortran/trans-const.cc index fc5b6d030578..204f4df301c0 100644 --- a/gcc/fortran/trans-const.cc +++ b/gcc/fortran/trans-const.cc @@ -206,6 +206,14 @@ gfc_conv_mpz_to_tree (mpz_t i, int kind) return wide_int_to_tree (gfc_get_int_type (kind), val); } +/* Same, but for unsigned. */ + +tree +gfc_conv_mpz_unsigned_to_tree (mpz_t i, int kind) +{ + wide_int val = wi:: from_mpz (gfc_get_unsigned_type (kind), i, true); + return wide_int_to_tree (gfc_get_unsigned_type (kind), val); +} /* Convert a GMP integer into a tree node of type given by the type argument. */ @@ -315,6 +323,9 @@ gfc_conv_constant_to_tree (gfc_expr * expr) else return gfc_conv_mpz_to_tree (expr->value.integer, expr->ts.kind); + case BT_UNSIGNED: + return gfc_conv_mpz_unsigned_to_tree (expr->value.integer, expr->ts.kind); + case BT_REAL: if (expr->representation.string) return fold_build1_loc (input_location, VIEW_CONVERT_EXPR, diff --git a/gcc/fortran/trans-types.cc b/gcc/fortran/trans-types.cc index 59d72136a0de..a00dc80bf596 100644 --- a/gcc/fortran/trans-types.cc +++ b/gcc/fortran/trans-types.cc @@ -86,8 +86,10 @@ static GTY(()) tree gfc_cfi_descriptor_base[2 * (CFI_MAX_RANK + 2)]; #define MAX_INT_KINDS 5 gfc_integer_info gfc_integer_kinds[MAX_INT_KINDS + 1]; gfc_logical_info gfc_logical_kinds[MAX_INT_KINDS + 1]; +gfc_unsigned_info gfc_unsigned_kinds[MAX_INT_KINDS + 1]; static GTY(()) tree gfc_integer_types[MAX_INT_KINDS + 1]; static GTY(()) tree gfc_logical_types[MAX_INT_KINDS + 1]; +static GTY(()) tree gfc_unsigned_types[MAX_INT_KINDS + 1]; #define MAX_REAL_KINDS 5 gfc_real_info gfc_real_kinds[MAX_REAL_KINDS + 1]; @@ -109,6 +111,7 @@ int gfc_index_integer_kind; /* The default kinds of the various types. */ int gfc_default_integer_kind; +int gfc_default_unsigned_kind; int gfc_max_integer_kind; int gfc_default_real_kind; int gfc_default_double_kind; @@ -413,6 +416,14 @@ gfc_init_kinds (void) gfc_integer_kinds[i_index].digits = bitsize - 1; gfc_integer_kinds[i_index].bit_size = bitsize; + if (flag_unsigned) + { + gfc_unsigned_kinds[i_index].kind = kind; + gfc_unsigned_kinds[i_index].radix = 2; + gfc_unsigned_kinds[i_index].digits = bitsize; + gfc_unsigned_kinds[i_index].bit_size = bitsize; + } + gfc_logical_kinds[i_index].kind = kind; gfc_logical_kinds[i_index].bit_size = bitsize; @@ -585,6 +596,8 @@ gfc_init_kinds (void) gfc_numeric_storage_size = gfc_integer_kinds[i_index - 1].bit_size; } + gfc_default_unsigned_kind = gfc_default_integer_kind; + /* Choose the default real kind. Again, we choose 4 when possible. */ if (flag_default_real_8) { @@ -756,6 +769,18 @@ validate_integer (int kind) return -1; } +static int +validate_unsigned (int kind) +{ + int i; + + for (i = 0; gfc_unsigned_kinds[i].kind != 0; i++) + if (gfc_unsigned_kinds[i].kind == kind) + return i; + + return -1; +} + static int validate_real (int kind) { @@ -810,6 +835,9 @@ gfc_validate_kind (bt type, int kind, bool may_fail) case BT_INTEGER: rc = validate_integer (kind); break; + case BT_UNSIGNED: + rc = validate_unsigned (kind); + break; case BT_LOGICAL: rc = validate_logical (kind); break; @@ -880,6 +908,24 @@ gfc_build_uint_type (int size) return make_unsigned_type (size); } +static tree +gfc_build_unsigned_type (gfc_unsigned_info *info) +{ + int mode_precision = info->bit_size; + + if (mode_precision == CHAR_TYPE_SIZE) + info->c_unsigned_char = 1; + if (mode_precision == SHORT_TYPE_SIZE) + info->c_unsigned_short = 1; + if (mode_precision == INT_TYPE_SIZE) + info->c_unsigned_int = 1; + if (mode_precision == LONG_TYPE_SIZE) + info->c_unsigned_long = 1; + if (mode_precision == LONG_LONG_TYPE_SIZE) + info->c_unsigned_long_long = 1; + + return gfc_build_uint_type (mode_precision); +} static tree gfc_build_real_type (gfc_real_info *info) @@ -992,6 +1038,18 @@ gfc_init_types (void) PUSH_TYPE (name_buf, type); } + if (flag_unsigned) + { + for (index = 0; gfc_unsigned_kinds[index].kind != 0;++index) + { + type = gfc_build_unsigned_type (&gfc_unsigned_kinds[index]); + gfc_unsigned_types[index] = type; + snprintf (name_buf, sizeof(name_buf), "unsigned(kind=%d", + gfc_integer_kinds[index].kind); + PUSH_TYPE (name_buf, type); + } + } + for (index = 0; gfc_logical_kinds[index].kind != 0; ++index) { type = gfc_build_logical_type (&gfc_logical_kinds[index]); @@ -1092,6 +1150,13 @@ gfc_get_int_type (int kind) return index < 0 ? 0 : gfc_integer_types[index]; } +tree +gfc_get_unsigned_type (int kind) +{ + int index = gfc_validate_kind (BT_INTEGER, kind, true); + return index < 0 ? 0 : gfc_integer_types[index]; +} + tree gfc_get_real_type (int kind) { @@ -1192,6 +1257,10 @@ gfc_typenode_for_spec (gfc_typespec * spec, int codim) basetype = gfc_get_int_type (spec->kind); break; + case BT_UNSIGNED: + basetype = gfc_get_unsigned_type (spec->kind); + break; + case BT_REAL: basetype = gfc_get_real_type (spec->kind); break; diff --git a/gcc/fortran/trans-types.h b/gcc/fortran/trans-types.h index 60096facde81..afc4da995265 100644 --- a/gcc/fortran/trans-types.h +++ b/gcc/fortran/trans-types.h @@ -76,6 +76,7 @@ void gfc_init_c_interop_kinds (void); tree get_dtype_type_node (void); tree gfc_get_int_type (int); +tree gfc_get_unsigned_type (int); tree gfc_get_real_type (int); tree gfc_get_complex_type (int); tree gfc_get_logical_type (int); diff --git a/gcc/testsuite/gfortran.dg/unsigned_1.f90 b/gcc/testsuite/gfortran.dg/unsigned_1.f90 new file mode 100644 index 000000000000..e8caadca9d98 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/unsigned_1.f90 @@ -0,0 +1,8 @@ +! { dg-do compile } +! { dg-options "-funsigned" } +! A first, very simple program, that should compile. +program memain + unsigned :: u + u = 1U + u = 2u +end program memain