[m-dev.] for review: GCC back-end: variable scoping

Fergus Henderson fjh at cs.mu.OZ.AU
Sun Jan 7 19:38:23 AEDT 2001


This is relative to my previously posted diff.

Estimated hours taken: 12

Implement proper variable scoping.
This has two consequences:
- the generated code uses less stack space, since various
  whose scope does not overlap get assigned the same stack slot
- local variables now show up in gdb.

mercury/compiler/gcc.m:
	New routines start_block and end_block.

mercury/compiler/mlds_to_gcc.m:
	Call the new routines.

gcc/mercury/mercury-gcc.c:
	- Call pushdecl() for builtin types and for local variables,
	  to ensure that they get recorded in gcc's symbol tables,
	  so that it will generate debugging information for them.
	- Fix a bug (copied from the toy.c example front-end)
	  where it was clobbering the function DECL_ARGUMENTS field.
	- Simplify the spec1() macro by eliminating its first arg.

===================================================================
RCS file: gcc.m,v
retrieving revision 1.11
diff -u -r1.11 gcc.m
--- gcc.m	2001/01/06 15:15:41	1.11
+++ gcc.m	2001/01/07 08:31:15
@@ -163,6 +163,22 @@
 :- pred set_var_decl_readonly(gcc__var_decl::in, io__state::di, io__state::uo) is det.
 
 %
+% Routines to start/end a block.
+%
+% Every start_block must be matched by a corresponding end_block.
+% The lifetime of any local variable declarations
+% within the block will end at the corresponding end_block.
+%
+
+	% Like `{' in C.
+:- pred start_block(io__state, io__state).
+:- mode start_block(di, uo) is det.
+
+	% Like `}' in C.
+:- pred end_block(io__state, io__state).
+:- mode end_block(di, uo) is det.
+
+%
 % Stuff for function declarations
 %
 
@@ -1181,6 +1197,24 @@
 %
 % Statements.
 %
+
+%
+% blocks
+%
+
+:- pragma c_code(start_block(_IO0::di, _IO::uo),
+	[will_not_call_mercury],
+"
+	pushlevel(0);
+	expand_start_bindings(0);
+").
+
+:- pragma c_code(end_block(_IO0::di, _IO::uo),
+	[will_not_call_mercury],
+"
+	tree block = poplevel(/*keep=*/1, /*reverse=*/1, /*functionbody=*/0);
+	expand_end_bindings(block, /*mark_ends=*/1, /*dont_jump_in=*/0);
+").
 
 %
 % if-then-else
===================================================================
RCS file: mlds_to_gcc.m,v
retrieving revision 1.13
diff -u -r1.13 mlds_to_gcc.m
--- mlds_to_gcc.m	2001/01/06 15:15:41	1.13
+++ mlds_to_gcc.m	2001/01/07 08:35:59
@@ -18,6 +18,10 @@
 % it will end up compiling everything via C.
 
 % TODO:
+%	Fix bugs:
+%	- calling convention for semidet code not binary compatible
+%	  with C; need to promote boolean return type to int
+%
 %	Fix configuration issues:
 %	- mmake support
 %	- document installation procedure
@@ -35,18 +39,23 @@
 %
 %	Implement implementation-specific features that are supported
 %	by other gcc front-ends:
+%	- generate gcc trees rather than expanding as we go
 %	- support gdb
 %		- improve accuracy of line numbers (e.g. for decls).
-%		- fix variable scoping so that local vars show up
-%	- generate gcc trees rather than expanding as we go
+%		- make variable names match what's in the original source
+%		- use nested functions or something like that to hide
+%		  from the user the environment struct stuff that we
+%		  generate for nondet code
+%		- extend gdb to print Mercury data structures better
+%		- extend gdb to print Mercury stacks better
 %
 %	Improve efficiency of generated code:
+%	- implement annotation in gcc tree to force tailcalls
 %	- improve code for switches with default_is_unreachable.
+%	  (We already do a reasonably good job, so this is a low priority.)
 %	  One way would be to implement computed_goto and cast_to_unsigned,
 %	  and change target_supports_computed_goto_2(asm) in ml_switch_gen.m
 %	  to `yes'.
-%	- fix variable scoping
-%	- implement annotation in gcc tree to force tailcalls
 %
 %	Improve efficiency of compilation:
 %	- improve symbol table handling
@@ -2153,12 +2162,14 @@
 	% sequence
 	%
 gen_stmt(FuncInfo0, block(Defns, Statements), _Context) -->
+	gcc__start_block,
 	{ FuncName = FuncInfo0 ^ func_name },
 	{ FuncName = qual(ModuleName, _) },
 	{ SymbolTable0 = FuncInfo0 ^ local_vars },
 	build_local_defns(Defns, FuncInfo0, ModuleName, SymbolTable0, SymbolTable),
 	{ FuncInfo = FuncInfo0 ^ local_vars := SymbolTable },
-	gen_statements(FuncInfo, Statements).
+	gen_statements(FuncInfo, Statements),
+	gcc__end_block.
 
 	%
 	% iteration
Index: mercury-gcc.c
===================================================================
RCS file: /home/pgrad/fjh/fs/hg/fjh_repository/mercury/mercury-gcc.c,v
retrieving revision 1.19
diff -u -d -u -r1.19 mercury-gcc.c
--- mercury-gcc.c	2001/01/05 06:01:26	1.19
+++ mercury-gcc.c	2001/01/07 08:17:45
@@ -200,6 +200,7 @@
   tree var_decl = build_decl (VAR_DECL, get_identifier (var_name),
 			      var_type);
   expand_decl (var_decl);
+  pushdecl (var_decl);
   return var_decl;
 }
 
@@ -535,9 +536,6 @@
 merc_start_function (fndecl)
      tree fndecl;
 {
-  tree param_decl, next_param;
-  tree first_param;
-
   /* Set line number information.  */
   DECL_SOURCE_FILE (fndecl) = input_filename;
   DECL_SOURCE_LINE (fndecl) = lineno;
@@ -561,13 +559,18 @@
   expand_function_start (fndecl, 0);
 
   pushlevel (0);
-  expand_start_bindings (2);
+  expand_start_bindings (0);
 
+#if 0
+{
+  tree param_decl, next_param;
+  tree first_param;
+
   /* Push all the PARM_DECL nodes onto the current scope (i.e. the scope of the
      subprogram body) so that they can be recognized as local variables in the
      subprogram.   */
 
-  for (first_param = param_decl = nreverse (DECL_ARGUMENTS (fndecl));
+  for (first_param = param_decl = DECL_ARGUMENTS (fndecl);
        param_decl;
        param_decl = next_param)
     {
@@ -577,7 +580,9 @@
     }
 
   /* Store back the PARM_DECL nodes. They appear in the right order. */
-  DECL_ARGUMENTS (fndecl) = first_param; /*getdecls ();*/
+  DECL_ARGUMENTS (fndecl) = getdecls ();
+}
+#endif
 
   pushlevel (0);
   expand_start_bindings (0);
@@ -1148,6 +1153,7 @@
 init_decl_processing ()
 {
   tree array_domain_type;
+  tree jmpbuf_domain_type;
 
   set_identifier_size (sizeof (struct tree_identifier));
 
@@ -1195,63 +1201,70 @@
   /* Define `int' and `char' first so that dbx will output them first.  */
 
   /* spec1() ensures that the type's type is itself. Needed for DBX.
+     Should only be used for atomic types.
      For the C front-end this is done in pushdecl with a kludge.  */
 
-#define spec1(type, id, node) \
+#define spec1(id, type_node) \
  { \
    tree spec1_decl; \
-   TREE_TYPE (node) = node; \
-   spec1_decl = build_decl (type, id, node); \
-   TYPE_NAME (node) = spec1_decl; \
+   TREE_TYPE (type_node) = type_node; \
+   spec1_decl = build_decl (TYPE_DECL, id, type_node); \
+   TYPE_NAME (type_node) = spec1_decl; \
+   TYPE_STUB_DECL (type_node) = spec1_decl; \
    pushdecl (spec1_decl); \
  }
 
- spec1(TYPE_DECL, ridpointers[(int) RID_INT], integer_type_node);
- spec1(TYPE_DECL, get_identifier ("char"), char_type_node);
- spec1(TYPE_DECL, get_identifier ("long int"), long_integer_type_node);
- spec1(TYPE_DECL, get_identifier ("unsigned int"), unsigned_type_node);
- spec1(TYPE_DECL, get_identifier ("long unsigned int"), long_unsigned_type_node);
- spec1(TYPE_DECL, get_identifier ("long long int"), long_long_integer_type_node);
- spec1(TYPE_DECL, get_identifier ("long long unsigned int"), long_long_unsigned_type_node);
- spec1(TYPE_DECL, get_identifier ("short int"), short_integer_type_node);
- spec1(TYPE_DECL, get_identifier ("short unsigned int"), short_unsigned_type_node);
- spec1(TYPE_DECL, get_identifier ("signed char"), signed_char_type_node);
- spec1(TYPE_DECL, get_identifier ("unsigned char"), unsigned_char_type_node);
- spec1(TYPE_DECL, NULL_TREE, intQI_type_node);
- spec1(TYPE_DECL, NULL_TREE, intHI_type_node);
- spec1(TYPE_DECL, NULL_TREE, intSI_type_node);
- spec1(TYPE_DECL, NULL_TREE, intDI_type_node);
+ spec1(ridpointers[(int) RID_INT], integer_type_node);
+ spec1(get_identifier ("char"), char_type_node);
+ spec1(get_identifier ("long int"), long_integer_type_node);
+ spec1(get_identifier ("unsigned int"), unsigned_type_node);
+ spec1(get_identifier ("long unsigned int"), long_unsigned_type_node);
+ spec1(get_identifier ("long long int"), long_long_integer_type_node);
+ spec1(get_identifier ("long long unsigned int"), long_long_unsigned_type_node);
+ spec1(get_identifier ("short int"), short_integer_type_node);
+ spec1(get_identifier ("short unsigned int"), short_unsigned_type_node);
+ spec1(get_identifier ("signed char"), signed_char_type_node);
+ spec1(get_identifier ("unsigned char"), unsigned_char_type_node);
+ spec1(NULL_TREE, intQI_type_node);
+ spec1(NULL_TREE, intHI_type_node);
+ spec1(NULL_TREE, intSI_type_node);
+ spec1(NULL_TREE, intDI_type_node);
 #if HOST_BITS_PER_WIDE_INT >= 64
- spec1(TYPE_DECL, NULL_TREE, intTI_type_node);
+ spec1(NULL_TREE, intTI_type_node);
 #endif
- spec1(TYPE_DECL, NULL_TREE, unsigned_intQI_type_node);
- spec1(TYPE_DECL, NULL_TREE, unsigned_intHI_type_node);
- spec1(TYPE_DECL, NULL_TREE, unsigned_intSI_type_node);
- spec1(TYPE_DECL, NULL_TREE, unsigned_intDI_type_node);
+ spec1(NULL_TREE, unsigned_intQI_type_node);
+ spec1(NULL_TREE, unsigned_intHI_type_node);
+ spec1(NULL_TREE, unsigned_intSI_type_node);
+ spec1(NULL_TREE, unsigned_intDI_type_node);
 #if HOST_BITS_PER_WIDE_INT >= 64
- spec1(TYPE_DECL, NULL_TREE, unsigned_intTI_type_node);
+ spec1(NULL_TREE, unsigned_intTI_type_node);
 #endif
   
  /* Create the widest literal types. */
   widest_integer_literal_type_node = make_signed_type (HOST_BITS_PER_WIDE_INT * 2);
   widest_unsigned_literal_type_node = make_unsigned_type (HOST_BITS_PER_WIDE_INT * 2);
-  spec1(TYPE_DECL, NULL_TREE, widest_integer_literal_type_node);
-  spec1(TYPE_DECL, NULL_TREE, widest_unsigned_literal_type_node);
+  spec1(NULL_TREE, widest_integer_literal_type_node);
+  spec1(NULL_TREE, widest_unsigned_literal_type_node);
 
   merc_int8_type_node = make_signed_type (8);
   merc_int16_type_node = make_signed_type (16);
   merc_int32_type_node = make_signed_type (32);
   merc_int64_type_node = make_signed_type (64);
   merc_intptr_type_node = make_signed_type (POINTER_SIZE);
+  spec1(get_identifier ("MR_int8_t"), merc_int8_type_node);
+  spec1(get_identifier ("MR_int16_t"), merc_int16_type_node);
+  spec1(get_identifier ("MR_int32_t"), merc_int32_type_node);
+  spec1(get_identifier ("MR_int64_t"), merc_int64_type_node);
+  spec1(get_identifier ("MR_intptr_t"), merc_intptr_type_node);
 
   set_sizetype (merc_intptr_type_node);
 
   build_common_tree_nodes_2 (merc_flag_short_double);
 
-  spec1(TYPE_DECL, ridpointers[(int) RID_FLOAT], float_type_node);
-  spec1(TYPE_DECL, ridpointers[(int) RID_DOUBLE], double_type_node);
-  spec1(TYPE_DECL, get_identifier ("long double"), long_double_type_node);
-  spec1(TYPE_DECL, ridpointers[(int) RID_VOID], void_type_node);
+  spec1(ridpointers[(int) RID_FLOAT], float_type_node);
+  spec1(ridpointers[(int) RID_DOUBLE], double_type_node);
+  spec1(get_identifier ("long double"), long_double_type_node);
+  spec1(ridpointers[(int) RID_VOID], void_type_node);
 
 #ifdef MD_INIT_BUILTINS
   MD_INIT_BUILTINS;
@@ -1271,8 +1284,7 @@
   boolean_type_node = make_node (BOOLEAN_TYPE);
   TYPE_PRECISION (boolean_type_node) = 1;
   fixup_unsigned_type (boolean_type_node);
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("boolean"),
-			boolean_type_node));
+  spec1(get_identifier ("boolean"), boolean_type_node);
   boolean_false_node = TYPE_MIN_VALUE (boolean_type_node);
   boolean_true_node = TYPE_MAX_VALUE (boolean_type_node);
 #endif
@@ -1280,6 +1292,8 @@
   string_type_node = build_pointer_type (char_type_node);
   const_string_type_node
     = build_pointer_type (build_type_variant (char_type_node, 1, 0));
+  spec1(get_identifier ("MR_String"), string_type_node);
+  spec1(get_identifier ("MR_ConstString"), const_string_type_node);
 
   /* Make a type to be the domain of a few array types
      whose domains don't really matter.
@@ -1296,8 +1310,11 @@
 
   /* The documentation in builtins.c says that __builtin_setjmp expects its
      argument to be a pointer to an array of five words.  */
-  merc_jmpbuf_type_node
-    = build_array_type (ptr_type_node, build_index_type (build_int_2 (4, 0)));
+  jmpbuf_domain_type = build_index_type (build_int_2 (4, 0));
+  spec1(get_identifier ("__builtin_jmpbuf_index"), jmpbuf_domain_type);
+  merc_jmpbuf_type_node = build_array_type (ptr_type_node, jmpbuf_domain_type);
+  spec1(get_identifier ("__builtin_jmpbuf"), merc_jmpbuf_type_node);
+  TREE_TYPE (merc_jmpbuf_type_node) = ptr_type_node;
 
   merc_init_builtin_functions ();
 
-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
                                    |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list