Bug (?) in initialization code.

Brad Lucier lucier@math.purdue.edu
Mon Mar 20 19:22:00 GMT 2000


The code that needs to be changed to fix this seems to begin at line
4104 of varasm.c; see the analysis below.  But I don't know how to fix it.

Ivan Kokshaysky was kind enough to point me to the REFLONG relocations
in the loader, which does what I want, loads the lower 32 bits of a pointer
at load time; see elf64_alpha_howto_table in bfd/elf64-alpha.c in the 
binutils source.

Compiling the following program actually bombs at line 5847 in c-typeck.c:

 else if (require_constant_elements
	   && initializer_constant_valid_p (value, TREE_TYPE (value)) == 0)
    {
      error_init ("initializer element is not computable at load time");
      value = error_mark_node;
    }

TREE_TYPE(value) is a union type, but the most likely candidate for the
type seems to be:

  common = {
    chain = 0x0, 
    type = 0x0, 
    code = INTEGER_TYPE, 
    side_effects_flag = 0, 
    constant_flag = 0, 
    permanent_flag = 0, 
    addressable_flag = 0, 
    volatile_flag = 0, 
    readonly_flag = 0, 
    unsigned_flag = 0, 
    asm_written_flag = 0, 
    used_flag = 0, 
    nothrow_flag = 0, 
    static_flag = 0, 
    public_flag = 0, 
    private_flag = 0, 
    protected_flag = 0, 
    lang_flag_0 = 0, 
    lang_flag_1 = 0, 
    lang_flag_2 = 0, 
    lang_flag_3 = 0, 
    lang_flag_4 = 0, 
    lang_flag_5 = 0, 
    lang_flag_6 = 0
  }, 

It seems that value is a pointer to the following union element:

  common = {
    chain = 0x0, 
    type = 0x2000002a700, 
    code = NOP_EXPR, 
    side_effects_flag = 2, 
    constant_flag = 2, 
    permanent_flag = 2, 
    addressable_flag = 2, 
    volatile_flag = 2, 
    readonly_flag = 2, 
    unsigned_flag = 2, 
    asm_written_flag = 2, 
    used_flag = 0, 
    nothrow_flag = 0, 
    static_flag = 0, 
    public_flag = 0, 
    private_flag = 0, 
    protected_flag = 0, 
    lang_flag_0 = 0, 
    lang_flag_1 = 0, 
    lang_flag_2 = 0, 
    lang_flag_3 = 0, 
    lang_flag_4 = 0, 
    lang_flag_5 = 0, 
    lang_flag_6 = 0
  }, 

and the code in varasm.c that handles this case seems to begin at line
4072:

    case CONVERT_EXPR:
    case NOP_EXPR:
      /* Allow conversions between pointer types.  */
      if (POINTER_TYPE_P (TREE_TYPE (value))
          && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
        return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);

      /* Allow conversions between real types.  */
      if (FLOAT_TYPE_P (TREE_TYPE (value))
          && FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
        return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);

      /* Allow length-preserving conversions between integer types.  */
      if (INTEGRAL_TYPE_P (TREE_TYPE (value))
          && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
          && (TYPE_PRECISION (TREE_TYPE (value))
              == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
        return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);

      /* Allow conversions between other integer types only if
         explicit value.  */
      if (INTEGRAL_TYPE_P (TREE_TYPE (value))
          && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
        {
          tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0),
                                                     endtype);
          if (inner == null_pointer_node)
            return null_pointer_node;
          break;
        }

      /* Allow (int) &foo provided int is as wide as a pointer.  */
      if (INTEGRAL_TYPE_P (TREE_TYPE (value))
          && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
          && (TYPE_PRECISION (TREE_TYPE (value))
              >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
        return initializer_constant_valid_p (TREE_OPERAND (value, 0),
                                             endtype);

      /* Likewise conversions from int to pointers, but also allow
         conversions from 0.  */
      if (POINTER_TYPE_P (TREE_TYPE (value))
          && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
        {
          if (integer_zerop (TREE_OPERAND (value, 0)))
            return null_pointer_node;
          else if (TYPE_PRECISION (TREE_TYPE (value))
                   <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))
            return initializer_constant_valid_p (TREE_OPERAND (value, 0),
                                                 endtype);
        }

      /* Allow conversions to union types if the value inside is okay.  */
      if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
        return initializer_constant_valid_p (TREE_OPERAND (value, 0),
                                             endtype);
      break;

So it seems that we should allow (int) &foo for alpha.c even though
int is 32 bits and a pointer is 64, if I will use the -taso switch
with ld (which Kokshaysky says is OK).  Also for conversion from
int->pointers.

Brad Lucier

> 
> The following program:
> 
> /* compile with gcc -c foo.c on alpha */
> 
> typedef int int32;
> typedef long int64;
> 
> typedef struct { int a; int b; } foo;
> 
> extern foo f;
> 
> static int32 tbl1[] =
> {
>   (int32) &f
> };
> 
> static int64 tbl2[] =
> {
>   (int64) &f
> };
> 
> static foo* tbl3[] =
> {
>   &f
> };
> 
> compiled on alphaev6 with any gcc version I tried from 2.95.1 on
> bombs and gives the following error message:
> 
> foo.c:13: initializer element is not computable at load time
> foo.c:13: (near initialization for `tbl1[0]')
> 
> The problem seems to be that gcc thinks the loader cannot stuff
> a 64bit pointer into a 32bit int at load time.
> 
> I intend to use the -taso flag with ld 2.9.5.0.27 (H. J. Lu's release).
> 
> So, the questions:
> 
> 1.  Can the loader handle this construct correctly, given the -taso flag?
> 2.  Should gcc allow this construct?


More information about the Gcc-bugs mailing list