Patch for setting DW_AT_const_value in identity declaration VAR_DECLs

Jose E. Marchesi jemarch@gnu.org
Tue Sep 22 13:26:34 GMT 2026


Hi again.

I forgot to mention variables! :D

I think ideally all the identity declarations might be emitted as
DW_AT_const_value, because they are really constant once they get
initialized.

Now, will we need DW_AT_variable as well?  The answer is yes.

But first I have to explain how the concept of "variable" is realized in
Algol 68.

The identity declaration is generally:


    AMODE identifier = VALUE

Where AMODE is any mode.  And any mode means _any_ mode in an
orthogonal language, no exceptions.  So AMODE might be an integral
mode, a real number mode, a boolean mode, a string mode, a struct mode,
an union mode, a procedure mode, etc.

One of the kind of modes is the "name", or reference.  These are of mode
`ref AMODE' and the values are references to other values.  You can
think of them as sort of "pointers" (but not quite exactly, see below).

So for example, `ref int' is the mode of values which are references to
int.  Now, what VALUE do you assign to a reference?  Well, "names" or
reference values are conceptually storage, and you have of two kinds:

    AMODE   ID   VALUE
   ------- ---   -------
   ref int foo = loc int;    { `loc int' yields a ref to int value
                                on the stack. }

   ref int foo = heap int;   { `heap int' yields a ref to int value
                                allocated on the heap. }

loc and gen are "generators".

The assignation (assignment) construct looks like:

   LHS := RHS

where LHS must be of some `ref AMODE' and the RHS must be of some AMODE.
Its side effect is to make the reference value at the LHS to refer to a
copy of the value at the RHS.

Now, if we would implement mutability using just identity declarations,
we would be continuously doing indirect addressing non-stop.  Like for
example, to maintain a counter:


   begin
         ref int counter = loc int;

         counter := 0;  { ref int := int }
         do
             { ... do something with counter ... }
         od
   end

There `counter' has mode `ref int' and is a VAR_DECL that is really a
constant, as already discussed.  GCC will likely realize that VAR_DECL
as an automatic, that contains an *int.  Therefore every access to
`counter' would require indirection, and thats sort of silly.

For this reason, and also to provide some syntactic sugar, in Algol 68
you have a "variable declaration" construct that looks like:

   int counter;

Where the declared `counter' has mode `ref int', not int.

which is the equivalent to:

   int counter = loc int;

and to:

   loc int counter;

You can also do:

   heap int counter;

which is the equivalent to:

   int counter = heap int;

So, language wise, there is absolutely not difference between a counter
defined as `int counter = loc counter' and `int counter'.  But
implementation wise, we compile variable declarations into VAR_DECLs
that are not constant, to avoid indirect addressing.

So, this code is totally equivalent to the previous version language
wise:


   begin
         int counter;

         counter := 0;  { ref int := int }
         do
             { ... do something with counter ... }
         od
   end

But this time, `counter' results in a VAR_DECL with type int (and not
*int), not constant, and can be accessed using direct addressing.

For these we want to geneate DW_AT_variable values I guess..


> Hello Mark!
>
>> Hi Jose,
>>
>> On Tue, Sep 22, 2026 at 01:14:54AM +0200, Jose E. Marchesi wrote:
>>> This is the patch for getting the DW_AT_const_value in identity
>>> declaration DIEs in DWARF.
>>> 
>>> For the small test program:
>>> 
>>>   begin
>>>         int var := 10;
>>>         int ide = 20;
>>>         skip
>>>   end
>>> 
>>> It generates the DWARF:
>>> 
>>>  <4><7f>: Abbrev Number: 5 (DW_TAG_variable)
>>>     <80>   DW_AT_name        : ide
>>>     <84>   DW_AT_decl_file   : 2
>>>     <85>   DW_AT_decl_line   : 3
>>>     <86>   DW_AT_decl_column : 11
>>>     <87>   DW_AT_type        : <0x9e>
>>>     <8b>   DW_AT_const_value : 1
>>>  <4><8c>: Abbrev Number: 6 (DW_TAG_variable)
>>>     <8d>   DW_AT_name        : var
>>>     <91>   DW_AT_decl_file   : 2
>>>     <92>   DW_AT_decl_line   : 2
>>>     <93>   DW_AT_decl_column : 11
>>>     <94>   DW_AT_type        : <0x9e>
>>>     <98>   DW_AT_location    : 2 byte block: 91 6c 	(DW_OP_fbreg: -20)
>>
>> Is that really how you want to represent constant values?
>> DW_AT_const_value gives the constant value of a variable. But here it
>> seems to be used as a flag whether the value is constant? (I would
>> have expected it to say 20.) There is DW_TAG_constant, which is used
>> for named constants.
>
> Ok this requires a bit of explanation.  We are having a hard time to
> decide which DWARF would be best for the language's language constructs.
> Algol 68 is hard :') [BTW we will be discussing about this in the GNU
> Algol 68 BoF in Cauldron, Sunday at 9AM.  It would be great if you could
> pass by and give us some advise. We would really benefit from the input
> someone who actually knows about DWARF.]
>
> Allright, so in Algol 68 the usual concepts of "constant", "variable",
> "pointer", parameter passing, etc, are generalized in a single concept:
> the "identity declaration", in which some value gets ascribed to an
> identifier, like in:
>
>
>     int foo = 10;
>
> After that, the identifier `foo' could be literally substituted by its
> ascribed value (10) and everything would be ok.  Note that the mode
> (type) of the so-defined identifier may be any mode, including multiples
> (arrays), structs, etc, like:
>
>
>     mode Person = struct (string name, int age,
>                           struct (string street, city, country) addr);
>
>     Person me = ("Jose Marchesi", 46, ("C/Foo", "Frankfurt", "Germany"));
>
> The ascribed value doens't have to be a denotation (literal), but it
> could literally anything, like in:
>
>     Person me = if is_monday then jose else mrhyde fi;
>
> Once ascribed, there is simply no way to modify the value ascribed to
> the identifier in the identity declaration.  This is assured by a) the
> value ascribed is actually a copy of the value that appears at the right
> in the identity declaration, and b) assignation (assignment) cannot be
> used to change an ascribed value.  An identity declaration is the way to
> use a "constant" in Algol 68.
>
>
> Now, the "scope" (range in C terms) of an identifier declared in an
> identity declaration is the range (scope in C terms) in which it is
> declared, including _before_ the identity declaration, like in:
>
>    begin
>          { foo is accessible here, its constant value is 0. }
>          int foo = 10;
>          { foo is accessible here, its constant value is 10. }
>    end
>
> Note { and } are comment delimiters.
>
> When the front-end finds the above code, it lowers it to a GENERIC like:
>
>   void __algol68_main ()
>   {
>     STANDARD__prelude ();
>     POSIX__prelude ();
>     {
>       void stop;
>
>       {
>         signed int foo = 0;
>
>         /* foo is accessible here and its value is 0 */
>         foo = 10;
>         /* foo is accessible here and its value is 10 */
>       }
>       stop:, {};
>     }
>     POSIX__postlude ();
>     STANDARD__postlude ();
>   }
>
> In GENERIC terms, the front-end creates a VAR_DECL for foo, sets its
> DECL_INITIAL to zero, and then emits a MODIFY_EXPR to set it to 10 at
> the point in the program in which the identity declaration happens.
>
> Setting DECL_INITIAL to 10 wouldn't work.  First, because it would lead
> to:
>
>   void __algol68_main ()
>   {
>     STANDARD__prelude ();
>     POSIX__prelude ();
>     {
>       void stop;
>
>       {
>         signed int foo = 10;
>
>         /* foo is accessible here and its value is 10 (WRONG) */
>         /* Identity declaration is here.  */
>         /* foo is accessible here and its value is 10 */
>       }
>       stop:, {};
>     }
>     POSIX__postlude ();
>     STANDARD__postlude ();
>   }
>
> And worse, because the following code would miscompile, since the
> initializations may happen at any order, and at the beginning of the
> block:
>
>   { Make sure structs get copied when ascribed. }
>   begin
>         mode Bar = struct (int j, real r);
>         mode Foo = struct (int i, Bar bar);
>
>         Foo f1 := (10, (20, 3.14));
>         Foo f2 = f1;
>
>         j of bar of f1 := 200;
>         assert (j of bar of f1 = 200);
>         assert (j of bar of f2 = 20)
>   end
>
> So this is the reason why we cannot mark the VAR_DECL resulting from
> identity declarations as DECL_CONSTANT and TREE_READ_ONLY: we need to do
> the MODIFY_EXPR at the right place.
>
> Yesterday I was brainsorming a bit with cuper and faust, and we thought
> about ways of doing this better, but none works:
>
> - First, we thought about doing something like:
>
>
>      begin
>           int foo = 10;
>           { XXX }
>           int bar = 20;
>           { YYY }
>      end
>
>   to the generic:
>
>      {
>        {
>          int foo = 10;  VAR_DECL with constant
>          /* XXX */
>
>          {
>            int bar = 20; VAR DECL with constant
>            /* YYY */
>          }
>        }
>      }
>
>   i.e. to inroduce  a block for each declaration, so we can put the
>   ascribed value in DECL_INIT.  This of course wouldn't work because foo
>   and bar wouldn't be accessible before they are declared.
>
> - Then we went more crazy and thought about:
>
>      begin
>           { PRE }
>           int foo = 10;
>           { POST }
>      end
>
>   to be lowered to the GENERIC:
>
>
>      {
>         int foo' = 0;  VAR_DECL non-constant
>
>         /* PRE uses foo' for identifier foo */
>         {
>           int foo = 10; VAR_DECL constant
>           /* POST uses foo for identifier foo */
>         }
>      }
>
>   but this is not satisfactory, because foo' is suppose to be constant
>   too.
>
> So I guess this all boils down to... what would be the best way to
> denote all this in DWARF? :)
>           
>
>>
>> Cheers,
>>
>> Mark
>>
>>> diff --git a/gcc/algol68/a68-lang.cc b/gcc/algol68/a68-lang.cc
>>> index 6c3e607cb0c..042002eb1b3 100644
>>> --- a/gcc/algol68/a68-lang.cc
>>> +++ b/gcc/algol68/a68-lang.cc
>>> @@ -31,6 +31,7 @@
>>>  #include "machmode.h"
>>>  #include "stor-layout.h" /* For layout_type */
>>>  #include "vec.h"
>>> +#include "dwarf2.h"
>>>  
>>>  #include "a68.h"
>>>  
>>> @@ -50,6 +51,7 @@ struct GTY(()) lang_type
>>>  struct GTY(()) lang_decl
>>>  {
>>>    NODE_T * node;
>>> +  bool is_var;
>>>  };
>>>  
>>>  /* Language-specific identifier information.  This must include a
>>> @@ -100,7 +102,7 @@ a68_build_lang_type (MOID_T *moid)
>>>  /* Allocate and return a lang specific structure for decl tree nodes.  */
>>>  
>>>  struct lang_decl *
>>> -a68_build_lang_decl (NODE_T *node)
>>> +a68_build_lang_decl (NODE_T *node, bool is_var)
>>>  {
>>>    tree cdecl = CDECL (node);
>>>    struct lang_decl *ld = cdecl ? DECL_LANG_SPECIFIC (cdecl) : NULL;
>>> @@ -109,9 +111,29 @@ a68_build_lang_decl (NODE_T *node)
>>>      ld = (struct lang_decl *) ggc_cleared_alloc <struct lang_decl> ();
>>>    if (ld->node == NULL)
>>>      ld->node = node;
>>> +  ld->is_var = is_var;
>>>    return ld;
>>>  }
>>>  
>>> +/* Get the front-end is_var attribute associated with the given DECL.  */
>>> +
>>> +bool
>>> +a68_decl_is_var (const_tree decl)
>>> +{
>>> +  gcc_assert (VAR_P (decl));
>>> +  return DECL_LANG_SPECIFIC (decl) && DECL_LANG_SPECIFIC (decl)->is_var;
>>> +}
>>> +
>>> +/* Set the front-end is_var attribute associated with DECL to the given
>>> +   IS_VAR.  */
>>> +
>>> +void
>>> +a68_decl_set_is_var (tree decl, bool is_var)
>>> +{
>>> +  gcc_assert (VAR_P (decl));
>>> +  DECL_LANG_SPECIFIC (decl)->is_var = is_var;
>>> +}
>>> +
>>>  /* Get the front-end mode associated with the given TYPE.  If no mode is
>>>     associated then this function returns NO_MODE.  */
>>>  
>>> @@ -436,6 +458,25 @@ a68_getdecls (void)
>>>  #undef LANG_HOOKS_GETDECLS
>>>  #define LANG_HOOKS_GETDECLS a68_getdecls
>>>  
>>> +/* Return -1 if dwarf ATTR shouldn't be added for DECL, or the attribute
>>> +   value otherwise.  */
>>> +int
>>> +a68_decl_dwarf_attribute (const_tree decl, int attr)
>>> +{
>>> +  if (decl == NULL_TREE)
>>> +    return -1;
>>> +
>>> +  if (attr == DW_AT_const_value
>>> +      && VAR_P (decl)
>>> +      && !a68_decl_is_var (decl))
>>> +    return 1;
>>> +
>>> +  return -1;
>>> +}
>>> +
>>> +#undef LANG_HOOKS_DECL_DWARF_ATTRIBUTE
>>> +#define LANG_HOOKS_DECL_DWARF_ATTRIBUTE a68_decl_dwarf_attribute
>>> +
>>>  /* Return A68_GLOBAL_CONTEXT, but create it first if need be.  */
>>>  
>>>  static tree
>>> diff --git a/gcc/algol68/a68-low-moids.cc b/gcc/algol68/a68-low-moids.cc
>>> index ddd87671190..1ee786f401e 100644
>>> --- a/gcc/algol68/a68-low-moids.cc
>>> +++ b/gcc/algol68/a68-low-moids.cc
>>> @@ -132,7 +132,7 @@ chain_struct_fields (PACK_T *fields, tree context)
>>>  
>>>        /* Associate the tree field declaration and the front end node.  */
>>>        DECL_LANG_SPECIFIC (field_decl) =
>>> -	(NODE (field_mode) ? a68_build_lang_decl (NODE (field_mode)) : NULL);
>>> +	(NODE (field_mode) ? a68_build_lang_decl (NODE (field_mode), false /* is_var */) : NULL);
>>>  
>>>        /* Chain the field declaration in its containing context.  */
>>>        DECL_FIELD_CONTEXT (field_decl) = context;
>>> diff --git a/gcc/algol68/a68-low.cc b/gcc/algol68/a68-low.cc
>>> index 8fc112cd76f..99b25a32cea 100644
>>> --- a/gcc/algol68/a68-low.cc
>>> +++ b/gcc/algol68/a68-low.cc
>>> @@ -438,6 +438,7 @@ a68_make_anonymous_routine_decl (MOID_T *mode)
>>>  			       FUNCTION_DECL,
>>>  			       NULL_TREE /* name, set below.  */,
>>>  			       func_type);
>>> +
>>>    char *name = xasprintf ("routine%d", DECL_UID (func_decl));
>>>    DECL_NAME (func_decl) = a68_get_mangled_identifier (name);
>>>    free (name);
>>> @@ -470,6 +471,9 @@ a68_make_proc_identity_declaration_decl (NODE_T *identifier,
>>>  			       NULL_TREE, /* name, set below.  */
>>>  			       func_type);
>>>  
>>> +  DECL_LANG_SPECIFIC (func_decl)
>>> +    = a68_build_lang_decl (identifier, false);
>>> +
>>>    if (public_range)
>>>      {
>>>        bool publicized = PUBLICIZED (TAX (identifier));
>>> @@ -533,6 +537,9 @@ a68_make_identity_declaration_decl (NODE_T *identifier,
>>>  			  NULL_TREE, /* name, set below.  */
>>>  			  type);
>>>  
>>> +  DECL_LANG_SPECIFIC (decl)
>>> +    = a68_build_lang_decl (identifier, false /* is_var */);
>>> +
>>>    if (public_range)
>>>      {
>>>        bool publicized = PUBLICIZED (TAX (identifier));
>>> @@ -593,6 +600,9 @@ a68_make_variable_declaration_decl (NODE_T *identifier,
>>>  			  NULL_TREE, /* name, set below.  */
>>>  			  type);
>>>  
>>> +  DECL_LANG_SPECIFIC (decl)
>>> +    = a68_build_lang_decl (identifier, true /* is_var */);
>>> +
>>>    if (public_range)
>>>      {
>>>        bool publicized = PUBLICIZED (TAX (identifier));
>>> diff --git a/gcc/algol68/a68.h b/gcc/algol68/a68.h
>>> index 59f23e4e779..8fcbde97a75 100644
>>> --- a/gcc/algol68/a68.h
>>> +++ b/gcc/algol68/a68.h
>>> @@ -301,8 +301,10 @@ uint32_t *a68_u8_to_u32 (const uint8_t *s, size_t n, uint32_t *resultbuf, size_t
>>>  #define a68_word_real_type          A68_GLOBAL_TREES[ATI_WORD_REAL_TYPE]
>>>  
>>>  struct lang_type *a68_build_lang_type (MOID_T *moid);
>>> -struct lang_decl *a68_build_lang_decl (NODE_T *node);
>>> +struct lang_decl *a68_build_lang_decl (NODE_T *node, bool is_var);
>>>  MOID_T *a68_type_moid (tree type);
>>> +bool a68_decl_is_var (const_tree decl);
>>> +void a68_decl_set_is_var (tree decl, bool is_var);
>>>  
>>>  /* a68-diagnostics.cc  */
>>>  
>>> diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
>>> index d170e18c740..49d9778a858 100644
>>> --- a/gcc/dwarf2out.cc
>>> +++ b/gcc/dwarf2out.cc
>>> @@ -5655,6 +5655,16 @@ is_dlang (void)
>>>    return lang == DW_LANG_D;
>>>  }
>>>  
>>> +/* Return TRUE if the language is Algol 68.  */
>>> +
>>> +static inline bool
>>> +is_algol68 (void)
>>> +{
>>> +  unsigned int lang = get_AT_unsigned (comp_unit_die (), DW_AT_language);
>>> +
>>> +  return lang == DW_LANG_Algol68;
>>> +}
>>> +
>>>  /* Remove the specified attribute if present.  Return TRUE if removal
>>>     was successful.  */
>>>  
>>> @@ -27728,7 +27738,19 @@ gen_decl_die (tree decl, tree origin, struct vlr_context *ctx,
>>>  				  true /* Emit name attribute.  */,
>>>  				  context_die);
>>>        else
>>> -	gen_variable_die (decl, origin, context_die);
>>> +	{
>>> +	  gen_variable_die (decl, origin, context_die);
>>> +
>>> +	  if (is_algol68 ()
>>> +	      && lang_hooks.decls.decl_dwarf_attribute (decl,
>>> +							DW_AT_const_value) == 1)
>>> +	    {
>>> +	      dw_die_ref die = lookup_decl_die (decl);
>>> +	      gcc_assert (die != NULL);
>>> +	      if (!get_AT (die, DW_AT_const_value))
>>> +		add_AT_unsigned (die, DW_AT_const_value, 1);
>>> +	    }
>>> +	}
>>>        break;
>>>  
>>>      case FIELD_DECL:


More information about the Algol68 mailing list