PIPS
return.c
Go to the documentation of this file.
1 /*
2 
3  $Id: return.c 23065 2016-03-02 09:05:50Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of PIPS.
8 
9  PIPS is free software: you can redistribute it and/or modify it
10  under the terms of the GNU General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  any later version.
13 
14  PIPS is distributed in the hope that it will be useful, but WITHOUT ANY
15  WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  FITNESS FOR A PARTICULAR PURPOSE.
17 
18  See the GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with PIPS. If not, see <http://www.gnu.org/licenses/>.
22 
23 */
24 #ifdef HAVE_CONFIG_H
25  #include "pips_config.h"
26 #endif
27 /* Handling of RETURN statements and substitution of alternate returns.
28  *
29  * Most of the code deals with alternate returns. Functions GenerateReturn()
30  * and MakeReturn() are sufficient to process regular RETURN statements.
31  *
32  * Francois Irigoin
33  */
34 
35 #include <stdio.h>
36 
37 #include "genC.h"
38 #include "parser_private.h"
39 #include "linear.h"
40 #include "ri.h"
41 #include "ri-util.h"
42 #include "misc.h"
43 #include "properties.h"
44 
45 #include "syntax.h"
46 ␌
47 /* Should alternate returns be substituted or not ?
48  *
49  * If alternate returns are substituted, the code declarations should be
50  * regenerated unless hide_rc_p is true and some PIPS run-time Fortran
51  * functions provided. The corresponding property should be checked. */
52 static bool substitute_rc_p = false;
53 static bool substitute_stop_p = false;
54 static bool hide_rc_p = false;
55 #define GET_RC_PREFIX "GET_"
56 #define SET_RC_PREFIX "SET_"
57 
58 void
59 SubstituteAlternateReturns(const char* option)
60 {
61  substitute_rc_p = (strcmp(option, "RC")==0) || (strcmp(option, "HRC")==0) ;
62  hide_rc_p = (strcmp(option, "HRC")==0) ;
63  substitute_stop_p = (strcmp(option, "STOP")==0);
64 
65  if(!(substitute_rc_p || substitute_stop_p || strcmp(option, "NO")==0)) {
66  user_log("Unknown option \"%s\" for property "
67  "PARSER_SUBSTITUTE_ALTERNATE_RETURNS.\n"
68  "Three options are available for alternate return handling: "
69  "\"NO\", \"RC\" and \"STOP\"\n", option);
70  ParserError("SubstituteAlternateReturns", "Illegal property value");
71  }
72 
74  && !get_bool_property("PRETTYPRINT_ALL_DECLARATIONS"))
75  user_warning("SubstituteAlternateReturns",
76  "Module declarations should be regenerated."
77  " Set property PRETTYPRINT_ALL_DECLARATIONS.\n");
78 }
79 
80 bool
82 {
83  return substitute_rc_p;
84 }
85 
86 ␌
87 /* Variable used to carry return code replacing the alternate returns
88  *
89  * This variable may be either a formal parameter if the module uses
90  * alternate returns, or a dynamic variable if it uses such a module.
91  * When both conditions are true, the return code is a formal parameter.
92  */
94 
96 {
97  const char* rc_name = get_string_property("PARSER_RETURN_CODE_VARIABLE");
98  /* Cannot be asserted because the return_code_variable may either be a
99  * formal parameter if the current module uses multiple return, or
100  * a dynamic variable if it does not and if it calls a subroutine
101  * using alternate returns
102  */
103  /*
104  pips_assert("entity return_code_variable is undefined",
105  entity_undefined_p(return_code_variable));
106  */
110  }
111 
112  return return_code_variable;
113 }
114 
116 {
118 
119  /* Type, storage and initial value may have been set up earlier in
120  MakeFormalParameter(). */
121  if(type_undefined_p(entity_type(rc))) {
122  /* We must be dealing with the actual variable, not with the formal
123  variable. */
124  const char* module_name = get_current_module_name();
127 
129 
130  entity_storage(rc) =
132  make_ram(f, a,
133  add_variable_to_area(a, rc),
134  NIL));
135 
137  }
138 
139  pips_assert("rc is defined", !entity_undefined_p(rc));
140 
141  return rc;
142 }
143 
144 bool
146 {
147  return rcv == return_code_variable;
148 }
149 
150 void
152 {
154 }
155 
156 ␌
157 /* Remember if the current module uses alternate returns. If yes,
158  * the RETURN statements must include an assignment to the return code
159  * variable.
160  */
162 /* The current number of alternate returns is used to process a module
163  declaration */
165 
167 {
169 }
170 
171 void uses_alternate_return(bool use)
172 {
173  if(use && strcmp(get_string_property("PARSER_SUBSTITUTE_ALTERNATE_RETURNS"), "NO")==0) {
175  ("Lines %d-%d: Alternate return not processed with current option \"%s\". "
176  "Formal label * ignored.\n"
177  "See property PARSER_SUBSTITUTE_ALTERNATE_RETURNS for other options\n",
178  line_b_I, line_e_I, get_string_property("PARSER_SUBSTITUTE_ALTERNATE_RETURNS"));
179  ParserError("uses_alternate_return", "Alternate returns prohibited by user\n");
180  }
181 
183 
185 }
186 
188 {
190 }
191 
193 {
195 }
196 
198 {
200 }
201 
202 ␌
203 /* Update the formal and actual parameter lists by adding the return code
204  * variable as last argument.
205  *
206  * To avoid an explicit check in gram.y which is large enough, the additions
207  * are conditional to the alternate return substitution.
208  */
210 {
211  list new_fpl = fpl;
212 
215 
216  /* Type, storage and initial value are set up later in MakeFormalParameter() */
217  new_fpl = gen_nconc(fpl, CONS(ENTITY, frc, NIL));
218  }
219  return new_fpl;
220 }
221 
223 {
224  list new_apl = apl;
225 
228 
229  new_apl = gen_nconc(apl, CONS(EXPRESSION, entity_to_expression(frc), NIL));
230  }
231 
232  return new_apl;
233 }
234 ␌
235 /* Keep track of the labels used as actual arguments for alternate returns
236  * and generate the tests to check the return code.
237  */
238 
240 
241 void
242 add_alternate_return(string label_name)
243 {
245 
246  if(substitute_rc_p) {
247  l = MakeLabel(label_name);
249  }
250  else {
251  pips_user_warning("Lines %d-%d: Alternate return towards label %s not supported. "
252  "Actual label argument internally substituted by a character string.\n",
253  line_b_I, line_e_I, label_name);
254  }
255 }
256 
257 list
259 {
260  return alternate_returns;
261 }
262 
263 void
265 {
266  pips_assert("alternate return list is undefined", list_undefined_p(alternate_returns));
269 }
270 
271 void
273 {
274  pips_assert("alternate return list is defined", !list_undefined_p(alternate_returns));
278 }
279 
280 /* ParserError() cannot guess if it has been performed or not, because it
281  is reinitialized before and after each call statement. If the error
282  occurs within a call, alternate returns must be reset. Else they should
283  not be reset.*/
285 {
288  }
289 }
290 ␌
292 {
295  string get_rc_name = strdup(concatenate(GET_RC_PREFIX,
296  get_string_property("PARSER_RETURN_CODE_VARIABLE"),
297  NULL));
298  entity get_rc = FindEntity(TOP_LEVEL_MODULE_NAME, get_rc_name);
299 
300  if(entity_undefined_p(get_rc)) {
301  get_rc = FindOrCreateEntity(TOP_LEVEL_MODULE_NAME, get_rc_name);
302  /* get_rc takes an argument and returns void */
303  entity_type(get_rc) =
308  NIL,NIL)),
311  NIL),
313  /*
314  entity_type(get_rc) =
315  make_type(is_type_functional,
316  make_functional(NIL,
317  make_type(is_type_variable,
318  make_variable(make_basic(is_basic_int, (value) 4),
319  NIL,NIL))));
320  */
323  update_called_modules(get_rc);
324  }
325 
326  pips_assert("Function get_rc is defined", !entity_undefined_p(get_rc));
327 
329  make_call(get_rc, CONS(EXPRESSION, rc_ref, NIL)));
330  s_get = instruction_to_statement(i_get);
332 
333  return s_get;
334 }
335 
336 
338 {
340  list lln = NIL;
343 
344  pips_assert("The label list is not empty", !ENDP(labels));
345 
346 
347 
348  ercv = entity_to_expression(rcv);
349 
350  FOREACH(ENTITY, l, labels) {
351  lln = CONS(STRING, (char*)label_local_name(l), lln);
352  }
353 
354  i = MakeComputedGotoInst(lln, ercv);
355 
356  /* The reset is controlled from gram.y, as is the set */
357  /* reset_alternate_returns(); */
358  gen_free_list(lln);
359 
361 
362  if(hide_rc_p) {
364 
365  /* ifdebug(2) { */
366  /* pips_debug(2, "Additional statement generated for hide_rc_p:\n"); */
367  /* print_statement(s_init_rcv); */
368  /* } */
369  pips_assert("i is a sequence", instruction_block_p(i));
370  instruction_block(i) = CONS(STATEMENT, s_init_rcv, instruction_block(i));
372  }
373 
374  return i;
375 }
376 
377 ␌
378 /* This function creates a goto instruction to label end_label. This is
379  * done to eliminate return statements.
380  *
381  * Note: I was afraid the mouse trap would not work to analyze
382  * multiple procedures but there is no problem. I guess that MakeGotoInst()
383  * generates the proper label entity regardless of end_label. FI.
384  */
385 
388 
390 {
391  string set_rc_name = strdup(concatenate(SET_RC_PREFIX,
392  get_string_property("PARSER_RETURN_CODE_VARIABLE"),
393  NULL));
394  entity set_rc = FindEntity(TOP_LEVEL_MODULE_NAME, set_rc_name);
395 
396  if(entity_undefined_p(set_rc)) {
397  set_rc = FindOrCreateEntity(TOP_LEVEL_MODULE_NAME, set_rc_name);
398  /* set_rc takes no argument and returns a scalar int */
399  entity_type(set_rc) =
404  NIL,NIL)),
407  NIL),
411  update_called_modules(set_rc);
412  }
413 
414  pips_assert("Function set_rc is defined", !entity_undefined_p(set_rc));
415 
416  return set_rc;
417 }
418 
419 /* The return code may be directly assigned or indirectly through a PIPS
420  run-time function call.*/
422 {
425 
426  if(hide_rc_p) {
429  CONS(EXPRESSION, rc, NIL)));
430 
432  }
433  else {
435  }
436 
437  /* ifdebug(2) { */
438  /* pips_debug(2, "Statement generated: "); */
439  /* print_statement(src); */
440  /* } */
441 
442  return src;
443 }
444 
446 {
448 
450  user_error("MakeReturn",
451  "Lines %d-%d: Alternate return not supported. "
452  "Standard return generated\n",
454  }
455 
456  if (end_label == entity_undefined) {
458  }
459 
461  /* Assign e to the return code variable, but be sure not to count
462  * this assignment as a user instruction. Wrap if with the Go To
463  * in a block and return the block instruction.
464  *
465  * See how code is synthesized for computed goto's...
466  */
469 
472  // (void) get_next_statement_number();
475  }
477  /* Let's try to provide more useful information to the user */
478  /* inst = MakeZeroOrOneArgCallInst("STOP", e); */
479  if(expression_call_p(e)) {
480  const char* mn = get_current_module_name();
482 
484  ("STOP",
485  MakeCharacterConstantExpression(strdup(concatenate("\"", sn, " in ", mn, "\"", NULL))));
486  }
487  else {
488  pips_internal_error("unexpected argument type for RETURN");
489  }
490  }
491  else {
493  }
494 
495  return inst;
496 }
497 
498 /* Generate a unique call to RETURN per module */
500 {
502  /* statement c = MakeStatement(l, make_continue_instruction()); */
503 
504 
511 
514  /*
515  statement_number(jmp) = get_statement_number();
516  (void) get_next_statement_number();
517  */
520  }
521  else {
522  strcpy(lab_I, end_label_local_name);
524  }
525 
526  LinkInstToCurrentBlock(inst, true);
527 }
void user_log(const char *format,...)
Definition: message.c:234
bool instruction_consistent_p(instruction p)
Definition: ri.c:1124
functional make_functional(list a1, type a2)
Definition: ri.c:1109
call make_call(entity a1, list a2)
Definition: ri.c:269
value make_value_unknown(void)
Definition: ri.c:2847
parameter make_parameter(type a1, mode a2, dummy a3)
Definition: ri.c:1495
mode make_mode(enum mode_utype tag, void *val)
Definition: ri.c:1350
basic make_basic(enum basic_utype tag, void *val)
Definition: ri.c:155
storage make_storage(enum storage_utype tag, void *val)
Definition: ri.c:2273
ram make_ram(entity a1, entity a2, intptr_t a3, list a4)
Definition: ri.c:1999
value make_value(enum value_utype tag, void *val)
Definition: ri.c:2832
variable make_variable(basic a1, list a2, list a3)
Definition: ri.c:2895
instruction make_instruction(enum instruction_utype tag, void *val)
Definition: ri.c:1166
dummy make_dummy_unknown(void)
Definition: ri.c:617
type make_type(enum type_utype tag, void *val)
Definition: ri.c:2706
cons * arguments_add_entity(cons *a, entity e)
Definition: arguments.c:85
#define LOCAL
Definition: bootstrap.c:84
expression MakeCharacterConstantExpression(string s)
END_EOLE.
Definition: constant.c:573
const char * module_name(const char *s)
Return the module part of an entity name.
Definition: entity_names.c:296
char * get_string_property(const char *)
bool get_bool_property(const string)
FC 2015-07-20: yuk, moved out to prevent an include cycle dependency include "properties....
#define STRING(x)
Definition: genC.h:87
statement instruction_to_statement(instruction)
Build a statement from a give instruction.
Definition: statement.c:597
const char * get_current_module_name(void)
Get the name of the current module.
Definition: static.c:121
instruction make_instruction_block(list statements)
Build an instruction block from a list of statements.
Definition: instruction.c:106
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
#define list_undefined_p(c)
Return if a list is undefined.
Definition: newgen_list.h:75
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
#define CONS(_t_, _i_, _l_)
List element cell constructor (insert an element at the beginning of a list)
Definition: newgen_list.h:150
list gen_nconc(list cp1, list cp2)
physically concatenates CP1 and CP2 but do not duplicates the elements
Definition: list.c:344
void gen_free_list(list l)
free the spine of the list
Definition: list.c:327
#define FOREACH(_fe_CASTER, _fe_item, _fe_list)
Apply/map an instruction block on all the elements of a list.
Definition: newgen_list.h:179
#define list_undefined
Undefined list definition :-)
Definition: newgen_list.h:69
statement make_assign_statement(expression, expression)
Definition: statement.c:583
#define src(name, suf)
HPFC by Fabien Coelho, May 1993 and later...
Definition: compile.c:41
#define pips_user_warning
Definition: misc-local.h:146
#define pips_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
#define pips_internal_error
Definition: misc-local.h:149
#define user_error(fn,...)
Definition: misc-local.h:265
#define user_warning(fn,...)
Definition: misc-local.h:262
#define RETURN_LABEL_NAME
Definition: naming-local.h:106
#define DYNAMIC_AREA_LOCAL_NAME
Definition: naming-local.h:69
#define TOP_LEVEL_MODULE_NAME
Module containing the global variables in Fortran and C.
Definition: naming-local.h:101
string concatenate(const char *,...)
Return the concatenation of the given strings.
Definition: string.c:183
#define UU
Definition: newgen_types.h:98
int f(int off1, int off2, int n, float r[n], float a[n], float b[n])
Definition: offsets.c:15
void update_called_modules(entity e)
Definition: procedure.c:308
int get_statement_number()
eturn the line number of the statement being parsed
Definition: reader.c:1392
#define instruction_block_p(i)
#define instruction_block(i)
entity FindEntity(const char *package, const char *name)
Retrieve an entity from its package/module name and its local name.
Definition: entity.c:1503
const char * entity_local_name(entity e)
entity_local_name modified so that it does not core when used in vect_fprint, since someone thought t...
Definition: entity.c:453
entity FindOrCreateEntity(const char *package, const char *local_name)
Problem: A functional global entity may be referenced without parenthesis or CALL keyword in a functi...
Definition: entity.c:1586
entity local_name_to_top_level_entity(const char *n)
This function try to find a top-level entity from a local name.
Definition: entity.c:1450
const char * label_local_name(entity e)
END_EOLE.
Definition: entity.c:604
bool expression_call_p(expression e)
Definition: expression.c:415
expression entity_to_expression(entity e)
if v is a constant, returns a constant call.
Definition: expression.c:165
expression int_to_expression(_int i)
transform an int into an expression and generate the corresponding entity if necessary; it is not cle...
Definition: expression.c:1188
int add_variable_to_area(entity, entity)
Definition: variable.c:1376
type MakeTypeVariable(basic, cons *)
BEGIN_EOLE.
Definition: type.c:116
@ is_basic_int
Definition: ri.h:571
#define code_undefined
Definition: ri.h:757
#define call_function(x)
Definition: ri.h:709
#define ENTITY(x)
ENTITY.
Definition: ri.h:2755
@ is_mode_reference
Definition: ri.h:1676
#define entity_storage(x)
Definition: ri.h:2794
@ is_value_code
Definition: ri.h:3031
#define EXPRESSION(x)
EXPRESSION.
Definition: ri.h:1217
#define instruction_undefined
Definition: ri.h:1454
@ is_storage_rom
Definition: ri.h:2494
@ is_storage_ram
Definition: ri.h:2492
#define type_undefined_p(x)
Definition: ri.h:2884
#define entity_undefined_p(x)
Definition: ri.h:2762
#define entity_undefined
Definition: ri.h:2761
#define expression_undefined
Definition: ri.h:1223
@ is_instruction_call
Definition: ri.h:1474
#define PARAMETER(x)
PARAMETER.
Definition: ri.h:1788
#define syntax_call(x)
Definition: ri.h:2736
#define expression_undefined_p(x)
Definition: ri.h:1224
@ is_type_void
Definition: ri.h:2904
@ is_type_functional
Definition: ri.h:2901
@ is_type_variable
Definition: ri.h:2900
#define entity_type(x)
Definition: ri.h:2792
#define statement_number(x)
Definition: ri.h:2452
#define expression_syntax(x)
Definition: ri.h:1247
#define statement_undefined
Definition: ri.h:2419
#define STATEMENT(x)
STATEMENT.
Definition: ri.h:2413
#define entity_initial(x)
Definition: ri.h:2796
char * strdup()
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
int line_e_I
Definition: parser.c:68
int line_b_I
Indicates where the current instruction (in fact statement) starts and ends in the input file and giv...
Definition: parser.c:68
char lab_I[6]
Definition: parser.c:69
bool ParserError(const char *f, const char *m)
Definition: parser.c:116
void set_current_number_of_alternate_returns()
Definition: return.c:187
void soft_reset_alternate_returns()
ParserError() cannot guess if it has been performed or not, because it is reinitialized before and af...
Definition: return.c:284
static bool substitute_stop_p
Definition: return.c:53
void SubstituteAlternateReturns(const char *option)
return.c
Definition: return.c:59
static list alternate_returns
Keep track of the labels used as actual arguments for alternate returns and generate the tests to che...
Definition: return.c:239
LOCAL char * end_label_local_name
Definition: return.c:387
static entity GetFullyDefinedReturnCodeVariable()
Definition: return.c:115
bool SubstituteAlternateReturnsP()
Definition: return.c:81
void set_alternate_returns()
Definition: return.c:264
list add_actual_return_code(list apl)
Definition: return.c:222
instruction generate_return_code_checks(list labels)
Definition: return.c:337
void uses_alternate_return(bool use)
Definition: return.c:171
entity GetReturnCodeVariable()
Definition: return.c:95
static int current_number_of_alternate_returns
The current number of alternate returns is used to process a module declaration.
Definition: return.c:164
#define SET_RC_PREFIX
Definition: return.c:56
static entity return_code_variable
Variable used to carry return code replacing the alternate returns.
Definition: return.c:93
list add_formal_return_code(list fpl)
Update the formal and actual parameter lists by adding the return code variable as last argument.
Definition: return.c:209
void ResetReturnCodeVariable()
Definition: return.c:151
#define GET_RC_PREFIX
Definition: return.c:55
void GenerateReturn()
Generate a unique call to RETURN per module.
Definition: return.c:499
void add_alternate_return(string label_name)
Definition: return.c:242
static statement make_set_rc_statement(expression e)
The return code may be directly assigned or indirectly through a PIPS run-time function call.
Definition: return.c:421
bool ReturnCodeVariableP(entity rcv)
Definition: return.c:145
bool uses_alternate_return_p()
Definition: return.c:166
static entity set_rc_function()
Definition: return.c:389
static bool hide_rc_p
Definition: return.c:54
void reset_alternate_returns()
Definition: return.c:272
LOCAL entity end_label
This function creates a goto instruction to label end_label.
Definition: return.c:386
list get_alternate_returns()
Definition: return.c:258
static bool substitute_rc_p
Handling of RETURN statements and substitution of alternate returns.
Definition: return.c:52
instruction MakeReturn(expression e)
Definition: return.c:445
int get_current_number_of_alternate_returns()
Definition: return.c:197
void reset_current_number_of_alternate_returns()
Definition: return.c:192
static bool current_module_uses_alternate_returns
Remember if the current module uses alternate returns.
Definition: return.c:161
static statement make_get_rc_statement(expression rc_ref)
Definition: return.c:291
statement MakeStatement(entity l, instruction i)
This function makes a statement.
Definition: statement.c:431
instruction MakeZeroOrOneArgCallInst(char *s, expression e)
this function creates a simple Fortran statement such as RETURN, CONTINUE, ...
Definition: statement.c:669
entity MakeLabel(char *s) const
This functions creates a label.
Definition: statement.c:257
instruction MakeComputedGotoInst(list ll, expression e)
Definition: statement.c:727
instruction MakeGotoInst(string n)
this function creates a goto instruction.
Definition: statement.c:686
void LinkInstToCurrentBlock(instruction i, bool number_it)
this function links the instruction i to the current block of statements.
Definition: statement.c:529