| /* m2type.cc provides an interface to GCC type trees. |
| |
| Copyright (C) 2012-2025 Free Software Foundation, Inc. |
| Contributed by Gaius Mulley <gaius@glam.ac.uk>. |
| |
| This file is part of GNU Modula-2. |
| |
| GNU Modula-2 is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| GNU Modula-2 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 GNU Modula-2; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "gcc-consolidation.h" |
| |
| #include "../gm2-lang.h" |
| #include "../m2-tree.h" |
| |
| #define m2type_c |
| #include "m2assert.h" |
| #include "m2block.h" |
| #include "m2builtins.h" |
| #include "m2convert.h" |
| #include "m2decl.h" |
| #include "m2except.h" |
| #include "m2expr.h" |
| #include "m2linemap.h" |
| #include "m2tree.h" |
| #include "m2treelib.h" |
| #include "m2type.h" |
| #include "m2options.h" |
| #include "m2configure.h" |
| |
| #define USE_BOOLEAN |
| static int broken_set_debugging_info = true; |
| |
| |
| struct GTY (()) struct_constructor |
| { |
| /* Constructor_type, the type that we are constructing. */ |
| tree GTY ((skip (""))) constructor_type; |
| /* Constructor_fields, the list of fields belonging to |
| constructor_type. Used by SET and RECORD constructors. */ |
| tree GTY ((skip (""))) constructor_fields; |
| /* Constructor_element_list, the list of constants used by SET and |
| RECORD constructors. */ |
| tree GTY ((skip (""))) constructor_element_list; |
| /* Constructor_elements, used by an ARRAY initializer all elements |
| are held in reverse order. */ |
| vec<constructor_elt, va_gc> *constructor_elements; |
| /* Level, the next level down in the constructor stack. */ |
| struct struct_constructor *level; |
| }; |
| |
| static GTY (()) struct struct_constructor *top_constructor = NULL; |
| |
| typedef struct GTY (()) array_desc |
| { |
| int type; |
| tree index; |
| tree array; |
| struct array_desc *next; |
| } array_desc; |
| |
| static GTY (()) array_desc *list_of_arrays = NULL; |
| /* Used in BuildStartFunctionType. */ |
| static GTY (()) tree param_type_list; |
| |
| static GTY (()) tree proc_type_node; |
| static GTY (()) tree bitset_type_node; |
| static GTY (()) tree bitnum_type_node; |
| static GTY (()) tree m2_char_type_node; |
| static GTY (()) tree m2_integer_type_node; |
| static GTY (()) tree m2_cardinal_type_node; |
| static GTY (()) tree m2_short_real_type_node; |
| static GTY (()) tree m2_real_type_node; |
| static GTY (()) tree m2_long_real_type_node; |
| static GTY (()) tree m2_long_int_type_node; |
| static GTY (()) tree m2_long_card_type_node; |
| static GTY (()) tree m2_short_int_type_node; |
| static GTY (()) tree m2_short_card_type_node; |
| static GTY (()) tree m2_z_type_node; |
| static GTY (()) tree m2_iso_loc_type_node; |
| static GTY (()) tree m2_iso_byte_type_node; |
| static GTY (()) tree m2_iso_word_type_node; |
| static GTY (()) tree m2_integer8_type_node; |
| static GTY (()) tree m2_integer16_type_node; |
| static GTY (()) tree m2_integer32_type_node; |
| static GTY (()) tree m2_integer64_type_node; |
| static GTY (()) tree m2_cardinal8_type_node; |
| static GTY (()) tree m2_cardinal16_type_node; |
| static GTY (()) tree m2_cardinal32_type_node; |
| static GTY (()) tree m2_cardinal64_type_node; |
| static GTY (()) tree m2_word16_type_node; |
| static GTY (()) tree m2_word32_type_node; |
| static GTY (()) tree m2_word64_type_node; |
| static GTY (()) tree m2_bitset8_type_node; |
| static GTY (()) tree m2_bitset16_type_node; |
| static GTY (()) tree m2_bitset32_type_node; |
| static GTY (()) tree m2_real32_type_node; |
| static GTY (()) tree m2_real64_type_node; |
| static GTY (()) tree m2_real96_type_node; |
| static GTY (()) tree m2_real128_type_node; |
| static GTY (()) tree m2_complex_type_node; |
| static GTY (()) tree m2_long_complex_type_node; |
| static GTY (()) tree m2_short_complex_type_node; |
| static GTY (()) tree m2_c_type_node; |
| static GTY (()) tree m2_complex32_type_node; |
| static GTY (()) tree m2_complex64_type_node; |
| static GTY (()) tree m2_complex96_type_node; |
| static GTY (()) tree m2_complex128_type_node; |
| static GTY (()) tree m2_packed_boolean_type_node; |
| static GTY (()) tree m2_cardinal_address_type_node; |
| static GTY (()) tree m2_offt_type_node; |
| |
| /* gm2_canonicalize_array - returns a unique array node based on |
| index_type and type. */ |
| |
| static tree |
| gm2_canonicalize_array (tree index_type, int type) |
| { |
| array_desc *l = list_of_arrays; |
| |
| while (l != NULL) |
| { |
| if (l->type == type && l->index == index_type) |
| return l->array; |
| else |
| l = l->next; |
| } |
| l = ggc_alloc<array_desc> (); |
| l->next = list_of_arrays; |
| l->type = type; |
| l->index = index_type; |
| l->array = make_node (ARRAY_TYPE); |
| TREE_TYPE (l->array) = NULL_TREE; |
| TYPE_DOMAIN (l->array) = index_type; |
| list_of_arrays = l; |
| return l->array; |
| } |
| |
| /* BuildStartArrayType - creates an array with an indextype and |
| elttype. The front end symbol type is also passed to allow the |
| gccgm2 to return the canonical edition of the array type even if |
| the GCC elttype is NULL_TREE. */ |
| |
| tree |
| m2type_BuildStartArrayType (tree index_type, tree elt_type, int type) |
| { |
| tree t; |
| |
| elt_type = m2tree_skip_type_decl (elt_type); |
| ASSERT_CONDITION (index_type != NULL_TREE); |
| if (elt_type == NULL_TREE) |
| { |
| /* Cannot use GCC canonicalization routines yet, so we use our front |
| end version based on the front end type. */ |
| return gm2_canonicalize_array (index_type, type); |
| } |
| t = gm2_canonicalize_array (index_type, type); |
| if (TREE_TYPE (t) == NULL_TREE) |
| TREE_TYPE (t) = elt_type; |
| else |
| ASSERT_CONDITION (TREE_TYPE (t) == elt_type); |
| |
| return t; |
| } |
| |
| /* PutArrayType assignes TREE_TYPE (array) to the skipped type. */ |
| |
| void |
| m2type_PutArrayType (tree array, tree type) |
| { |
| TREE_TYPE (array) = m2tree_skip_type_decl (type); |
| } |
| |
| /* gccgm2_GetArrayNoOfElements returns the number of elements in |
| arraytype. */ |
| |
| tree |
| m2type_GetArrayNoOfElements (location_t location, tree arraytype) |
| { |
| tree index_type = TYPE_DOMAIN (m2tree_skip_type_decl (arraytype)); |
| tree min = TYPE_MIN_VALUE (index_type); |
| tree max = TYPE_MAX_VALUE (index_type); |
| |
| m2assert_AssertLocation (location); |
| return m2expr_FoldAndStrip (m2expr_BuildSub (location, max, min, false)); |
| } |
| |
| /* gm2_finish_build_array_type complete building the partially |
| created array type, arrayType. The arrayType is now known to be |
| declared as: ARRAY index_type OF elt_type. There will only ever |
| be one gcc tree type for this array definition. The third |
| parameter type is a front end type and this is necessary so that |
| the canonicalization creates unique array types for each type. */ |
| |
| static tree |
| gm2_finish_build_array_type (tree arrayType, tree elt_type, tree index_type, |
| int type) |
| { |
| tree old = arrayType; |
| |
| elt_type = m2tree_skip_type_decl (elt_type); |
| ASSERT_CONDITION (index_type != NULL_TREE); |
| if (TREE_CODE (elt_type) == FUNCTION_TYPE) |
| { |
| error ("arrays of functions are not meaningful"); |
| elt_type = integer_type_node; |
| } |
| |
| TREE_TYPE (arrayType) = elt_type; |
| TYPE_DOMAIN (arrayType) = index_type; |
| |
| arrayType = gm2_canonicalize_array (index_type, type); |
| if (arrayType != old) |
| internal_error ("array declaration canonicalization has failed"); |
| |
| if (!COMPLETE_TYPE_P (arrayType)) |
| layout_type (arrayType); |
| return arrayType; |
| } |
| |
| /* BuildEndArrayType returns a type which is an array indexed by |
| IndexType and which has ElementType elements. */ |
| |
| tree |
| m2type_BuildEndArrayType (tree arraytype, tree elementtype, tree indextype, |
| int type) |
| { |
| elementtype = m2tree_skip_type_decl (elementtype); |
| ASSERT (indextype == TYPE_DOMAIN (arraytype), indextype); |
| |
| if (TREE_CODE (elementtype) == FUNCTION_TYPE) |
| return gm2_finish_build_array_type (arraytype, ptr_type_node, indextype, |
| type); |
| else |
| return gm2_finish_build_array_type ( |
| arraytype, m2tree_skip_type_decl (elementtype), indextype, type); |
| } |
| |
| /* gm2_build_array_type returns a type which is an array indexed by |
| IndexType and which has ElementType elements. */ |
| |
| static tree |
| gm2_build_array_type (tree elementtype, tree indextype, int fetype) |
| { |
| tree arrayType = m2type_BuildStartArrayType (indextype, elementtype, fetype); |
| return m2type_BuildEndArrayType (arrayType, elementtype, indextype, fetype); |
| } |
| |
| /* ValueInTypeRange returns true if the constant, value, lies within |
| the range of type. */ |
| |
| bool |
| m2type_ValueInTypeRange (tree type, tree value) |
| { |
| tree low_type = m2tree_skip_type_decl (type); |
| tree min_value = TYPE_MIN_VALUE (low_type); |
| tree max_value = TYPE_MAX_VALUE (low_type); |
| |
| value = m2expr_FoldAndStrip (value); |
| return ((tree_int_cst_compare (min_value, value) <= 0) |
| && (tree_int_cst_compare (value, max_value) <= 0)); |
| } |
| |
| /* ValueOutOfTypeRange returns true if the constant, value, exceeds |
| the range of type. */ |
| |
| bool |
| m2type_ValueOutOfTypeRange (tree type, tree value) |
| { |
| return (!m2type_ValueInTypeRange (type, value)); |
| } |
| |
| /* ExceedsTypeRange return true if low or high exceed the range of |
| type. */ |
| |
| bool |
| m2type_ExceedsTypeRange (tree type, tree low, tree high) |
| { |
| return (m2type_ValueOutOfTypeRange (type, low) |
| || m2type_ValueOutOfTypeRange (type, high)); |
| } |
| |
| /* WithinTypeRange return true if low and high are within the range |
| of type. */ |
| |
| bool |
| m2type_WithinTypeRange (tree type, tree low, tree high) |
| { |
| return (m2type_ValueInTypeRange (type, low) |
| && m2type_ValueInTypeRange (type, high)); |
| } |
| |
| /* BuildArrayIndexType creates an integer index which accesses an |
| array. low and high are the min, max elements of the array. GCC |
| insists we access an array with an integer indice. */ |
| |
| tree |
| m2type_BuildArrayIndexType (tree low, tree high) |
| { |
| tree sizelow = convert (m2type_GetIntegerType (), m2expr_FoldAndStrip (low)); |
| tree sizehigh |
| = convert (m2type_GetIntegerType (), m2expr_FoldAndStrip (high)); |
| |
| if (m2expr_TreeOverflow (sizelow)) |
| error ("low bound for the array is outside the ztype limits"); |
| if (m2expr_TreeOverflow (sizehigh)) |
| error ("high bound for the array is outside the ztype limits"); |
| |
| return build_range_type (m2type_GetIntegerType (), |
| m2expr_FoldAndStrip (sizelow), |
| m2expr_FoldAndStrip (sizehigh)); |
| } |
| |
| /* build_m2_type_node_by_array builds a ISO Modula-2 word type from |
| ARRAY [low..high] OF arrayType. This matches the front end data |
| type fetype which is only used during canonicalization. */ |
| |
| static tree |
| build_m2_type_node_by_array (tree arrayType, tree low, tree high, int fetype) |
| { |
| return gm2_build_array_type (arrayType, |
| m2type_BuildArrayIndexType (low, high), fetype); |
| } |
| |
| /* build_m2_word16_type_node build an ISO 16 bit word as an ARRAY |
| [0..1] OF loc. */ |
| |
| static tree |
| build_m2_word16_type_node (location_t location, int loc) |
| { |
| return build_m2_type_node_by_array (m2type_GetISOLocType (), |
| m2expr_GetIntegerZero (location), |
| m2expr_GetIntegerOne (location), loc); |
| } |
| |
| /* build_m2_word32_type_node build an ISO 32 bit word as an ARRAY |
| [0..3] OF loc. */ |
| |
| static tree |
| build_m2_word32_type_node (location_t location, int loc) |
| { |
| return build_m2_type_node_by_array (m2type_GetISOLocType (), |
| m2expr_GetIntegerZero (location), |
| m2decl_BuildIntegerConstant (3), loc); |
| } |
| |
| /* build_m2_word64_type_node build an ISO 32 bit word as an ARRAY |
| [0..7] OF loc. */ |
| |
| static tree |
| build_m2_word64_type_node (location_t location, int loc) |
| { |
| return build_m2_type_node_by_array (m2type_GetISOLocType (), |
| m2expr_GetIntegerZero (location), |
| m2decl_BuildIntegerConstant (7), loc); |
| } |
| |
| |
| /* GetM2Complex32 return the fixed size complex type. */ |
| |
| tree |
| m2type_GetM2Complex32 (void) |
| { |
| return m2_complex32_type_node; |
| } |
| |
| /* GetM2Complex64 return the fixed size complex type. */ |
| |
| tree |
| m2type_GetM2Complex64 (void) |
| { |
| return m2_complex64_type_node; |
| } |
| |
| /* GetM2Complex96 return the fixed size complex type. */ |
| |
| tree |
| m2type_GetM2Complex96 (void) |
| { |
| return m2_complex96_type_node; |
| } |
| |
| /* GetM2Complex128 return the fixed size complex type. */ |
| |
| tree |
| m2type_GetM2Complex128 (void) |
| { |
| return m2_complex128_type_node; |
| } |
| |
| /* GetM2CType a test function. */ |
| |
| tree |
| m2type_GetM2CType (void) |
| { |
| return m2_c_type_node; |
| } |
| |
| /* GetM2ShortComplexType return the short complex type. */ |
| |
| tree |
| m2type_GetM2ShortComplexType (void) |
| { |
| return m2_short_complex_type_node; |
| } |
| |
| /* GetM2LongComplexType return the long complex type. */ |
| |
| tree |
| m2type_GetM2LongComplexType (void) |
| { |
| return m2_long_complex_type_node; |
| } |
| |
| /* GetM2ComplexType return the complex type. */ |
| |
| tree |
| m2type_GetM2ComplexType (void) |
| { |
| return m2_complex_type_node; |
| } |
| |
| /* GetM2Real128 return the real 128 bit type. */ |
| |
| tree |
| m2type_GetM2Real128 (void) |
| { |
| return m2_real128_type_node; |
| } |
| |
| /* GetM2Real96 return the real 96 bit type. */ |
| |
| tree |
| m2type_GetM2Real96 (void) |
| { |
| return m2_real96_type_node; |
| } |
| |
| /* GetM2Real64 return the real 64 bit type. */ |
| |
| tree |
| m2type_GetM2Real64 (void) |
| { |
| return m2_real64_type_node; |
| } |
| |
| /* GetM2Real32 return the real 32 bit type. */ |
| |
| tree |
| m2type_GetM2Real32 (void) |
| { |
| return m2_real32_type_node; |
| } |
| |
| /* GetM2Bitset32 return the bitset 32 bit type. */ |
| |
| tree |
| m2type_GetM2Bitset32 (void) |
| { |
| return m2_bitset32_type_node; |
| } |
| |
| /* GetM2Bitset16 return the bitset 16 bit type. */ |
| |
| tree |
| m2type_GetM2Bitset16 (void) |
| { |
| return m2_bitset16_type_node; |
| } |
| |
| /* GetM2Bitset8 return the bitset 8 bit type. */ |
| |
| tree |
| m2type_GetM2Bitset8 (void) |
| { |
| return m2_bitset8_type_node; |
| } |
| |
| /* GetM2Word64 return the word 64 bit type. */ |
| |
| tree |
| m2type_GetM2Word64 (void) |
| { |
| return m2_word64_type_node; |
| } |
| |
| /* GetM2Word32 return the word 32 bit type. */ |
| |
| tree |
| m2type_GetM2Word32 (void) |
| { |
| return m2_word32_type_node; |
| } |
| |
| /* GetM2Word16 return the word 16 bit type. */ |
| |
| tree |
| m2type_GetM2Word16 (void) |
| { |
| return m2_word16_type_node; |
| } |
| |
| /* GetM2Cardinal64 return the cardinal 64 bit type. */ |
| |
| tree |
| m2type_GetM2Cardinal64 (void) |
| { |
| return m2_cardinal64_type_node; |
| } |
| |
| /* GetM2Cardinal32 return the cardinal 32 bit type. */ |
| |
| tree |
| m2type_GetM2Cardinal32 (void) |
| { |
| return m2_cardinal32_type_node; |
| } |
| |
| /* GetM2Cardinal16 return the cardinal 16 bit type. */ |
| |
| tree |
| m2type_GetM2Cardinal16 (void) |
| { |
| return m2_cardinal16_type_node; |
| } |
| |
| /* GetM2Cardinal8 return the cardinal 8 bit type. */ |
| |
| tree |
| m2type_GetM2Cardinal8 (void) |
| { |
| return m2_cardinal8_type_node; |
| } |
| |
| /* GetM2Integer64 return the integer 64 bit type. */ |
| |
| tree |
| m2type_GetM2Integer64 (void) |
| { |
| return m2_integer64_type_node; |
| } |
| |
| /* GetM2Integer32 return the integer 32 bit type. */ |
| |
| tree |
| m2type_GetM2Integer32 (void) |
| { |
| return m2_integer32_type_node; |
| } |
| |
| /* GetM2Integer16 return the integer 16 bit type. */ |
| |
| tree |
| m2type_GetM2Integer16 (void) |
| { |
| return m2_integer16_type_node; |
| } |
| |
| /* GetM2Integer8 return the integer 8 bit type. */ |
| |
| tree |
| m2type_GetM2Integer8 (void) |
| { |
| return m2_integer8_type_node; |
| } |
| |
| /* GetM2RType return the ISO R data type, the longest real |
| datatype. */ |
| |
| tree |
| m2type_GetM2RType (void) |
| { |
| return long_double_type_node; |
| } |
| |
| /* GetM2ZType return the ISO Z data type, the longest int datatype. */ |
| |
| tree |
| m2type_GetM2ZType (void) |
| { |
| return m2_z_type_node; |
| } |
| |
| /* GetShortCardType return the C short unsigned data type. */ |
| |
| tree |
| m2type_GetShortCardType (void) |
| { |
| return short_unsigned_type_node; |
| } |
| |
| /* GetM2ShortCardType return the m2 short cardinal data type. */ |
| |
| tree |
| m2type_GetM2ShortCardType (void) |
| { |
| return m2_short_card_type_node; |
| } |
| |
| /* GetShortIntType return the C short int data type. */ |
| |
| tree |
| m2type_GetShortIntType (void) |
| { |
| return short_integer_type_node; |
| } |
| |
| /* GetM2ShortIntType return the m2 short integer data type. */ |
| |
| tree |
| m2type_GetM2ShortIntType (void) |
| { |
| return m2_short_int_type_node; |
| } |
| |
| /* GetM2LongCardType return the m2 long cardinal data type. */ |
| |
| tree |
| m2type_GetM2LongCardType (void) |
| { |
| return m2_long_card_type_node; |
| } |
| |
| /* GetM2LongIntType return the m2 long integer data type. */ |
| |
| tree |
| m2type_GetM2LongIntType (void) |
| { |
| return m2_long_int_type_node; |
| } |
| |
| /* GetM2LongRealType return the m2 long real data type. */ |
| |
| tree |
| m2type_GetM2LongRealType (void) |
| { |
| return m2_long_real_type_node; |
| } |
| |
| /* GetM2RealType return the m2 real data type. */ |
| |
| tree |
| m2type_GetM2RealType (void) |
| { |
| return m2_real_type_node; |
| } |
| |
| /* GetM2ShortRealType return the m2 short real data type. */ |
| |
| tree |
| m2type_GetM2ShortRealType (void) |
| { |
| return m2_short_real_type_node; |
| } |
| |
| /* GetM2CardinalType return the m2 cardinal data type. */ |
| |
| tree |
| m2type_GetM2CardinalType (void) |
| { |
| return m2_cardinal_type_node; |
| } |
| |
| /* GetM2IntegerType return the m2 integer data type. */ |
| |
| tree |
| m2type_GetM2IntegerType (void) |
| { |
| return m2_integer_type_node; |
| } |
| |
| /* GetM2CharType return the m2 char data type. */ |
| |
| tree |
| m2type_GetM2CharType (void) |
| { |
| return m2_char_type_node; |
| } |
| |
| /* GetProcType return the m2 proc data type. */ |
| |
| tree |
| m2type_GetProcType (void) |
| { |
| return proc_type_node; |
| } |
| |
| /* GetISOWordType return the m2 iso word data type. */ |
| |
| tree |
| m2type_GetISOWordType (void) |
| { |
| return m2_iso_word_type_node; |
| } |
| |
| /* GetISOByteType return the m2 iso byte data type. */ |
| |
| tree |
| m2type_GetISOByteType (void) |
| { |
| return m2_iso_byte_type_node; |
| } |
| |
| /* GetISOLocType return the m2 loc word data type. */ |
| |
| tree |
| m2type_GetISOLocType (void) |
| { |
| return m2_iso_loc_type_node; |
| } |
| |
| /* GetWordType return the C unsigned data type. */ |
| |
| tree |
| m2type_GetWordType (void) |
| { |
| return unsigned_type_node; |
| } |
| |
| /* GetLongIntType return the C long int data type. */ |
| |
| tree |
| m2type_GetLongIntType (void) |
| { |
| return long_integer_type_node; |
| } |
| |
| /* GetShortRealType return the C float data type. */ |
| |
| tree |
| m2type_GetShortRealType (void) |
| { |
| return float_type_node; |
| } |
| |
| /* GetLongRealType return the C long double data type. */ |
| |
| tree |
| m2type_GetLongRealType (void) |
| { |
| return long_double_type_node; |
| } |
| |
| /* GetRealType returns the C double_type_node. */ |
| |
| tree |
| m2type_GetRealType (void) |
| { |
| return double_type_node; |
| } |
| |
| /* GetBitnumType return the ISO bitnum type. */ |
| |
| tree |
| m2type_GetBitnumType (void) |
| { |
| return bitnum_type_node; |
| } |
| |
| /* GetBitsetType return the bitset type. */ |
| |
| tree |
| m2type_GetBitsetType (void) |
| { |
| return bitset_type_node; |
| } |
| |
| /* GetCardinalType return the cardinal type. */ |
| |
| tree |
| m2type_GetCardinalType (void) |
| { |
| return unsigned_type_node; |
| } |
| |
| /* GetPointerType return the GCC ptr type node. Equivalent to |
| (void *). */ |
| |
| tree |
| m2type_GetPointerType (void) |
| { |
| return ptr_type_node; |
| } |
| |
| /* GetVoidType return the C void type. */ |
| |
| tree |
| m2type_GetVoidType (void) |
| { |
| return void_type_node; |
| } |
| |
| /* GetByteType return the byte type node. */ |
| |
| tree |
| m2type_GetByteType (void) |
| { |
| return unsigned_char_type_node; |
| } |
| |
| /* GetCharType return the char type node. */ |
| |
| tree |
| m2type_GetCharType (void) |
| { |
| return char_type_node; |
| } |
| |
| /* GetIntegerType return the integer type node. */ |
| |
| tree |
| m2type_GetIntegerType (void) |
| { |
| return integer_type_node; |
| } |
| |
| /* GetCSizeTType return a type representing size_t. */ |
| |
| tree |
| m2type_GetCSizeTType (void) |
| { |
| return sizetype; |
| } |
| |
| /* GetCSSizeTType return a type representing size_t. */ |
| |
| tree |
| m2type_GetCSSizeTType (void) |
| { |
| return ssizetype; |
| } |
| |
| /* GetCSSizeTType return a type representing off_t. */ |
| |
| tree |
| m2type_GetCOffTType (void) |
| { |
| return m2_offt_type_node; |
| } |
| |
| /* GetPackedBooleanType return the packed boolean data type node. */ |
| |
| tree |
| m2type_GetPackedBooleanType (void) |
| { |
| return m2_packed_boolean_type_node; |
| } |
| |
| /* GetBooleanTrue return modula-2 true. */ |
| |
| tree |
| m2type_GetBooleanTrue (void) |
| { |
| #if defined(USE_BOOLEAN) |
| return boolean_true_node; |
| #else /* !USE_BOOLEAN */ |
| return m2expr_GetIntegerOne (m2linemap_BuiltinsLocation ()); |
| #endif /* !USE_BOOLEAN */ |
| } |
| |
| /* GetBooleanFalse return modula-2 FALSE. */ |
| |
| tree |
| m2type_GetBooleanFalse (void) |
| { |
| #if defined(USE_BOOLEAN) |
| return boolean_false_node; |
| #else /* !USE_BOOLEAN */ |
| return m2expr_GetIntegerZero (m2linemap_BuiltinsLocation ()); |
| #endif /* !USE_BOOLEAN */ |
| } |
| |
| /* GetBooleanType return the modula-2 BOOLEAN type. */ |
| |
| tree |
| m2type_GetBooleanType (void) |
| { |
| #if defined(USE_BOOLEAN) |
| return boolean_type_node; |
| #else /* !USE_BOOLEAN */ |
| return integer_type_node; |
| #endif /* !USE_BOOLEAN */ |
| } |
| |
| /* GetCardinalAddressType returns the internal data type for |
| computing binary arithmetic upon the ADDRESS datatype. */ |
| |
| tree |
| m2type_GetCardinalAddressType (void) |
| { |
| return m2_cardinal_address_type_node; |
| } |
| |
| #if 0 |
| /* build_set_type creates a set type from the, domain, [low..high]. |
| The values low..high all have type, range_type. */ |
| |
| static tree |
| build_set_type (tree domain, tree range_type, int allow_void, int ispacked) |
| { |
| tree type; |
| |
| if (!m2tree_IsOrdinal (domain) |
| && !(allow_void && TREE_CODE (domain) == VOID_TYPE)) |
| { |
| error ("set base type must be an ordinal type"); |
| return NULL; |
| } |
| |
| if (TYPE_SIZE (range_type) == 0) |
| layout_type (range_type); |
| |
| if (TYPE_SIZE (domain) == 0) |
| layout_type (domain); |
| |
| type = make_node (SET_TYPE); |
| TREE_TYPE (type) = range_type; |
| TYPE_DOMAIN (type) = domain; |
| TYPE_PACKED (type) = ispacked; |
| return type; |
| } |
| |
| |
| /* convert_type_to_range does the conversion and copies the range |
| type */ |
| |
| static tree |
| convert_type_to_range (tree type) |
| { |
| tree min, max; |
| tree itype; |
| |
| if (!m2tree_IsOrdinal (type)) |
| { |
| error ("ordinal type expected"); |
| return error_mark_node; |
| } |
| |
| min = TYPE_MIN_VALUE (type); |
| max = TYPE_MAX_VALUE (type); |
| |
| if (TREE_TYPE (min) != TREE_TYPE (max)) |
| { |
| error ("range limits are not of the same type"); |
| return error_mark_node; |
| } |
| |
| itype = build_range_type (TREE_TYPE (min), min, max); |
| |
| if (TREE_TYPE (type) == NULL_TREE) |
| { |
| layout_type (type); |
| TREE_TYPE (itype) = type; |
| } |
| else |
| { |
| layout_type (TREE_TYPE (type)); |
| TREE_TYPE (itype) = TREE_TYPE (type); |
| } |
| |
| layout_type (itype); |
| return itype; |
| } |
| #endif |
| |
| /* build_bitset_type builds the type BITSET which is exported from |
| SYSTEM. It also builds BITNUM (the subrange from which BITSET is |
| created). */ |
| |
| static tree |
| build_bitset_type (location_t location) |
| { |
| m2assert_AssertLocation (location); |
| bitnum_type_node = build_range_type ( |
| m2tree_skip_type_decl (m2type_GetCardinalType ()), |
| m2decl_BuildIntegerConstant (0), |
| m2decl_BuildIntegerConstant (m2decl_GetBitsPerBitset () - 1)); |
| layout_type (bitnum_type_node); |
| |
| #if 1 |
| if (broken_set_debugging_info) |
| return unsigned_type_node; |
| #endif |
| |
| ASSERT ((COMPLETE_TYPE_P (bitnum_type_node)), bitnum_type_node); |
| |
| return m2type_BuildSetTypeFromSubrange ( |
| location, NULL, bitnum_type_node, m2decl_BuildIntegerConstant (0), |
| m2decl_BuildIntegerConstant (m2decl_GetBitsPerBitset () - 1), false); |
| } |
| |
| /* BuildSetTypeFromSubrange constructs a set type from a |
| subrangeType. --fixme-- revisit once gdb/gcc supports dwarf-5 set type. */ |
| |
| tree |
| m2type_BuildSetTypeFromSubrange (location_t location, |
| char *name __attribute__ ((unused)), |
| tree subrangeType __attribute__ ((unused)), |
| tree lowval, tree highval, bool ispacked) |
| { |
| m2assert_AssertLocation (location); |
| lowval = m2expr_FoldAndStrip (lowval); |
| highval = m2expr_FoldAndStrip (highval); |
| |
| #if 0 |
| if (broken_set_debugging_info) |
| return unsigned_type_node; |
| else |
| #endif |
| if (ispacked) |
| { |
| tree noelements = m2expr_BuildAdd ( |
| location, m2expr_BuildSub (location, highval, lowval, false), |
| integer_one_node, false); |
| highval = m2expr_FoldAndStrip (m2expr_BuildSub ( |
| location, m2expr_BuildLSL (location, m2expr_GetWordOne (location), |
| noelements, false), |
| m2expr_GetIntegerOne (location), false)); |
| lowval = m2expr_GetIntegerZero (location); |
| return m2type_BuildSmallestTypeRange (location, lowval, highval); |
| } |
| else |
| return unsigned_type_node; |
| } |
| |
| /* build_m2_size_set_type build and return a set type with |
| precision bits. */ |
| |
| static tree |
| build_m2_size_set_type (location_t location, int precision) |
| { |
| tree bitnum_type_node |
| = build_range_type (m2tree_skip_type_decl (m2type_GetCardinalType ()), |
| m2decl_BuildIntegerConstant (0), |
| m2decl_BuildIntegerConstant (precision - 1)); |
| layout_type (bitnum_type_node); |
| m2assert_AssertLocation (location); |
| |
| if (broken_set_debugging_info) |
| return unsigned_type_node; |
| |
| ASSERT ((COMPLETE_TYPE_P (bitnum_type_node)), bitnum_type_node); |
| |
| return m2type_BuildSetTypeFromSubrange ( |
| location, NULL, bitnum_type_node, m2decl_BuildIntegerConstant (0), |
| m2decl_BuildIntegerConstant (precision - 1), false); |
| } |
| |
| /* build_m2_specific_size_type build a specific data type matching |
| number of bits precision whether it is_signed. It creates a |
| set type if base == SET_TYPE or returns the already created real, |
| if REAL_TYPE is specified. */ |
| |
| static tree |
| build_m2_specific_size_type (location_t location, enum tree_code base, |
| int precision, int is_signed) |
| { |
| tree c; |
| |
| m2assert_AssertLocation (location); |
| |
| c = make_node (base); |
| TYPE_PRECISION (c) = precision; |
| |
| if (base == REAL_TYPE) |
| { |
| if (!float_mode_for_size (TYPE_PRECISION (c)).exists ()) |
| return NULL; |
| } |
| else if (base == SET_TYPE) |
| return build_m2_size_set_type (location, precision); |
| else |
| { |
| TYPE_SIZE (c) = 0; |
| |
| if (is_signed) |
| { |
| fixup_signed_type (c); |
| TYPE_UNSIGNED (c) = false; |
| } |
| else |
| { |
| fixup_unsigned_type (c); |
| TYPE_UNSIGNED (c) = true; |
| } |
| } |
| layout_type (c); |
| return c; |
| } |
| |
| /* BuildSmallestTypeRange returns the smallest INTEGER_TYPE which |
| is sufficient to contain values: low..high. */ |
| |
| tree |
| m2type_BuildSmallestTypeRange (location_t location, tree low, tree high) |
| { |
| tree bits; |
| |
| m2assert_AssertLocation (location); |
| low = fold (low); |
| high = fold (high); |
| bits = fold (m2expr_calcNbits (location, low, high)); |
| return build_m2_specific_size_type (location, INTEGER_TYPE, |
| TREE_INT_CST_LOW (bits), |
| tree_int_cst_sgn (low) < 0); |
| } |
| |
| /* GetTreeType returns TREE_TYPE (t). */ |
| |
| tree |
| m2type_GetTreeType (tree t) |
| { |
| return TREE_TYPE (t); |
| } |
| |
| /* finish_build_pointer_type finish building a POINTER_TYPE node. |
| necessary to solve self references in procedure types. */ |
| |
| /* Code taken from tree.cc:build_pointer_type_for_mode. */ |
| |
| static tree |
| finish_build_pointer_type (tree t, tree to_type, enum machine_mode mode, |
| bool can_alias_all) |
| { |
| TREE_TYPE (t) = to_type; |
| SET_TYPE_MODE (t, mode); |
| TYPE_REF_CAN_ALIAS_ALL (t) = can_alias_all; |
| TYPE_NEXT_PTR_TO (t) = TYPE_POINTER_TO (to_type); |
| TYPE_POINTER_TO (to_type) = t; |
| |
| /* Lay out the type. */ |
| /* layout_type (t); */ |
| layout_type (t); |
| return t; |
| } |
| |
| /* BuildParameterDeclaration creates and returns one parameter |
| from, name, and, type. It appends this parameter to the internal |
| param_type_list. */ |
| |
| tree |
| m2type_BuildProcTypeParameterDeclaration (location_t location, tree type, |
| bool isreference) |
| { |
| m2assert_AssertLocation (location); |
| ASSERT_BOOL (isreference); |
| type = m2tree_skip_type_decl (type); |
| if (isreference) |
| type = build_reference_type (type); |
| |
| param_type_list = tree_cons (NULL_TREE, type, param_type_list); |
| return type; |
| } |
| |
| /* BuildEndFunctionType build a function type which would return a, |
| value. The arguments have been created by |
| BuildParameterDeclaration. */ |
| |
| tree |
| m2type_BuildEndFunctionType (tree func, tree return_type, bool uses_varargs) |
| { |
| tree last; |
| |
| if (return_type == NULL_TREE) |
| return_type = void_type_node; |
| else |
| return_type = m2tree_skip_type_decl (return_type); |
| |
| if (uses_varargs) |
| { |
| if (param_type_list != NULL_TREE) |
| { |
| param_type_list = nreverse (param_type_list); |
| last = param_type_list; |
| param_type_list = nreverse (param_type_list); |
| gcc_assert (last != void_list_node); |
| } |
| } |
| else if (param_type_list == NULL_TREE) |
| param_type_list = void_list_node; |
| else |
| { |
| param_type_list = nreverse (param_type_list); |
| last = param_type_list; |
| param_type_list = nreverse (param_type_list); |
| TREE_CHAIN (last) = void_list_node; |
| } |
| param_type_list = build_function_type (return_type, param_type_list); |
| |
| func = finish_build_pointer_type (func, param_type_list, ptr_mode, false); |
| TYPE_SIZE (func) = 0; |
| layout_type (func); |
| return func; |
| } |
| |
| /* BuildStartFunctionType creates a pointer type, necessary to |
| create a function type. */ |
| |
| tree |
| m2type_BuildStartFunctionType (location_t location ATTRIBUTE_UNUSED, |
| char *name ATTRIBUTE_UNUSED) |
| { |
| tree n = make_node (POINTER_TYPE); |
| |
| m2assert_AssertLocation (location); |
| return n; |
| } |
| |
| /* InitFunctionTypeParameters resets the current function type |
| parameter list. */ |
| |
| void |
| m2type_InitFunctionTypeParameters (void) |
| { |
| param_type_list = NULL_TREE; |
| } |
| |
| /* gm2_finish_decl finishes VAR, TYPE and FUNCTION declarations. */ |
| |
| static void |
| gm2_finish_decl (location_t location, tree decl) |
| { |
| tree type = TREE_TYPE (decl); |
| int was_incomplete = (DECL_SIZE (decl) == 0); |
| |
| m2assert_AssertLocation (location); |
| if (VAR_P (decl)) |
| { |
| if (DECL_SIZE (decl) == 0 && TREE_TYPE (decl) != error_mark_node |
| && COMPLETE_TYPE_P (TREE_TYPE (decl))) |
| layout_decl (decl, 0); |
| |
| if (DECL_SIZE (decl) == 0 |
| /* Don't give an error if we already gave one earlier. */ |
| && TREE_TYPE (decl) != error_mark_node) |
| { |
| error_at (location, "storage size of %q+D isn%'t known", decl); |
| TREE_TYPE (decl) = error_mark_node; |
| } |
| |
| if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl)) |
| && DECL_SIZE (decl) != 0) |
| { |
| if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST) |
| m2expr_ConstantExpressionWarning (DECL_SIZE (decl)); |
| else |
| error_at (location, "storage size of %q+D isn%'t constant", decl); |
| } |
| |
| if (TREE_USED (type)) |
| TREE_USED (decl) = 1; |
| } |
| |
| /* Output the assembler code and/or RTL code for variables and |
| functions, unless the type is an undefined structure or union. If |
| not, it will get done when the type is completed. */ |
| |
| if (VAR_P (decl) || TREE_CODE (decl) == FUNCTION_DECL) |
| { |
| if (DECL_FILE_SCOPE_P (decl)) |
| { |
| if (DECL_INITIAL (decl) == NULL_TREE |
| || DECL_INITIAL (decl) == error_mark_node) |
| |
| /* Don't output anything when a tentative file-scope definition is |
| seen. But at end of compilation, do output code for them. */ |
| DECL_DEFER_OUTPUT (decl) = 1; |
| rest_of_decl_compilation (decl, true, 0); |
| } |
| |
| if (!DECL_FILE_SCOPE_P (decl)) |
| { |
| |
| /* Recompute the RTL of a local array now if it used to be an |
| incomplete type. */ |
| if (was_incomplete && !TREE_STATIC (decl) && !DECL_EXTERNAL (decl)) |
| { |
| /* If we used it already as memory, it must stay in memory. */ |
| TREE_ADDRESSABLE (decl) = TREE_USED (decl); |
| /* If it's still incomplete now, no init will save it. */ |
| if (DECL_SIZE (decl) == 0) |
| DECL_INITIAL (decl) = 0; |
| } |
| } |
| } |
| |
| if (TREE_CODE (decl) == TYPE_DECL) |
| { |
| if (!DECL_FILE_SCOPE_P (decl) |
| && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)) |
| m2block_pushDecl (build_stmt (location, DECL_EXPR, decl)); |
| |
| rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl), 0); |
| } |
| } |
| |
| /* BuildVariableArrayAndDeclare creates a variable length array. |
| high is the maximum legal elements (which is a runtime variable). |
| This creates and array index, array type and local variable. */ |
| |
| tree |
| m2type_BuildVariableArrayAndDeclare (location_t location, tree elementtype, |
| tree high, char *name, tree scope) |
| { |
| tree indextype = build_index_type (variable_size (high)); |
| tree arraytype = build_array_type (elementtype, indextype); |
| tree id = get_identifier (name); |
| tree decl; |
| |
| m2assert_AssertLocation (location); |
| decl = build_decl (location, VAR_DECL, id, arraytype); |
| |
| DECL_EXTERNAL (decl) = false; |
| TREE_PUBLIC (decl) = true; |
| DECL_CONTEXT (decl) = scope; |
| TREE_USED (arraytype) = true; |
| TREE_USED (decl) = true; |
| |
| m2block_pushDecl (decl); |
| |
| gm2_finish_decl (location, indextype); |
| gm2_finish_decl (location, arraytype); |
| add_stmt (location, build_stmt (location, DECL_EXPR, decl)); |
| return decl; |
| } |
| |
| static tree |
| build_m2_iso_word_node (location_t location, int loc) |
| { |
| tree c; |
| |
| m2assert_AssertLocation (location); |
| /* Define `WORD' as specified in ISO m2 |
| |
| WORD = ARRAY [0..SizeOfWord / SizeOfLoc] OF LOC ; */ |
| |
| if (m2decl_GetBitsPerInt () == BITS_PER_UNIT) |
| c = m2type_GetISOLocType (); |
| else |
| c = gm2_build_array_type ( |
| m2type_GetISOLocType (), |
| m2type_BuildArrayIndexType ( |
| m2expr_GetIntegerZero (location), |
| (m2expr_BuildSub (location, |
| m2decl_BuildIntegerConstant ( |
| m2decl_GetBitsPerInt () / BITS_PER_UNIT), |
| m2expr_GetIntegerOne (location), false))), |
| loc); |
| return c; |
| } |
| |
| static tree |
| build_m2_iso_byte_node (location_t location, int loc) |
| { |
| tree c; |
| |
| /* Define `BYTE' as specified in ISO m2 |
| |
| BYTE = ARRAY [0..SizeOfByte / SizeOfLoc] OF LOC ; */ |
| |
| if (BITS_PER_UNIT == 8) |
| c = m2type_GetISOLocType (); |
| else |
| c = gm2_build_array_type ( |
| m2type_GetISOLocType (), |
| m2type_BuildArrayIndexType ( |
| m2expr_GetIntegerZero (location), |
| m2decl_BuildIntegerConstant (BITS_PER_UNIT / 8)), |
| loc); |
| return c; |
| } |
| |
| static tree |
| build_m2_offt_type_node (location_t location) |
| { |
| m2assert_AssertLocation (location); |
| int offt_size = M2Options_GetFileOffsetBits (); |
| |
| if (offt_size == 0) |
| offt_size = TREE_INT_CST_LOW (TYPE_SIZE (ssizetype)); |
| return build_m2_specific_size_type (location, INTEGER_TYPE, |
| offt_size, true); |
| } |
| |
| /* m2type_InitSystemTypes initialise loc and word derivatives. */ |
| |
| void |
| m2type_InitSystemTypes (location_t location, int loc) |
| { |
| m2assert_AssertLocation (location); |
| |
| m2_iso_word_type_node = build_m2_iso_word_node (location, loc); |
| m2_iso_byte_type_node = build_m2_iso_byte_node (location, loc); |
| |
| m2_word16_type_node = build_m2_word16_type_node (location, loc); |
| m2_word32_type_node = build_m2_word32_type_node (location, loc); |
| m2_word64_type_node = build_m2_word64_type_node (location, loc); |
| m2_offt_type_node = build_m2_offt_type_node (location); |
| } |
| |
| static tree |
| build_m2_integer_node (void) |
| { |
| return m2type_GetIntegerType (); |
| } |
| |
| static tree |
| build_m2_cardinal_node (void) |
| { |
| return m2type_GetCardinalType (); |
| } |
| |
| static tree |
| build_m2_char_node (void) |
| { |
| tree c; |
| |
| /* Define `CHAR', to be an unsigned char. */ |
| |
| c = make_unsigned_type (CHAR_TYPE_SIZE); |
| layout_type (c); |
| return c; |
| } |
| |
| static tree |
| build_m2_short_real_node (void) |
| { |
| /* Define `SHORTREAL'. */ |
| ASSERT_CONDITION (TYPE_SIZE (float_type_node)); |
| return float_type_node; |
| } |
| |
| static tree |
| build_m2_real_node (void) |
| { |
| /* Define `REAL'. */ |
| ASSERT_CONDITION (TYPE_SIZE (double_type_node)); |
| return double_type_node; |
| } |
| |
| static tree |
| build_m2_long_real_node (void) |
| { |
| tree longreal; |
| |
| /* Define `LONGREAL'. */ |
| if (M2Options_GetIEEELongDouble ()) |
| longreal = float128_type_node; |
| else |
| longreal = long_double_type_node; |
| ASSERT_CONDITION (TYPE_SIZE (longreal)); |
| return longreal; |
| } |
| |
| static tree |
| build_m2_ztype_node (void) |
| { |
| tree ztype_node; |
| |
| /* Define `ZTYPE'. */ |
| |
| if (targetm.scalar_mode_supported_p (TImode)) |
| ztype_node = gm2_type_for_size (128, 0); |
| else |
| ztype_node = gm2_type_for_size (64, 0); |
| layout_type (ztype_node); |
| return ztype_node; |
| } |
| |
| static tree |
| build_m2_long_int_node (void) |
| { |
| tree c; |
| |
| /* Define `LONGINT'. */ |
| |
| c = make_signed_type (LONG_LONG_TYPE_SIZE); |
| layout_type (c); |
| return c; |
| } |
| |
| static tree |
| build_m2_long_card_node (void) |
| { |
| tree c; |
| |
| /* Define `LONGCARD'. */ |
| |
| c = make_unsigned_type (LONG_LONG_TYPE_SIZE); |
| layout_type (c); |
| return c; |
| } |
| |
| static tree |
| build_m2_short_int_node (void) |
| { |
| tree c; |
| |
| /* Define `SHORTINT'. */ |
| |
| c = make_signed_type (SHORT_TYPE_SIZE); |
| layout_type (c); |
| return c; |
| } |
| |
| static tree |
| build_m2_short_card_node (void) |
| { |
| tree c; |
| |
| /* Define `SHORTCARD'. */ |
| |
| c = make_unsigned_type (SHORT_TYPE_SIZE); |
| layout_type (c); |
| return c; |
| } |
| |
| static tree |
| build_m2_iso_loc_node (void) |
| { |
| tree c; |
| |
| /* Define `LOC' as specified in ISO m2. */ |
| |
| c = make_node (INTEGER_TYPE); |
| TYPE_PRECISION (c) = BITS_PER_UNIT; |
| TYPE_SIZE (c) = 0; |
| |
| fixup_unsigned_type (c); |
| TYPE_UNSIGNED (c) = 1; |
| return c; |
| } |
| |
| static tree |
| build_m2_integer8_type_node (location_t location) |
| { |
| m2assert_AssertLocation (location); |
| return build_m2_specific_size_type (location, INTEGER_TYPE, 8, true); |
| } |
| |
| static tree |
| build_m2_integer16_type_node (location_t location) |
| { |
| m2assert_AssertLocation (location); |
| return build_m2_specific_size_type (location, INTEGER_TYPE, 16, true); |
| } |
| |
| static tree |
| build_m2_integer32_type_node (location_t location) |
| { |
| m2assert_AssertLocation (location); |
| return build_m2_specific_size_type (location, INTEGER_TYPE, 32, true); |
| } |
| |
| static tree |
| build_m2_integer64_type_node (location_t location) |
| { |
| m2assert_AssertLocation (location); |
| return build_m2_specific_size_type (location, INTEGER_TYPE, 64, true); |
| } |
| |
| static tree |
| build_m2_cardinal8_type_node (location_t location) |
| { |
| m2assert_AssertLocation (location); |
| return build_m2_specific_size_type (location, INTEGER_TYPE, 8, false); |
| } |
| |
| static tree |
| build_m2_cardinal16_type_node (location_t location) |
| { |
| m2assert_AssertLocation (location); |
| return build_m2_specific_size_type (location, INTEGER_TYPE, 16, false); |
| } |
| |
| static tree |
| build_m2_cardinal32_type_node (location_t location) |
| { |
| m2assert_AssertLocation (location); |
| return build_m2_specific_size_type (location, INTEGER_TYPE, 32, false); |
| } |
| |
| static tree |
| build_m2_cardinal64_type_node (location_t location) |
| { |
| m2assert_AssertLocation (location); |
| return build_m2_specific_size_type (location, INTEGER_TYPE, 64, false); |
| } |
| |
| static tree |
| build_m2_bitset8_type_node (location_t location) |
| { |
| m2assert_AssertLocation (location); |
| if (broken_set_debugging_info) |
| return build_m2_specific_size_type (location, INTEGER_TYPE, 8, false); |
| else |
| return build_m2_specific_size_type (location, SET_TYPE, 8, false); |
| } |
| |
| static tree |
| build_m2_bitset16_type_node (location_t location) |
| { |
| m2assert_AssertLocation (location); |
| if (broken_set_debugging_info) |
| return build_m2_specific_size_type (location, INTEGER_TYPE, 16, false); |
| else |
| return build_m2_specific_size_type (location, SET_TYPE, 16, false); |
| } |
| |
| static tree |
| build_m2_bitset32_type_node (location_t location) |
| { |
| m2assert_AssertLocation (location); |
| if (broken_set_debugging_info) |
| return build_m2_specific_size_type (location, INTEGER_TYPE, 32, false); |
| else |
| return build_m2_specific_size_type (location, SET_TYPE, 32, false); |
| } |
| |
| static tree |
| build_m2_real32_type_node (location_t location) |
| { |
| m2assert_AssertLocation (location); |
| return build_m2_specific_size_type (location, REAL_TYPE, 32, true); |
| } |
| |
| static tree |
| build_m2_real64_type_node (location_t location) |
| { |
| m2assert_AssertLocation (location); |
| return build_m2_specific_size_type (location, REAL_TYPE, 64, true); |
| } |
| |
| static tree |
| build_m2_real96_type_node (location_t location) |
| { |
| m2assert_AssertLocation (location); |
| return build_m2_specific_size_type (location, REAL_TYPE, 96, true); |
| } |
| |
| static tree |
| build_m2_real128_type_node (location_t location) |
| { |
| m2assert_AssertLocation (location); |
| return build_m2_specific_size_type (location, REAL_TYPE, 128, true); |
| } |
| |
| static tree |
| build_m2_complex_type_from (tree scalar_type) |
| { |
| tree new_type; |
| |
| if (scalar_type == NULL) |
| return NULL; |
| if (scalar_type == float_type_node) |
| return complex_float_type_node; |
| if (scalar_type == double_type_node) |
| return complex_double_type_node; |
| if (scalar_type == long_double_type_node) |
| return complex_long_double_type_node; |
| |
| new_type = make_node (COMPLEX_TYPE); |
| TREE_TYPE (new_type) = scalar_type; |
| layout_type (new_type); |
| return new_type; |
| } |
| |
| static tree |
| build_m2_complex_type_node (void) |
| { |
| return build_m2_complex_type_from (m2_real_type_node); |
| } |
| |
| static tree |
| build_m2_long_complex_type_node (void) |
| { |
| return build_m2_complex_type_from (m2_long_real_type_node); |
| } |
| |
| static tree |
| build_m2_short_complex_type_node (void) |
| { |
| return build_m2_complex_type_from (m2_short_real_type_node); |
| } |
| |
| static tree |
| build_m2_complex32_type_node (void) |
| { |
| return build_m2_complex_type_from (m2_real32_type_node); |
| } |
| |
| static tree |
| build_m2_complex64_type_node (void) |
| { |
| return build_m2_complex_type_from (m2_real64_type_node); |
| } |
| |
| static tree |
| build_m2_complex96_type_node (void) |
| { |
| return build_m2_complex_type_from (m2_real96_type_node); |
| } |
| |
| static tree |
| build_m2_complex128_type_node (void) |
| { |
| return build_m2_complex_type_from (m2_real128_type_node); |
| } |
| |
| static tree |
| build_m2_cardinal_address_type_node (location_t location) |
| { |
| tree size = size_in_bytes (ptr_type_node); |
| int bits = TREE_INT_CST_LOW (size) * BITS_PER_UNIT; |
| |
| return build_m2_specific_size_type (location, INTEGER_TYPE, bits, false); |
| } |
| |
| static void |
| build_m2_boolean (location_t location) |
| { |
| tree tname = get_identifier ("BOOLEAN"); |
| tree typedecl = build_decl (location, TYPE_DECL, tname, boolean_type_node); |
| DECL_ARTIFICIAL (typedecl) = 1; |
| TYPE_NAME (boolean_type_node) = typedecl; |
| } |
| |
| |
| /* Return true if real types a and b are the same. */ |
| |
| bool |
| m2type_SameRealType (tree a, tree b) |
| { |
| return ((a == b) |
| || (TYPE_PRECISION (a) == TYPE_PRECISION (b))); |
| } |
| |
| /* InitBaseTypes create the Modula-2 base types. */ |
| |
| void |
| m2type_InitBaseTypes (location_t location) |
| { |
| m2assert_AssertLocation (location); |
| m2block_init (); |
| |
| ptr_type_node = build_pointer_type (void_type_node); |
| |
| proc_type_node |
| = build_pointer_type (build_function_type (void_type_node, NULL_TREE)); |
| |
| bitset_type_node = build_bitset_type (location); |
| m2_char_type_node = build_m2_char_node (); |
| m2_integer_type_node = build_m2_integer_node (); |
| m2_cardinal_type_node = build_m2_cardinal_node (); |
| m2_short_real_type_node = build_m2_short_real_node (); |
| m2_real_type_node = build_m2_real_node (); |
| m2_long_real_type_node = build_m2_long_real_node (); |
| m2_long_int_type_node = build_m2_long_int_node (); |
| m2_long_card_type_node = build_m2_long_card_node (); |
| m2_short_int_type_node = build_m2_short_int_node (); |
| m2_short_card_type_node = build_m2_short_card_node (); |
| m2_z_type_node = build_m2_ztype_node (); |
| m2_integer8_type_node = build_m2_integer8_type_node (location); |
| m2_integer16_type_node = build_m2_integer16_type_node (location); |
| m2_integer32_type_node = build_m2_integer32_type_node (location); |
| m2_integer64_type_node = build_m2_integer64_type_node (location); |
| m2_cardinal8_type_node = build_m2_cardinal8_type_node (location); |
| m2_cardinal16_type_node = build_m2_cardinal16_type_node (location); |
| m2_cardinal32_type_node = build_m2_cardinal32_type_node (location); |
| m2_cardinal64_type_node = build_m2_cardinal64_type_node (location); |
| m2_bitset8_type_node = build_m2_bitset8_type_node (location); |
| m2_bitset16_type_node = build_m2_bitset16_type_node (location); |
| m2_bitset32_type_node = build_m2_bitset32_type_node (location); |
| m2_real32_type_node = build_m2_real32_type_node (location); |
| m2_real64_type_node = build_m2_real64_type_node (location); |
| m2_real96_type_node = build_m2_real96_type_node (location); |
| m2_real128_type_node = build_m2_real128_type_node (location); |
| m2_complex_type_node = build_m2_complex_type_node (); |
| m2_long_complex_type_node = build_m2_long_complex_type_node (); |
| m2_short_complex_type_node = build_m2_short_complex_type_node (); |
| m2_c_type_node = m2_long_complex_type_node; |
| m2_complex32_type_node = build_m2_complex32_type_node (); |
| m2_complex64_type_node = build_m2_complex64_type_node (); |
| m2_complex96_type_node = build_m2_complex96_type_node (); |
| m2_complex128_type_node = build_m2_complex128_type_node (); |
| m2_iso_loc_type_node = build_m2_iso_loc_node (); |
| |
| m2_cardinal_address_type_node |
| = build_m2_cardinal_address_type_node (location); |
| |
| m2_packed_boolean_type_node = build_nonstandard_integer_type (1, true); |
| build_m2_boolean (location); |
| |
| if (M2Options_GetPPOnly ()) |
| return; |
| |
| m2builtins_init (location); |
| m2except_InitExceptions (location); |
| m2expr_init (location); |
| } |
| |
| /* BuildStartType given a, type, with a, name, return a GCC |
| declaration of this type. TYPE name = foo ; |
| |
| the type, foo, maybe a partially created type (which has |
| yet to be 'gm2_finish_decl'ed). */ |
| |
| tree |
| m2type_BuildStartType (location_t location, char *name, tree type) |
| { |
| tree id = get_identifier (name); |
| tree decl, tem; |
| |
| m2assert_AssertLocation (location); |
| ASSERT (m2tree_is_type (type), type); |
| type = m2tree_skip_type_decl (type); |
| decl = build_decl (location, TYPE_DECL, id, type); |
| |
| tem = m2block_pushDecl (decl); |
| ASSERT (tem == decl, decl); |
| ASSERT (m2tree_is_type (decl), decl); |
| |
| return tem; |
| } |
| |
| /* BuildEndType finish declaring, type, and return, type. */ |
| |
| tree |
| m2type_BuildEndType (location_t location, tree type) |
| { |
| m2assert_AssertLocation (location); |
| layout_type (TREE_TYPE (type)); |
| gm2_finish_decl (location, type); |
| return type; |
| } |
| |
| /* DeclareKnownType given a, type, with a, name, return a GCC |
| declaration of this type. TYPE name = foo ; */ |
| |
| tree |
| m2type_DeclareKnownType (location_t location, char *name, tree type) |
| { |
| m2assert_AssertLocation (location); |
| return m2type_BuildEndType (location, |
| m2type_BuildStartType (location, name, type)); |
| } |
| |
| /* GetDefaultType given a, type, with a, name, return a GCC |
| declaration of this type. Checks to see whether the type name has |
| already been declared as a default type and if so it returns this |
| declaration. Otherwise it declares the type. In Modula-2 this is |
| equivalent to: |
| |
| TYPE name = type ; |
| |
| We need this function during gm2 initialization as it allows |
| gm2 to access default types before creating Modula-2 types. */ |
| |
| tree |
| m2type_GetDefaultType (location_t location, char *name, tree type) |
| { |
| tree id = maybe_get_identifier (name); |
| |
| m2assert_AssertLocation (location); |
| if (id == NULL) |
| { |
| tree prev = type; |
| tree t; |
| |
| while (prev != NULL) |
| { |
| if (TYPE_NAME (prev) == NULL) |
| TYPE_NAME (prev) = get_identifier (name); |
| prev = TREE_TYPE (prev); |
| } |
| t = m2type_DeclareKnownType (location, name, type); |
| return t; |
| } |
| else |
| return id; |
| } |
| |
| /* IsGccRealType return true if type is a GCC realtype. */ |
| |
| static |
| bool |
| IsGccRealType (tree type) |
| { |
| return (type == m2_real_type_node || type == m2type_GetRealType () || |
| type == m2_long_real_type_node || type == m2type_GetLongRealType () || |
| type == m2_short_real_type_node || type == m2type_GetShortRealType () || |
| type == m2type_GetM2Real32 () || |
| type == m2type_GetM2Real64 () || |
| type == m2type_GetM2Real96 () || |
| type == m2type_GetM2Real128 ()); |
| } |
| |
| static |
| tree |
| do_min_real (tree type) |
| { |
| REAL_VALUE_TYPE r; |
| char buf[128]; |
| enum machine_mode mode = TYPE_MODE (type); |
| |
| get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf), false); |
| real_from_string (&r, buf); |
| return build1 (NEGATE_EXPR, type, build_real (type, r)); |
| } |
| |
| /* GetMinFrom given a, type, return a constant representing the |
| minimum legal value. */ |
| |
| tree |
| m2type_GetMinFrom (location_t location, tree type) |
| { |
| m2assert_AssertLocation (location); |
| |
| if (IsGccRealType (type)) |
| return do_min_real (type); |
| if (type == ptr_type_node) |
| return m2expr_GetPointerZero (location); |
| |
| return TYPE_MIN_VALUE (m2tree_skip_type_decl (type)); |
| } |
| |
| static |
| tree |
| do_max_real (tree type) |
| { |
| REAL_VALUE_TYPE r; |
| char buf[128]; |
| enum machine_mode mode = TYPE_MODE (type); |
| |
| get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf), false); |
| real_from_string (&r, buf); |
| return build_real (type, r); |
| } |
| |
| /* GetMaxFrom given a, type, return a constant representing the |
| maximum legal value. */ |
| |
| tree |
| m2type_GetMaxFrom (location_t location, tree type) |
| { |
| m2assert_AssertLocation (location); |
| |
| if (IsGccRealType (type)) |
| return do_max_real (type); |
| if (type == ptr_type_node) |
| return fold (m2expr_BuildSub (location, m2expr_GetPointerZero (location), |
| m2expr_GetPointerOne (location), false)); |
| |
| return TYPE_MAX_VALUE (m2tree_skip_type_decl (type)); |
| } |
| |
| /* BuildTypeDeclaration adds the, type, to the current statement |
| list. */ |
| |
| void |
| m2type_BuildTypeDeclaration (location_t location, tree type) |
| { |
| enum tree_code code = TREE_CODE (type); |
| |
| m2assert_AssertLocation (location); |
| if (code == TYPE_DECL || code == RECORD_TYPE || code == POINTER_TYPE) |
| { |
| m2block_pushDecl (build_decl (location, TYPE_DECL, NULL, type)); |
| } |
| else if (code == VAR_DECL) |
| { |
| m2type_BuildTypeDeclaration (location, TREE_TYPE (type)); |
| m2block_pushDecl ( |
| build_stmt (location, DECL_EXPR, |
| type)); /* Is this safe? --fixme--. */ |
| } |
| } |
| |
| /* Begin compiling the definition of an enumeration type. NAME is |
| its name (or null if anonymous). Returns the type object, as yet |
| incomplete. Also records info about it so that build_enumerator may |
| be used to declare the individual values as they are read. */ |
| |
| static tree |
| gm2_start_enum (location_t location, tree name, int ispacked) |
| { |
| tree enumtype = make_node (ENUMERAL_TYPE); |
| |
| m2assert_AssertLocation (location); |
| if (TYPE_VALUES (enumtype) != 0) |
| { |
| /* This enum is a named one that has been declared already. */ |
| error_at (location, "redeclaration of enum %qs", |
| IDENTIFIER_POINTER (name)); |
| |
| /* Completely replace its old definition. The old enumerators remain |
| defined, however. */ |
| TYPE_VALUES (enumtype) = 0; |
| } |
| |
| TYPE_PACKED (enumtype) = ispacked; |
| TREE_TYPE (enumtype) = m2type_GetIntegerType (); |
| |
| /* This is required as rest_of_type_compilation will use this field |
| when called from gm2_finish_enum. |
| |
| Create a fake NULL-named TYPE_DECL node whose TREE_TYPE will be the |
| tagged type we just added to the current scope. This fake NULL-named |
| TYPE_DECL node helps dwarfout.cc to know when it needs to output a |
| representation of a tagged type, and it also gives us a convenient |
| place to record the "scope start" address for the tagged type. */ |
| |
| TYPE_STUB_DECL (enumtype) = m2block_pushDecl ( |
| build_decl (location, TYPE_DECL, NULL_TREE, enumtype)); |
| |
| return enumtype; |
| } |
| |
| /* After processing and defining all the values of an enumeration |
| type, install their decls in the enumeration type and finish it off. |
| ENUMTYPE is the type object, VALUES a list of decl-value pairs, and |
| ATTRIBUTES are the specified attributes. Returns ENUMTYPE. */ |
| |
| static tree |
| gm2_finish_enum (location_t location, tree enumtype, tree values) |
| { |
| tree pair, tem; |
| tree minnode = 0, maxnode = 0; |
| int precision; |
| signop sign; |
| |
| /* Calculate the maximum value of any enumerator in this type. */ |
| |
| if (values == error_mark_node) |
| minnode = maxnode = integer_zero_node; |
| else |
| { |
| minnode = maxnode = TREE_VALUE (values); |
| for (pair = TREE_CHAIN (values); pair; pair = TREE_CHAIN (pair)) |
| { |
| tree value = TREE_VALUE (pair); |
| if (tree_int_cst_lt (maxnode, value)) |
| maxnode = value; |
| if (tree_int_cst_lt (value, minnode)) |
| minnode = value; |
| } |
| } |
| |
| /* Construct the final type of this enumeration. It is the same as |
| one of the integral types the narrowest one that fits, except that |
| normally we only go as narrow as int and signed iff any of the |
| values are negative. */ |
| sign = (tree_int_cst_sgn (minnode) >= 0) ? UNSIGNED : SIGNED; |
| precision = MAX (tree_int_cst_min_precision (minnode, sign), |
| tree_int_cst_min_precision (maxnode, sign)); |
| |
| if (precision > TYPE_PRECISION (integer_type_node)) |
| { |
| warning (0, "enumeration values exceed range of integer"); |
| tem = long_long_integer_type_node; |
| } |
| else if (TYPE_PACKED (enumtype)) |
| tem = m2type_BuildSmallestTypeRange (location, minnode, maxnode); |
| else |
| tem = sign == UNSIGNED ? unsigned_type_node : integer_type_node; |
| |
| TYPE_MIN_VALUE (enumtype) = TYPE_MIN_VALUE (tem); |
| TYPE_MAX_VALUE (enumtype) = TYPE_MAX_VALUE (tem); |
| TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (tem); |
| TYPE_SIZE (enumtype) = 0; |
| |
| /* If the precision of the type was specific with an attribute and it |
| was too small, give an error. Otherwise, use it. */ |
| if (TYPE_PRECISION (enumtype)) |
| { |
| if (precision > TYPE_PRECISION (enumtype)) |
| error ("specified mode too small for enumerated values"); |
| } |
| else |
| TYPE_PRECISION (enumtype) = TYPE_PRECISION (tem); |
| |
| layout_type (enumtype); |
| |
| if (values != error_mark_node) |
| { |
| |
| /* Change the type of the enumerators to be the enum type. We need |
| to do this irrespective of the size of the enum, for proper type |
| checking. Replace the DECL_INITIALs of the enumerators, and the |
| value slots of the list, with copies that have the enum type; they |
| cannot be modified in place because they may be shared (e.g. |
| integer_zero_node) Finally, change the purpose slots to point to the |
| names of the decls. */ |
| for (pair = values; pair; pair = TREE_CHAIN (pair)) |
| { |
| tree enu = TREE_PURPOSE (pair); |
| tree ini = DECL_INITIAL (enu); |
| |
| TREE_TYPE (enu) = enumtype; |
| |
| if (TREE_TYPE (ini) != integer_type_node) |
| ini = convert (enumtype, ini); |
| |
| DECL_INITIAL (enu) = ini; |
| TREE_PURPOSE (pair) = DECL_NAME (enu); |
| TREE_VALUE (pair) = ini; |
| } |
| |
| TYPE_VALUES (enumtype) = values; |
| } |
| |
| /* Fix up all variant types of this enum type. */ |
| for (tem = TYPE_MAIN_VARIANT (enumtype); tem; tem = TYPE_NEXT_VARIANT (tem)) |
| { |
| if (tem == enumtype) |
| continue; |
| TYPE_VALUES (tem) = TYPE_VALUES (enumtype); |
| TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype); |
| TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype); |
| TYPE_SIZE (tem) = TYPE_SIZE (enumtype); |
| TYPE_SIZE_UNIT (tem) = TYPE_SIZE_UNIT (enumtype); |
| SET_TYPE_MODE (tem, TYPE_MODE (enumtype)); |
| TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype); |
| SET_TYPE_ALIGN (tem, TYPE_ALIGN (enumtype)); |
| TYPE_USER_ALIGN (tem) = TYPE_USER_ALIGN (enumtype); |
| TYPE_UNSIGNED (tem) = TYPE_UNSIGNED (enumtype); |
| TYPE_LANG_SPECIFIC (tem) = TYPE_LANG_SPECIFIC (enumtype); |
| } |
| |
| /* Finish debugging output for this type. */ |
| rest_of_type_compilation (enumtype, m2block_toplevel ()); |
| return enumtype; |
| } |
| |
| /* BuildStartEnumeration create an enumerated type in gcc. */ |
| |
| tree |
| m2type_BuildStartEnumeration (location_t location, char *name, bool ispacked) |
| { |
| tree id; |
| |
| m2assert_AssertLocation (location); |
| if ((name == NULL) || (strcmp (name, "") == 0)) |
| id = NULL_TREE; |
| else |
| id = get_identifier (name); |
| |
| return gm2_start_enum (location, id, ispacked); |
| } |
| |
| /* BuildEndEnumeration finish building the enumeration, it uses the |
| enum list, enumvalues, and returns a enumeration type tree. */ |
| |
| tree |
| m2type_BuildEndEnumeration (location_t location, tree enumtype, |
| tree enumvalues) |
| { |
| tree finished ATTRIBUTE_UNUSED |
| = gm2_finish_enum (location, enumtype, enumvalues); |
| return enumtype; |
| } |
| |
| /* Build and install a CONST_DECL for one value of the current |
| enumeration type (one that was begun with start_enum). Return a |
| tree-list containing the CONST_DECL and its value. Assignment of |
| sequential values by default is handled here. */ |
| |
| static tree |
| gm2_build_enumerator (location_t location, tree name, tree value) |
| { |
| tree decl, type; |
| |
| m2assert_AssertLocation (location); |
| /* Remove no-op casts from the value. */ |
| if (value) |
| STRIP_TYPE_NOPS (value); |
| |
| /* Now create a declaration for the enum value name. */ |
| |
| type = TREE_TYPE (value); |
| |
| decl = build_decl (location, CONST_DECL, name, type); |
| DECL_INITIAL (decl) = convert (type, value); |
| m2block_pushDecl (decl); |
| |
| return tree_cons (decl, value, NULL_TREE); |
| } |
| |
| /* BuildEnumerator build an enumerator and add it to the, |
| enumvalues, list. It returns a copy of the value. */ |
| |
| tree |
| m2type_BuildEnumerator (location_t location, char *name, tree value, |
| tree *enumvalues) |
| { |
| tree id = get_identifier (name); |
| tree copy_of_value = copy_node (value); |
| tree gccenum = gm2_build_enumerator (location, id, copy_of_value); |
| |
| m2assert_AssertLocation (location); |
| /* Choose copy_of_value for enum value. */ |
| *enumvalues = chainon (gccenum, *enumvalues); |
| return copy_of_value; |
| } |
| |
| /* BuildPointerType returns a type which is a pointer to, totype. */ |
| |
| tree |
| m2type_BuildPointerType (tree totype) |
| { |
| return build_pointer_type (m2tree_skip_type_decl (totype)); |
| } |
| |
| /* BuildConstPointerType returns a type which is a const pointer |
| to, totype. */ |
| |
| tree |
| m2type_BuildConstPointerType (tree totype) |
| { |
| tree t = build_pointer_type (m2tree_skip_type_decl (totype)); |
| TYPE_READONLY (t) = true; |
| return t; |
| } |
| |
| /* BuildSetType creates a SET OF [lowval..highval]. */ |
| |
| tree |
| m2type_BuildSetType (location_t location, char *name, tree type, tree lowval, |
| tree highval, bool ispacked) |
| { |
| tree range = build_range_type (m2tree_skip_type_decl (type), |
| m2expr_FoldAndStrip (lowval), |
| m2expr_FoldAndStrip (highval)); |
| |
| TYPE_PACKED (range) = ispacked; |
| m2assert_AssertLocation (location); |
| return m2type_BuildSetTypeFromSubrange (location, name, range, |
| m2expr_FoldAndStrip (lowval), |
| m2expr_FoldAndStrip (highval), |
| ispacked); |
| } |
| |
| /* push_constructor returns a new compound constructor frame. */ |
| |
| static struct struct_constructor * |
| push_constructor (void) |
| { |
| struct struct_constructor *p = ggc_alloc<struct_constructor> (); |
| |
| p->level = top_constructor; |
| top_constructor = p; |
| return p; |
| } |
| |
| /* pop_constructor throws away the top constructor frame on the |
| stack. */ |
| |
| static void |
| pop_constructor (struct struct_constructor *p) |
| { |
| ASSERT_CONDITION (p |
| == top_constructor); /* p should be the top_constructor. */ |
| top_constructor = top_constructor->level; |
| } |
| |
| /* BuildStartSetConstructor starts to create a set constant. |
| Remember that type is really a record type. */ |
| |
| void * |
| m2type_BuildStartSetConstructor (tree type) |
| { |
| struct struct_constructor *p = push_constructor (); |
| |
| type = m2tree_skip_type_decl (type); |
| layout_type (type); |
| p->constructor_type = type; |
| p->constructor_fields = TYPE_FIELDS (type); |
| p->constructor_element_list = NULL_TREE; |
| vec_alloc (p->constructor_elements, 1); |
| return (void *)p; |
| } |
| |
| /* BuildSetConstructorElement adds, value, to the |
| constructor_element_list. */ |
| |
| void |
| m2type_BuildSetConstructorElement (void *p, tree value) |
| { |
| struct struct_constructor *c = (struct struct_constructor *)p; |
| |
| if (value == NULL_TREE) |
| { |
| internal_error ("set type cannot be initialized with a %qs", |
| "NULL_TREE"); |
| return; |
| } |
| |
| if (c->constructor_fields == NULL) |
| { |
| internal_error ("set type does not take another integer value"); |
| return; |
| } |
| |
| c->constructor_element_list |
| = tree_cons (c->constructor_fields, value, c->constructor_element_list); |
| c->constructor_fields = TREE_CHAIN (c->constructor_fields); |
| } |
| |
| /* BuildEndSetConstructor finishes building a set constant. */ |
| |
| tree |
| m2type_BuildEndSetConstructor (void *p) |
| { |
| tree constructor; |
| tree link; |
| struct struct_constructor *c = (struct struct_constructor *)p; |
| |
| for (link = c->constructor_element_list; link; link = TREE_CHAIN (link)) |
| { |
| tree field = TREE_PURPOSE (link); |
| DECL_SIZE (field) = bitsize_int (SET_WORD_SIZE); |
| DECL_BIT_FIELD (field) = 1; |
| } |
| |
| constructor = build_constructor_from_list ( |
| c->constructor_type, nreverse (c->constructor_element_list)); |
| TREE_CONSTANT (constructor) = 1; |
| TREE_STATIC (constructor) = 1; |
| |
| pop_constructor (c); |
| |
| return constructor; |
| } |
| |
| /* BuildStartRecordConstructor initializes a record compound |
| constructor frame. */ |
| |
| void * |
| m2type_BuildStartRecordConstructor (tree type) |
| { |
| struct struct_constructor *p = push_constructor (); |
| |
| type = m2tree_skip_type_decl (type); |
| layout_type (type); |
| p->constructor_type = type; |
| p->constructor_fields = TYPE_FIELDS (type); |
| p->constructor_element_list = NULL_TREE; |
| vec_alloc (p->constructor_elements, 1); |
| return (void *)p; |
| } |
| |
| /* BuildEndRecordConstructor returns a tree containing the record |
| compound literal. */ |
| |
| tree |
| m2type_BuildEndRecordConstructor (void *p) |
| { |
| struct struct_constructor *c = (struct struct_constructor *)p; |
| tree constructor = build_constructor_from_list ( |
| c->constructor_type, nreverse (c->constructor_element_list)); |
| TREE_CONSTANT (constructor) = 1; |
| TREE_STATIC (constructor) = 1; |
| |
| pop_constructor (c); |
| |
| return constructor; |
| } |
| |
| /* BuildRecordConstructorElement adds, value, to the |
| constructor_element_list. */ |
| |
| void |
| m2type_BuildRecordConstructorElement (void *p, tree value) |
| { |
| m2type_BuildSetConstructorElement (p, value); |
| } |
| |
| /* BuildStartArrayConstructor initializes an array compound |
| constructor frame. */ |
| |
| void * |
| m2type_BuildStartArrayConstructor (tree type) |
| { |
| struct struct_constructor *p = push_constructor (); |
| |
| type = m2tree_skip_type_decl (type); |
| layout_type (type); |
| p->constructor_type = type; |
| p->constructor_fields = TREE_TYPE (type); |
| p->constructor_element_list = NULL_TREE; |
| vec_alloc (p->constructor_elements, 1); |
| return (void *)p; |
| } |
| |
| /* BuildEndArrayConstructor returns a tree containing the array |
| compound literal. */ |
| |
| tree |
| m2type_BuildEndArrayConstructor (void *p) |
| { |
| struct struct_constructor *c = (struct struct_constructor *)p; |
| tree constructor; |
| |
| constructor |
| = build_constructor (c->constructor_type, c->constructor_elements); |
| TREE_CONSTANT (constructor) = true; |
| TREE_STATIC (constructor) = true; |
| |
| pop_constructor (c); |
| |
| return constructor; |
| } |
| |
| /* BuildArrayConstructorElement adds, value, to the |
| constructor_element_list. */ |
| |
| void |
| m2type_BuildArrayConstructorElement (void *p, tree value, tree indice) |
| { |
| struct struct_constructor *c = (struct struct_constructor *)p; |
| constructor_elt celt; |
| |
| if (value == NULL_TREE) |
| { |
| internal_error ("array cannot be initialized with a %qs", "NULL_TREE"); |
| return; |
| } |
| |
| if (c->constructor_fields == NULL_TREE) |
| { |
| internal_error ("array type must be initialized"); |
| return; |
| } |
| |
| if (c->constructor_fields != TREE_TYPE (value)) |
| { |
| internal_error ( |
| "array element value must be the same type as its declaration"); |
| return; |
| } |
| |
| celt.index = indice; |
| celt.value = value; |
| vec_safe_push (c->constructor_elements, celt); |
| } |
| |
| /* BuildArrayStringConstructor creates an array constructor for, |
| arrayType, consisting of the character elements defined by, str, |
| of, length, characters. */ |
| |
| tree |
| m2type_BuildArrayStringConstructor (location_t location, tree arrayType, |
| tree str, tree length) |
| { |
| tree n; |
| tree val; |
| int i = 0; |
| const char *p = TREE_STRING_POINTER (str); |
| tree type = m2tree_skip_type_decl (TREE_TYPE (arrayType)); |
| struct struct_constructor *c |
| = (struct struct_constructor *)m2type_BuildStartArrayConstructor ( |
| arrayType); |
| char nul[1]; |
| int len = strlen (p); |
| |
| nul[0] = (char)0; |
| |
| m2assert_AssertLocation (location); |
| n = m2expr_GetIntegerZero (location); |
| while (m2expr_CompareTrees (n, length) < 0) |
| { |
| if (i < len) |
| val = m2convert_BuildConvert ( |
| location, type, m2type_BuildCharConstant (location, &p[i]), false); |
| else |
| val = m2type_BuildCharConstant (location, &nul[0]); |
| m2type_BuildArrayConstructorElement (c, val, n); |
| i += 1; |
| n = m2expr_BuildAdd (location, n, m2expr_GetIntegerOne (location), |
| false); |
| } |
| return m2type_BuildEndArrayConstructor (c); |
| } |
| |
| /* BuildSubrangeType creates a subrange of, type, with, lowval, |
| highval. */ |
| |
| tree |
| m2type_BuildSubrangeType (location_t location, char *name, tree type, |
| tree lowval, tree highval) |
| { |
| tree range_type; |
| |
| m2assert_AssertLocation (location); |
| type = m2tree_skip_type_decl (type); |
| |
| lowval = m2expr_FoldAndStrip (lowval); |
| highval = m2expr_FoldAndStrip (highval); |
| |
| if (m2expr_TreeOverflow (lowval)) |
| error ("low bound for the subrange has overflowed"); |
| if (m2expr_TreeOverflow (highval)) |
| error ("high bound for the subrange has overflowed"); |
| |
| /* First build a type with the base range. */ |
| range_type = build_range_type (type, lowval, highval); |
| |
| TYPE_UNSIGNED (range_type) = TYPE_UNSIGNED (type); |
| #if 0 |
| /* Then set the actual range. */ |
| SET_TYPE_RM_MIN_VALUE (range_type, lowval); |
| SET_TYPE_RM_MAX_VALUE (range_type, highval); |
| #endif |
| |
| if ((name != NULL) && (strcmp (name, "") != 0)) |
| { |
| /* Declared as TYPE foo = [x..y]; */ |
| range_type = m2type_DeclareKnownType (location, name, range_type); |
| layout_type (m2tree_skip_type_decl (range_type)); |
| } |
| |
| return range_type; |
| } |
| |
| /* BuildCharConstantChar creates a character constant given a character, ch. */ |
| |
| tree |
| m2type_BuildCharConstantChar (location_t location, char ch) |
| { |
| tree id = build_int_cst (char_type_node, (int) ch); |
| id = m2convert_BuildConvert (location, m2type_GetM2CharType (), id, false); |
| return m2block_RememberConstant (id); |
| } |
| |
| /* BuildCharConstant creates a character constant given a, string. */ |
| |
| tree |
| m2type_BuildCharConstant (location_t location, const char *string) |
| { |
| return m2type_BuildCharConstantChar (location, string[0]); |
| } |
| |
| /* RealToTree convert a real number into a Tree. */ |
| |
| tree |
| m2type_RealToTree (char *name) |
| { |
| return build_real ( |
| m2type_GetLongRealType (), |
| REAL_VALUE_ATOF (name, TYPE_MODE (m2type_GetLongRealType ()))); |
| } |
| |
| /* gm2_start_struct start to create a struct. */ |
| |
| static tree |
| gm2_start_struct (location_t location, enum tree_code code, char *name) |
| { |
| tree s = make_node (code); |
| tree id; |
| |
| m2assert_AssertLocation (location); |
| if ((name == NULL) || (strcmp (name, "") == 0)) |
| id = NULL_TREE; |
| else |
| id = get_identifier (name); |
| |
| /* This maybe set true later if necessary. */ |
| TYPE_PACKED (s) = false; |
| |
| m2block_pushDecl (build_decl (location, TYPE_DECL, id, s)); |
| return s; |
| } |
| |
| /* BuildStartRecord return a RECORD tree. */ |
| |
| tree |
| m2type_BuildStartRecord (location_t location, char *name) |
| { |
| m2assert_AssertLocation (location); |
| return gm2_start_struct (location, RECORD_TYPE, name); |
| } |
| |
| /* BuildStartUnion return a union tree. */ |
| |
| tree |
| m2type_BuildStartUnion (location_t location, char *name) |
| { |
| m2assert_AssertLocation (location); |
| return gm2_start_struct (location, UNION_TYPE, name); |
| } |
| |
| /* m2type_BuildStartVarient builds a varient record. It creates a |
| record field which has a, name, and whose type is a union. */ |
| |
| tree |
| m2type_BuildStartVarient (location_t location, char *name) |
| { |
| tree varient = m2type_BuildStartUnion (location, name); |
| tree field = m2type_BuildStartFieldRecord (location, name, varient); |
| m2assert_AssertLocation (location); |
| return field; |
| } |
| |
| /* m2type_BuildEndVarient finish the varientField by calling |
| decl_finish and also finish the type of varientField (which is a |
| union). */ |
| |
| tree |
| m2type_BuildEndVarient (location_t location, tree varientField, |
| tree varientList, bool isPacked) |
| { |
| tree varient = TREE_TYPE (varientField); |
| m2assert_AssertLocation (location); |
| varient = m2type_BuildEndRecord (location, varient, varientList, isPacked); |
| gm2_finish_decl (location, varientField); |
| return varientField; |
| } |
| |
| /* m2type_BuildStartFieldVarient builds a field varient record. It |
| creates a record field which has a, name, and whose type is a |
| record. */ |
| |
| tree |
| m2type_BuildStartFieldVarient (location_t location, char *name) |
| { |
| tree record = m2type_BuildStartRecord (location, name); |
| tree field = m2type_BuildStartFieldRecord (location, name, record); |
| m2assert_AssertLocation (location); |
| return field; |
| } |
| |
| /* BuildEndRecord a heavily pruned finish_struct from c-decl.cc. It |
| sets the context for each field to, t, propagates isPacked |
| throughout the fields in the structure. */ |
| |
| tree |
| m2type_BuildEndRecord (location_t location, tree record, tree fieldlist, |
| bool isPacked) |
| { |
| tree x, d; |
| |
| m2assert_AssertLocation (location); |
| |
| /* If this type was previously laid out as a forward reference, make |
| sure we lay it out again. */ |
| |
| TYPE_SIZE (record) = 0; |
| |
| /* Install struct as DECL_CONTEXT of each field decl. Also process |
| specified field sizes, found in the DECL_INITIAL, storing 0 there |
| after the type has been changed to precision equal to its width, |
| rather than the precision of the specified standard type. (Correct |
| layout requires the original type to have been preserved until now). */ |
| |
| for (x = fieldlist; x; x = TREE_CHAIN (x)) |
| { |
| DECL_CONTEXT (x) = record; |
| |
| if (TYPE_PACKED (record) && TYPE_ALIGN (TREE_TYPE (x)) > BITS_PER_UNIT) |
| DECL_PACKED (x) = 1; |
| |
| if (isPacked) |
| { |
| DECL_PACKED (x) = 1; |
| DECL_BIT_FIELD (x) = 1; |
| } |
| } |
| |
| /* Now we have the nearly final fieldlist. Record it, then lay out |
| the structure or union (including the fields). */ |
| |
| TYPE_FIELDS (record) = fieldlist; |
| layout_type (record); |
| |
| /* Now we have the truly final field list. Store it in this type and |
| in the variants. */ |
| |
| for (x = TYPE_MAIN_VARIANT (record); x; x = TYPE_NEXT_VARIANT (x)) |
| { |
| TYPE_FIELDS (x) = TYPE_FIELDS (record); |
| TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (record); |
| SET_TYPE_ALIGN (x, TYPE_ALIGN (record)); |
| TYPE_USER_ALIGN (x) = TYPE_USER_ALIGN (record); |
| } |
| |
| d = build_decl (location, TYPE_DECL, NULL, record); |
| TYPE_STUB_DECL (record) = d; |
| |
| /* Finish debugging output for this type. This must be done after we have |
| called build_decl. */ |
| rest_of_type_compilation (record, m2block_toplevel ()); |
| |
| return record; |
| } |
| |
| /* m2type_BuildEndFieldVarient finish the varientField by calling |
| decl_finish and also finish the type of varientField (which is a |
| record). */ |
| |
| tree |
| m2type_BuildEndFieldVarient (location_t location, tree varientField, |
| tree varientList, bool isPacked) |
| { |
| tree record = TREE_TYPE (varientField); |
| |
| m2assert_AssertLocation (location); |
| record = m2type_BuildEndRecord (location, record, varientList, isPacked); |
| gm2_finish_decl (location, varientField); |
| return varientField; |
| } |
| |
| /* m2type_BuildStartFieldRecord starts building a field record. It |
| returns the field which must be completed by calling |
| gm2_finish_decl. */ |
| |
| tree |
| m2type_BuildStartFieldRecord (location_t location, char *name, tree type) |
| { |
| tree field, declarator; |
| |
| m2assert_AssertLocation (location); |
| if ((name == NULL) || (strcmp (name, "") == 0)) |
| declarator = NULL_TREE; |
| else |
| declarator = get_identifier (name); |
| |
| field = build_decl (location, FIELD_DECL, declarator, |
| m2tree_skip_type_decl (type)); |
| return field; |
| } |
| |
| /* Build a record field with name (name maybe NULL), returning the |
| new field declaration, FIELD_DECL. |
| |
| This is done during the parsing of the struct declaration. The |
| FIELD_DECL nodes are chained together and the lot of them are |
| ultimately passed to `build_struct' to make the RECORD_TYPE node. */ |
| |
| tree |
| m2type_BuildFieldRecord (location_t location, char *name, tree type) |
| { |
| tree field = m2type_BuildStartFieldRecord (location, name, type); |
| |
| m2assert_AssertLocation (location); |
| gm2_finish_decl (location, field); |
| return field; |
| } |
| |
| /* ChainOn interface so that Modula-2 can also create chains of |
| declarations. */ |
| |
| tree |
| m2type_ChainOn (tree t1, tree t2) |
| { |
| return chainon (t1, t2); |
| } |
| |
| /* ChainOnParamValue adds a list node {{name, str}, value} into the |
| tree list. */ |
| |
| tree |
| m2type_ChainOnParamValue (tree list, tree name, tree str, tree value) |
| { |
| return chainon (list, build_tree_list (build_tree_list (name, str), value)); |
| } |
| |
| /* AddStringToTreeList adds, string, to list. */ |
| |
| tree |
| m2type_AddStringToTreeList (tree list, tree string) |
| { |
| return tree_cons (NULL_TREE, string, list); |
| } |
| |
| /* SetAlignment sets the alignment of a, node, to, align. It |
| duplicates the, node, and sets the alignment to prevent alignment |
| effecting behaviour elsewhere. */ |
| |
| tree |
| m2type_SetAlignment (tree node, tree align) |
| { |
| tree type = NULL_TREE; |
| tree decl = NULL_TREE; |
| bool is_type = false; |
| int i; |
| |
| if (DECL_P (node)) |
| { |
| decl = node; |
| is_type = (TREE_CODE (node) == TYPE_DECL); |
| type = TREE_TYPE (decl); |
| } |
| else if (TYPE_P (node)) |
| { |
| is_type = true; |
| type = node; |
| } |
| |
| if (TREE_CODE (align) != INTEGER_CST) |
| error ("requested alignment is not a constant"); |
| else if ((i = tree_log2 (align)) == -1) |
| error ("requested alignment is not a power of 2"); |
| else if (i > HOST_BITS_PER_INT - 2) |
| error ("requested alignment is too large"); |
| else if (is_type) |
| { |
| /* If we have a TYPE_DECL, then copy the type, so that we don't |
| accidentally modify a builtin type. See pushdecl. */ |
| if (decl && TREE_TYPE (decl) != error_mark_node |
| && DECL_ORIGINAL_TYPE (decl) == NULL_TREE) |
| { |
| tree tt = TREE_TYPE (decl); |
| type = build_variant_type_copy (type); |
| DECL_ORIGINAL_TYPE (decl) = tt; |
| TYPE_NAME (type) = decl; |
| TREE_USED (type) = TREE_USED (decl); |
| TREE_TYPE (decl) = type; |
| } |
| |
| SET_TYPE_ALIGN (type, (1 << i) * BITS_PER_UNIT); |
| TYPE_USER_ALIGN (type) = 1; |
| |
| if (decl) |
| { |
| SET_DECL_ALIGN (decl, (1 << i) * BITS_PER_UNIT); |
| DECL_USER_ALIGN (decl) = 1; |
| } |
| } |
| else if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FIELD_DECL) |
| error ("alignment may not be specified for %qD", decl); |
| else |
| { |
| SET_DECL_ALIGN (decl, (1 << i) * BITS_PER_UNIT); |
| DECL_USER_ALIGN (decl) = 1; |
| } |
| return node; |
| } |
| |
| /* SetDeclPacked sets the packed bit in decl TREE, node. It |
| returns the node. */ |
| |
| tree |
| m2type_SetDeclPacked (tree node) |
| { |
| DECL_PACKED (node) = 1; |
| return node; |
| } |
| |
| /* SetTypePacked sets the packed bit in type TREE, node. It |
| returns the node. */ |
| |
| tree |
| m2type_SetTypePacked (tree node) |
| { |
| TYPE_PACKED (node) = 1; |
| return node; |
| } |
| |
| /* SetRecordFieldOffset returns field after the byteOffset and |
| bitOffset has been applied to it. */ |
| |
| tree |
| m2type_SetRecordFieldOffset (tree field, tree byteOffset, tree bitOffset, |
| tree fieldtype, tree nbits) |
| { |
| DECL_FIELD_OFFSET (field) = byteOffset; |
| DECL_FIELD_BIT_OFFSET (field) = bitOffset; |
| TREE_TYPE (field) = m2tree_skip_type_decl (fieldtype); |
| DECL_SIZE (field) = bitsize_int (TREE_INT_CST_LOW (nbits)); |
| return field; |
| } |
| |
| /* BuildPackedFieldRecord builds a packed field record of, name, |
| and, fieldtype. */ |
| |
| tree |
| m2type_BuildPackedFieldRecord (location_t location, char *name, tree fieldtype) |
| { |
| m2assert_AssertLocation (location); |
| return m2type_BuildFieldRecord (location, name, fieldtype); |
| } |
| |
| /* BuildNumberOfArrayElements returns the number of elements in an |
| arrayType. */ |
| |
| tree |
| m2type_BuildNumberOfArrayElements (location_t location, tree arrayType) |
| { |
| tree index = TYPE_DOMAIN (arrayType); |
| tree high = TYPE_MAX_VALUE (index); |
| tree low = TYPE_MIN_VALUE (index); |
| tree elements = m2expr_BuildAdd ( |
| location, m2expr_BuildSub (location, high, low, false), |
| m2expr_GetIntegerOne (location), false); |
| m2assert_AssertLocation (location); |
| return elements; |
| } |
| |
| /* AddStatement maps onto add_stmt. */ |
| |
| void |
| m2type_AddStatement (location_t location, tree t) |
| { |
| if (t != NULL_TREE) |
| add_stmt (location, t); |
| } |
| |
| /* MarkFunctionReferenced marks a function as referenced. */ |
| |
| void |
| m2type_MarkFunctionReferenced (tree f) |
| { |
| if (f != NULL_TREE) |
| if (TREE_CODE (f) == FUNCTION_DECL) |
| mark_decl_referenced (f); |
| } |
| |
| /* GarbageCollect force gcc to garbage collect. */ |
| |
| void |
| m2type_GarbageCollect (void) |
| { |
| ggc_collect (); |
| } |
| |
| /* gm2_type_for_size return an integer type with BITS bits of |
| precision, that is unsigned if UNSIGNEDP is nonzero, otherwise |
| signed. */ |
| |
| tree |
| m2type_gm2_type_for_size (unsigned int bits, bool unsignedp) |
| { |
| if (bits == TYPE_PRECISION (integer_type_node)) |
| return unsignedp ? unsigned_type_node : integer_type_node; |
| |
| if (bits == TYPE_PRECISION (signed_char_type_node)) |
| return unsignedp ? unsigned_char_type_node : signed_char_type_node; |
| |
| if (bits == TYPE_PRECISION (short_integer_type_node)) |
| return unsignedp ? short_unsigned_type_node : short_integer_type_node; |
| |
| if (bits == TYPE_PRECISION (long_integer_type_node)) |
| return unsignedp ? long_unsigned_type_node : long_integer_type_node; |
| |
| if (bits == TYPE_PRECISION (long_long_integer_type_node)) |
| return (unsignedp ? long_long_unsigned_type_node |
| : long_long_integer_type_node); |
| |
| if (bits <= TYPE_PRECISION (intQI_type_node)) |
| return unsignedp ? unsigned_intQI_type_node : intQI_type_node; |
| |
| if (bits <= TYPE_PRECISION (intHI_type_node)) |
| return unsignedp ? unsigned_intHI_type_node : intHI_type_node; |
| |
| if (bits <= TYPE_PRECISION (intSI_type_node)) |
| return unsignedp ? unsigned_intSI_type_node : intSI_type_node; |
| |
| if (bits <= TYPE_PRECISION (intDI_type_node)) |
| return unsignedp ? unsigned_intDI_type_node : intDI_type_node; |
| |
| return 0; |
| } |
| |
| /* gm2_unsigned_type return an unsigned type the same as TYPE in |
| other respects. */ |
| |
| tree |
| m2type_gm2_unsigned_type (tree type) |
| { |
| tree type1 = TYPE_MAIN_VARIANT (type); |
| if (type1 == signed_char_type_node || type1 == char_type_node) |
| return unsigned_char_type_node; |
| if (type1 == integer_type_node) |
| return unsigned_type_node; |
| if (type1 == short_integer_type_node) |
| return short_unsigned_type_node; |
| if (type1 == long_integer_type_node) |
| return long_unsigned_type_node; |
| if (type1 == long_long_integer_type_node) |
| return long_long_unsigned_type_node; |
| |
| #if HOST_BITS_PER_WIDE_INT >= 64 |
| if (type1 == intTI_type_node) |
| return unsigned_intTI_type_node; |
| #endif |
| if (type1 == intDI_type_node) |
| return unsigned_intDI_type_node; |
| if (type1 == intSI_type_node) |
| return unsigned_intSI_type_node; |
| if (type1 == intHI_type_node) |
| return unsigned_intHI_type_node; |
| if (type1 == intQI_type_node) |
| return unsigned_intQI_type_node; |
| |
| return m2type_gm2_signed_or_unsigned_type (true, type); |
| } |
| |
| /* gm2_signed_type return a signed type the same as TYPE in other |
| respects. */ |
| |
| tree |
| m2type_gm2_signed_type (tree type) |
| { |
| tree type1 = TYPE_MAIN_VARIANT (type); |
| if (type1 == unsigned_char_type_node || type1 == char_type_node) |
| return signed_char_type_node; |
| if (type1 == unsigned_type_node) |
| return integer_type_node; |
| if (type1 == short_unsigned_type_node) |
| return short_integer_type_node; |
| if (type1 == long_unsigned_type_node) |
| return long_integer_type_node; |
| if (type1 == long_long_unsigned_type_node) |
| return long_long_integer_type_node; |
| |
| #if HOST_BITS_PER_WIDE_INT >= 64 |
| if (type1 == unsigned_intTI_type_node) |
| return intTI_type_node; |
| #endif |
| if (type1 == unsigned_intDI_type_node) |
| return intDI_type_node; |
| if (type1 == unsigned_intSI_type_node) |
| return intSI_type_node; |
| if (type1 == unsigned_intHI_type_node) |
| return intHI_type_node; |
| if (type1 == unsigned_intQI_type_node) |
| return intQI_type_node; |
| |
| return m2type_gm2_signed_or_unsigned_type (false, type); |
| } |
| |
| /* check_type if the precision of baseType and type are the same |
| then return true and set the signed or unsigned type in result |
| else return false. */ |
| |
| static int |
| check_type (tree baseType, tree type, int unsignedp, tree baseu, tree bases, |
| tree *result) |
| { |
| if (TYPE_PRECISION (baseType) == TYPE_PRECISION (type)) |
| { |
| if (unsignedp) |
| *result = baseu; |
| else |
| *result = bases; |
| return true; |
| } |
| return false; |
| } |
| |
| /* gm2_signed_or_unsigned_type return a type the same as TYPE |
| except unsigned or signed according to UNSIGNEDP. */ |
| |
| tree |
| m2type_gm2_signed_or_unsigned_type (int unsignedp, tree type) |
| { |
| tree result; |
| |
| if (!INTEGRAL_TYPE_P (type) || TYPE_UNSIGNED (type) == unsignedp) |
| return type; |
| |
| /* For INTEGER_TYPEs we must check the precision as well, so as to |
| yield correct results for bit-field types. */ |
| |
| if (check_type (signed_char_type_node, type, unsignedp, |
| unsigned_char_type_node, signed_char_type_node, &result)) |
| return result; |
| if (check_type (integer_type_node, type, unsignedp, unsigned_type_node, |
| integer_type_node, &result)) |
| return result; |
| if (check_type (short_integer_type_node, type, unsignedp, |
| short_unsigned_type_node, short_integer_type_node, &result)) |
| return result; |
| if (check_type (long_integer_type_node, type, unsignedp, |
| long_unsigned_type_node, long_integer_type_node, &result)) |
| return result; |
| if (check_type (long_long_integer_type_node, type, unsignedp, |
| long_long_unsigned_type_node, long_long_integer_type_node, |
| &result)) |
| return result; |
| |
| #if HOST_BITS_PER_WIDE_INT >= 64 |
| if (check_type (intTI_type_node, type, unsignedp, unsigned_intTI_type_node, |
| intTI_type_node, &result)) |
| return result; |
| #endif |
| if (check_type (intDI_type_node, type, unsignedp, unsigned_intDI_type_node, |
| intDI_type_node, &result)) |
| return result; |
| if (check_type (intSI_type_node, type, unsignedp, unsigned_intSI_type_node, |
| intSI_type_node, &result)) |
| return result; |
| if (check_type (intHI_type_node, type, unsignedp, unsigned_intHI_type_node, |
| intHI_type_node, &result)) |
| return result; |
| if (check_type (intQI_type_node, type, unsignedp, unsigned_intQI_type_node, |
| intQI_type_node, &result)) |
| return result; |
| #undef TYPE_OK |
| |
| return type; |
| } |
| |
| /* IsAddress returns true if the type is an ADDRESS. */ |
| |
| bool |
| m2type_IsAddress (tree type) |
| { |
| return type == ptr_type_node; |
| } |
| |
| /* check_record_fields return true if all the fields in left and right |
| are GCC equivalent. */ |
| |
| static |
| bool |
| check_record_fields (tree left, tree right) |
| { |
| unsigned int i; |
| tree right_value; |
| vec<constructor_elt, va_gc> *values = CONSTRUCTOR_ELTS (right); |
| FOR_EACH_CONSTRUCTOR_VALUE (values, i, right_value) |
| { |
| tree left_field = TREE_TYPE (m2treelib_get_field_no (left, NULL_TREE, false, i)); |
| if (! m2type_IsGccStrictTypeEquivalent (left_field, right_value)) |
| return false; |
| } |
| return true; |
| } |
| |
| /* check_array_types return true if left and right have the same type and right |
| is not a CST_STRING. */ |
| |
| static |
| bool |
| check_array_types (tree right) |
| { |
| unsigned int i; |
| tree value; |
| vec<constructor_elt, va_gc> *values = CONSTRUCTOR_ELTS (right); |
| FOR_EACH_CONSTRUCTOR_VALUE (values, i, value) |
| { |
| enum tree_code right_code = TREE_CODE (value); |
| if (right_code == STRING_CST) |
| return false; |
| } |
| return true; |
| } |
| |
| bool |
| m2type_IsGccStrictTypeEquivalent (tree left, tree right) |
| { |
| enum tree_code right_code = TREE_CODE (right); |
| enum tree_code left_code = TREE_CODE (left); |
| if (left_code == VAR_DECL) |
| return m2type_IsGccStrictTypeEquivalent (TREE_TYPE (left), right); |
| if (right_code == VAR_DECL) |
| return m2type_IsGccStrictTypeEquivalent (left, TREE_TYPE (right)); |
| if (left_code == RECORD_TYPE && right_code == CONSTRUCTOR) |
| return check_record_fields (left, right); |
| if (left_code == UNION_TYPE && right_code == CONSTRUCTOR) |
| return false; |
| if (left_code == ARRAY_TYPE && right_code == CONSTRUCTOR) |
| return check_array_types (right); |
| if (right_code == STRING_CST) |
| return false; |
| return true; |
| } |
| |
| #include "gt-m2-m2type.h" |