/* @(#) expand.c 1.2 3/15/85 17:04:29 */ /***************************************************************** C++ source for cfront, the C++ compiler front-end written in the computer science research center of Bell Labs Copyright (c) 1984 AT&T Technologies, Inc. All rigths Reserved THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T TECHNOLOGIES, INC. If you ignore this notice the ghost of Ma Bell will haunt you forever. expand.c: expand inline functions ******************************************************************/ #include "cfront.h" char* temp(char* vn, char* fn, char* cn) /* make the name of the temporary: _X_vn_fn_cn */ { if (vn[0]!='_' || vn[1]!='X') { int vnl = strlen(vn); int fnl = strlen(fn); int cnl = (cn)?strlen(cn):0; char* s = new char[vnl+fnl+cnl+6]; s[0] = '_'; s[1] = 'X'; strcpy(s+2,vn); s[vnl+2] = '_'; strcpy(s+vnl+3,fn); if (cnl) { s[vnl+fnl+3] = '_'; strcpy(s+vnl+fnl+4,cn); } return s; } else return vn; } Pname dcl_local(Ptable scope, Pname an, Pname fn) { if (scope == 0) { error('s',"cannot expand inlineF needing temporary variable in nonF context"); return an; } if (an->n_stclass == STATIC) error('s',"static%n in inlineF",an); Pname cn = fn->n_table->t_name; char* s = temp(an->string,fn->string,(cn)?cn->string:0); Pname nx = new name(s); /*error('d',"%n: %d->dcl_local(%s)",fn,scope,s); */ nx->tp = an->tp; PERM(nx->tp); nx->n_used = an->n_used; nx->n_assigned_to = an->n_assigned_to; nx->n_addr_taken = an->n_addr_taken; Pname r = scope->insert(nx,0); delete nx; return r; } Pstmt stmt.expand() /* copy the statements with the formal arguments replaced by ANAMES called once only per inline function expand_tbl!=0 if the function should be transformed into an expression and expand_tbl is the table for local variables */ { if (this == 0) error('i',"0->stmt.expand() for%n",expand_fn); /*error('d',"stmt %d:%k s=%d e=%d l=%d",this,base,s,e,s_list);*/ if (memtbl) { /* check for static variables */ register Ptable t = memtbl; register int i; for (register Pname n = t->get_mem(i=1); n; n=t->get_mem(++i)) if (n->n_stclass == STATIC) { error('s',"static%n in inlineF",n); n->n_stclass = AUTO; } } if (expand_tbl) { /* make expression */ Pexpr ee; if (memtbl && base!=BLOCK) { /* temporaries */ int i; Pname n; Ptable tbl = memtbl; for (n = tbl->get_mem(i=1); n; n=tbl->get_mem(++i)) { /*error('d',"%n: %n",expand_fn,n);*/ Pname nn = dcl_local(scope,n,expand_fn); nn->base = NAME; n->string = nn->string; } } switch (base) { default: error('s',"%kS in inline%n",base,expand_fn); return (Pstmt)dummy; case BLOCK: if (s_list) { ee = (Pexpr) s_list->expand(); if (s) { ee = new expr(CM, (Pexpr)s->expand(), ee); PERM(ee); } return (Pstmt) ee; } if (s) return s->expand(); return (Pstmt) zero; case PAIR: ee = s2 ? (Pexpr)s2->expand() : 0; ee = new expr(CM, s?(Pexpr)s->expand():0, ee); if (s_list) ee = new expr(CM, ee, (Pexpr)s_list->expand()); PERM(ee); return (Pstmt) ee; case RETURN: s_list = 0; return (Pstmt) e->expand(); case SM: ee = (e==0 || e->base==DUMMY) ? zero : e->expand(); if (s_list) { ee = new expr(CM, ee, (Pexpr)s_list->expand()); PERM(ee); } return (Pstmt)ee; case IF: { Pexpr qq = new expr(QUEST,(Pexpr)s->expand(),0); qq->cond = e->expand(); qq->e2 = else_stmt ? (Pexpr)else_stmt->expand() : zero; if (s_list) qq = new expr(CM,qq,(Pexpr)s_list->expand()); PERM(qq); return (Pstmt)qq; } } } switch (base) { default: if (e) e = e->expand(); break; case PAIR: if (s2) s2 = s2->expand(); break; case BLOCK: break; case FOR: if (for_init) for_init = for_init->expand(); if (e2) e2 = e2->expand(); break; case LABEL: case GOTO: case RETURN: case BREAK: case CONTINUE: error('s',"%kS in inline%n",base,expand_fn); } if (s) s = s->expand(); if (s_list) s_list = s_list->expand(); PERM(this); return this; } Pexpr expr.expand() { if (this == 0) error('i',"expr.expand(0)"); /*fprintf(stderr,"%s(): expr %d: b=%d e1=%d e2=%d\n",expand_fn->string,this,base,e1,e2); fflush(stderr);*/ switch (base) { case NAME: if (expand_tbl && ((Pname)this)->n_scope==FCT) { Pname n = (Pname)this; char* s = n->string; if (s[0]=='_' && s[1]=='X') break; Pname cn = expand_fn->n_table->t_name; n->string = temp(s,expand_fn->string,(cn)?cn->string:0); } case DUMMY: case ICON: case FCON: case CCON: case IVAL: case FVAL: case LVAL: case STRING: case ZERO: case SIZEOF: case TEXT: case ANAME: break; case ICALL: if (expand_tbl && e1==0) { Pname fn = il->fct_name; Pfct f = (Pfct)fn->tp; if (f->returns==void_type && fn->n_oper!=CTOR) error('s',"non-value-returning inline%n called in value-returning inline%n",fn,expand_fn); else error("inline%n called before defined",fn); } break; case QUEST: cond = cond->expand(); default: if (e2) e2 = e2->expand(); case REF: case DOT: if (e1) e1 = e1->expand(); break; case CAST: PERM(tp2); e1 = e1->expand(); break; } PERM(this); return this; } bit expr.not_simple() /* is a temporary variable needed to hold the value of this expression as an argument for an inline expansion? return 1; if side effect return 2; if modifies expression */ { int s; /*error('d',"not_simple%k",base);*/ switch (base) { default: return 2; case ZERO: case IVAL: case FVAL: case ICON: case CCON: case FCON: case STRING: case NAME: /* unsafe (alias) */ return 0; case SIZEOF: return e1==dummy?0:e1->not_simple(); case G_ADDROF: case ADDROF: return e2->not_simple(); case CAST: case DOT: case REF: return e1->not_simple(); case UMINUS: case NOT: case COMPL: return e2->not_simple(); case DEREF: s = e1->not_simple(); if (1<s) return 2; if (e2==0) return s; return s |= e2->not_simple(); case MUL: case DIV: case MOD: case PLUS: case MINUS: case LS: case RS: case AND: case OR: case ER: case LT: case LE: case GT: case GE: case EQ: case NE: case ANDAND: case OROR: case CM: s = e1->not_simple(); if (1<s) return 2; return s |= e2->not_simple(); case QUEST: s = cond->not_simple(); if (1<s) return 2; s |= e1->not_simple(); if (1<s) return 2; return s |= e2->not_simple(); case ANAME: if (curr_icall) { Pname n = (Pname)this; int argno = n->n_val; Pin il; for (il=curr_icall; il; il=il->i_next) if (n->n_table == il->i_table) goto aok; goto bok; aok: return (il->local[argno]) ? 0 : il->arg[argno]->not_simple(); } bok: error('i',"expand aname%n",this); case VALUE: case NEW: case CALL: case G_CALL: case ICALL: case ASSIGN: case INCR: case DECR: case ASPLUS: case ASMINUS: case ASMUL: case ASDIV: case ASMOD: case ASAND: case ASOR: case ASER: case ASLS: case ASRS: return 2; } } Pexpr fct.expand(Pname fn, Ptable scope, Pexpr ll) /* expand call to (previously defined) inline function in "scope" with the argument list "ll" (1) declare variables in "scope" (2) initialize argument variables (3) link to body */ { //error('d',"expand%n inline=%d body %d defined %d f_expr %d last_exp=%d curr_expr=%d",fn,f_inline,body,defined ,f_expr,last_expanded,curr_expr); if ((body==0 && f_expr==0) // before defined || ((defined&SIMPLIFIED)==0) // before simplified || (Pfct(fn->tp)->body->memtbl==scope) // while defining || (f_inline==2) // recursive call || (last_expanded && last_expanded==curr_expr) // twice in an expression ) { fn->take_addr(); /* so don't expand */ if (fn->n_addr_taken == 1) { Pname nn = new name; /* but declare it */ *nn = *fn; nn->n_list = dcl_list; nn->n_sto = STATIC; dcl_list = nn; } return 0; } f_inline = 2; Pin il = new iline; Pexpr ic = new texpr(ICALL,0,0); il->fct_name = fn; ic->il = il; ic->tp = returns; Pname n; Pname at = (f_this) ? f_this : argtype; if (at) il->i_table = at->n_table; int i = 0; int not_simple = 0; /* is a temporary argument needed? */ for (n=at; n; n=n->n_list, i++) { /* check formal/actual argument pairs and generate temporaries as necessary */ if (ll == 0) error('i',"simpl.call:AX for %n",fn); Pexpr ee; if (ll->base == ELIST) { ee = ll->e1; ll = ll->e2; } else { ee = ll; ll = 0; } int s; /* could be avoided when expanding into a block */ //error('d',"n=%n addr %d ass %d used %d ee %k => %d",n,n->n_addr_taken,n->n_assigned_to,n->n_used,ee->base,ee->not_simple()); if (n->n_assigned_to == FUDGE111) { /* constructor's this */ if (ee != zero) { /* automatic or static then we can use the actual variable */ il->local[i] = 0; goto zxc; } } if (n->n_addr_taken || n->n_assigned_to) { Pname nn = dcl_local(scope,n,fn); nn->base = NAME; il->local[i] = nn; ++not_simple; } else if (n->n_used && (s=ee->not_simple()) && (1<s || 1<n->n_used) ) { /* not safe */ Pname nn = dcl_local(scope,n,fn); nn->base = NAME; il->local[i] = nn; ++not_simple; } else il->local[i] = 0; zxc: il->arg[i] = ee; il->tp[i] = n->tp; } Ptable tbl = body->memtbl; if (f_expr) { /* generate comma expression */ char loc_var = 0; /* look for local variables needing declaration: */ //error('d',"fn%n tbl %d",fn,tbl); for (n=tbl->get_mem(i=1); n; n=tbl->get_mem(++i) ) { //error('d',"?%s: b=%d u%d =%d &=%d",n->string,n->base,n->n_used,n->n_assigned_to,n->n_addr_taken); if (n->base==NAME && (n->n_used||n->n_assigned_to||n->n_addr_taken)) { Pname nn = dcl_local(scope,n,fn); nn->base = NAME; n->string = nn->string; loc_var++; } } /*error('d',"not_simple=%d loc_var=%d last_expanded=%d curr_expr=%d",not_simple,loc_var,last_expanded,curr_expr);*/ if (not_simple || loc_var) last_expanded = curr_expr; Pexpr ex; if (not_simple) { Pexpr etail = ex = new expr(CM,0,0); for (i=0; i<MIA; i++) { Pname n = il->local[i]; if (n==0) continue; Pexpr e = il->arg[i]; etail->e1 = new expr(ASSIGN,n,e); /*error('d',"%n = %k",n,e->base);*/ if (--not_simple) etail = etail->e2 = new expr(CM,0,0); else break; } etail->e2 = f_expr; } else { ex = f_expr; } ic->e1 = ex; } else { /* generate block: */ for (n=tbl->get_mem(i=1); n; n=tbl->get_mem(++i) ) { // mangle local names //error('d',"?%s: b=%d u%d =%d &=%d",n->string,n->base,n->n_used,n->n_assigned_to,n->n_addr_taken); if (n->base==NAME && (n->n_used||n->n_assigned_to||n->n_addr_taken)) { Pname cn = fn->n_table->t_name; n->string = temp(n->string,fn->string,(cn)?cn->string:0); } } Pstmt ss; if (not_simple) { last_expanded = curr_expr; Pstmt st = new estmt(SM,curloc,0,0); Pstmt stail = st; for (i=0; i<MIA; i++) { Pname n = il->local[i]; if (n == 0) continue; Pexpr e = il->arg[i]; stail->e = new expr(ASSIGN,n,e); if (--not_simple) stail = stail->s_list = new estmt(SM,curloc,0,0); else break; } stail->s_list = body; ss = new block(curloc,0,st); } else { ss = body; } ic->e2 = (Pexpr)ss; } f_inline = 1; return ic; }