This patch splits the instantiation process for generic functions into two
parts. The first stage instantiates information about the formal arguments
and return type, and the second stage instantiates the body and other
information that wasn't required to determine if a generic is the best
candidate for a call site.
This results in the compiler doing less work and requiring less memory, as
it no longer has to deal with function bodies that will never be the target
of a call site. In addition, this work is required to allow the
implementation of constrained generics.
- Chris
diff --git a/compiler/AST/symbol.cpp b/compiler/AST/symbol.cpp
index 6b6a0c4..23dc36b 100644
--- a/compiler/AST/symbol.cpp
+++ b/compiler/AST/symbol.cpp
@@ -22,6 +22,8 @@
#include "codegen.h"
+#include "view.h"
+
//
// The function that represents the compiler-generated entry point
//
@@ -1203,7 +1205,9 @@ FnSymbol::FnSymbol(const char* initName) :
userString(NULL),
valueFunction(NULL),
codegenUniqueNum(1),
- doc(NULL)
+ doc(NULL),
+ partialCopySource(NULL),
+ retSymbol(NULL)
{
substitutions.clear();
gFnSymbols.add(this);
@@ -1268,10 +1272,164 @@ FnSymbol::copyInner(SymbolMap* map) {
copy->_outer = _outer;
copy->instantiatedFrom = instantiatedFrom;
copy->instantiationPoint = instantiationPoint;
+
return copy;
}
+FnSymbol* FnSymbol::partialCopy(SymbolMap* map) {
+ FnSymbol* newFn = new FnSymbol(this->name);
+
+ newFn->copyFlags(this);
+
+ for_formals(formal, this) {
+ newFn->insertFormalAtTail(COPY_INT(formal->defPoint));
+ }
+
+ newFn->partialCopySource = this;
+ newFn->astloc = this->astloc;
+ newFn->retType = this->retType;
+ newFn->thisTag = this->thisTag;
+ newFn->cname = this->cname;
+ newFn->_outer = this->_outer;
+ newFn->retTag = this->retTag;
+ newFn->instantiatedFrom = this->instantiatedFrom;
+ newFn->instantiationPoint = this->instantiationPoint;
+ newFn->numPreTupleFormals = this->numPreTupleFormals;
+
+ if (this->_this == NULL) {
+ newFn->_this = NULL;
+
+ } else if (Symbol* replacementThis = map->get(this->_this)) {
+ // Handles case where _this comes from the function's formal arguments.
+ newFn->_this = replacementThis;
+
+ } else {
+ // Creates a new _this for when the symbol comes from the function's body.;
+ newFn->_this = this->_this->copy(map);
+ newFn->_this->defPoint = new DefExpr(newFn->_this,
+ COPY_INT(this->_this->defPoint->init),
+ COPY_INT(this->_this->defPoint->exprType));
+ }
+
+ if (this->where != NULL) {
+ newFn->where = COPY_INT(this->where);
+ insert_help(newFn->where, NULL, newFn);
+ }
+
+ if (this->retExprType != NULL) {
+ newFn->retExprType = COPY_INT(this->retExprType);
+ insert_help(newFn->retExprType, NULL, newFn);
+ }
+
+ if (this->getReturnSymbol() == gVoid) {
+ newFn->retSymbol = gVoid;
+
+ } else if (this->getReturnSymbol() == this->_this) {
+ newFn->retSymbol = newFn->_this;
+
+ } else {
+
+ if (Symbol* replacementRet = map->get(this->getReturnSymbol())) {
+ newFn->retSymbol = replacementRet;
+
+ } else {
+ newFn->retSymbol = COPY_INT(this->getReturnSymbol());
+
+ newFn->retSymbol->defPoint = new DefExpr(newFn->retSymbol,
+ COPY_INT(this->getReturnSymbol()->defPoint->init),
+ COPY_INT(this->getReturnSymbol()->defPoint->exprType));
+
+ update_symbols(newFn->retSymbol, map);
+ }
+ }
+
+ map->put(this, newFn);
+ update_symbols(newFn, map);
+
+ newFn->partialCopyMap.copy(*map);
+ newFn->addFlag(FLAG_PARTIAL_COPY);
+
+ return newFn;
+}
+
+void FnSymbol::finalizeCopy(void) {
+ if (this->hasFlag(FLAG_PARTIAL_COPY)) {
+
+ this->partialCopySource->finalizeCopy();
+
+ SET_LINENO(this);
+
+ SymbolMap* map = &(this->partialCopyMap);
+
+ this->setter = COPY_INT(this->partialCopySource->setter);
+
+ if (this->hasFlag(FLAG_EXPANDED_VARARGS)) {
+ BlockStmt* varArgNodes = this->body;
+ this->body = COPY_INT(this->partialCopySource->body);
+
+ for_alist_backward(node, varArgNodes->body) {
+ remove_help(node, false);
+ node->list = NULL;
+ this->body->insertAtHead(node);
+ }
+
+ // Clean up blocks that aren't going to be used any more.
+ gBlockStmts.remove(gBlockStmts.index(varArgNodes));
+ delete varArgNodes;
+
+ this->removeFlag(FLAG_EXPANDED_VARARGS);
+
+ } else if (this->body->body.length == 0) {
+ gBlockStmts.remove(gBlockStmts.index(this->body));
+ delete this->body;
+
+ this->body = COPY_INT(this->partialCopySource->body);
+ }
+
+ // this->partialCopySource->_this := A
+ // this->_this := B
+ // Case 1: A -> B
+ // Case 2: A -> C
+ Symbol* replacementThis = map->get(this->partialCopySource->_this);
+
+ if (replacementThis != this->_this) {
+ // In Case 2.
+
+ // A -> B
+ map->put(this->partialCopySource->_this, this->_this);
+ // C -> B
+ map->put(replacementThis, this->_this);
+
+ // Replace the definition of _this in the body.
+ // def(C) -> def(B)
+ replacementThis->defPoint->replace(this->_this->defPoint);
+ }
+
+ if (this->retSymbol != gVoid && this->retSymbol != this->_this) {
+ Symbol* replacementRet = map->get(this->partialCopySource->getReturnSymbol());
+
+ if (replacementRet != this->retSymbol) {
+ replacementRet->defPoint->replace(this->retSymbol->defPoint);
+
+ map->put(this->partialCopySource->getReturnSymbol(), this->retSymbol);
+ map->put(replacementRet, this->retSymbol);
+ }
+ }
+
+ this->retSymbol = NULL;
+
+ insert_help(this, this->defPoint, this->defPoint->parentSymbol);
+
+ update_symbols(this, map);
+
+ this->partialCopyMap.clear();
+ this->partialCopySource = NULL;
+ this->removeFlag(FLAG_PARTIAL_COPY);
+ }
+}
+
+
void FnSymbol::replaceChild(BaseAST* old_ast, BaseAST* new_ast) {
if (old_ast == body) {
body = toBlockStmt(new_ast);
@@ -1634,13 +1792,18 @@ FnSymbol::insertAtTail(const char* format, ...) {
Symbol*
FnSymbol::getReturnSymbol() {
- CallExpr* ret = toCallExpr(body->body.last());
- if (!ret || !ret->isPrimitive(PRIM_RETURN))
- INT_FATAL(this, "function is not normal");
- SymExpr* sym = toSymExpr(ret->get(1));
- if (!sym)
- INT_FATAL(this, "function is not normal");
- return sym->var;
+ if (this->retSymbol != NULL) {
+ return this->retSymbol;
+
+ } else {
+ CallExpr* ret = toCallExpr(body->body.last());
+ if (!ret || !ret->isPrimitive(PRIM_RETURN))
+ INT_FATAL(this, "function is not normal");
+ SymExpr* sym = toSymExpr(ret->get(1));
+ if (!sym)
+ INT_FATAL(this, "function is not normal");
+ return sym->var;
+ }
}
diff --git a/compiler/include/flags_list.h b/compiler/include/flags_list.h
index 81baf56..5d1d536 100644
--- a/compiler/include/flags_list.h
+++ b/compiler/include/flags_list.h
@@ -161,6 +161,11 @@ symbolFlag( FLAG_OMIT_FROM_CONSTRUCTOR , ypr, "omit from constructor" , ncm )
symbolFlag( FLAG_ON , npr, "on" , ncm )
symbolFlag( FLAG_ON_BLOCK , npr, "on block" , ncm )
symbolFlag( FLAG_PARAM , npr, "param" , "parameter (compile-time constant)" )
+
+symbolFlag( FLAG_PARTIAL_COPY, npr, "partial copy", ncm )
+symbolFlag( FLAG_PARTIAL_TUPLE, npr, "partial tuple", ncm)
+symbolFlag( FLAG_EXPANDED_VARARGS, npr, "expanded varargs", ncm)
+
symbolFlag( FLAG_PRIMITIVE_TYPE , ypr, "primitive type" , "attached to primitive types to keep them from being deleted" )
symbolFlag( FLAG_PRINT_MODULE_INIT_FN , ypr, "print module init fn" , ncm )
symbolFlag( FLAG_PRINT_MODULE_INIT_INDENT_LEVEL , ypr, "print module init indent level" , ncm )
diff --git a/compiler/include/symbol.h b/compiler/include/symbol.h
index 0689014..4cb0e49 100644
--- a/compiler/include/symbol.h
+++ b/compiler/include/symbol.h
@@ -219,6 +219,11 @@ class FnSymbol : public Symbol {
// resolve and used in cullOverReferences)
int codegenUniqueNum;
const char *doc;
+
+ SymbolMap partialCopyMap;
+ FnSymbol* partialCopySource;
+ Symbol* retSymbol;
+ int numPreTupleFormals;
FnSymbol(const char* initName);
~FnSymbol();
@@ -227,7 +232,10 @@ class FnSymbol : public Symbol {
DECLARE_SYMBOL_COPY(FnSymbol);
FnSymbol* getFnSymbol(void);
void replaceChild(BaseAST* old_ast, BaseAST* new_ast);
-
+
+ FnSymbol* partialCopy(SymbolMap* map);
+ void finalizeCopy(void);
+
// Returns an LLVM type or a C-cast expression
GenRet codegenFunctionType(bool forHeader);
GenRet codegenCast(GenRet fnPtr);
diff --git a/compiler/resolution/functionResolution.cpp b/compiler/resolution/functionResolution.cpp
index ad55d96..1e4c3e9 100644
--- a/compiler/resolution/functionResolution.cpp
+++ b/compiler/resolution/functionResolution.cpp
@@ -235,7 +235,7 @@ computeGenericSubs(SymbolMap &subs,
FnSymbol* fn,
Vec<Symbol*>& alignedActuals);
static FnSymbol*
-expandVarArgs(FnSymbol* fn, int numActuals);
+expandVarArgs(FnSymbol* origFn, int numActuals);
static void
filterCandidate(Vec<ResolutionCandidate*>& candidates,
@@ -433,8 +433,9 @@ static void makeRefType(Type* type) {
}
CallExpr* call = new CallExpr("_type_construct__ref", type->symbol);
- FnSymbol* fn = resolveUninsertedCall(type, call);
- type->refType = toAggregateType(fn->retType);
+ FnSymbol* fn = resolveUninsertedCall(type, call);
+ type->refType = toAggregateType(fn->retType);
+
type->refType->getField(1)->type = type;
if (type->symbol->hasFlag(FLAG_ATOMIC_TYPE))
@@ -1387,20 +1388,111 @@ computeGenericSubs(SymbolMap &subs,
}
-static FnSymbol*
-expandVarArgs(FnSymbol* fn, int numActuals) {
- static Map<FnSymbol*,Vec<FnSymbol*>*> cache;
+static void
+handleSymExprInExpandVarArgs(FnSymbol* workingFn, ArgSymbol* formal, SymExpr* sym) {
+ workingFn->addFlag(FLAG_EXPANDED_VARARGS);
+
+ // Handle specified number of variable arguments.
+ if (VarSymbol* n_var = toVarSymbol(sym->var)) {
+ if (n_var->type == dtInt[INT_SIZE_DEFAULT] && n_var->immediate) {
+ int n = n_var->immediate->int_value();
+ CallExpr* tupleCall = new CallExpr((formal->hasFlag(FLAG_TYPE_VARIABLE)) ?
+ "_type_construct__tuple" : "_construct__tuple");
+ for (int i = 0; i < n; i++) {
+ DefExpr* new_arg_def = formal->defPoint->copy();
+ ArgSymbol* new_formal = toArgSymbol(new_arg_def->sym);
+ new_formal->variableExpr = NULL;
+ tupleCall->insertAtTail(new SymExpr(new_formal));
+ new_formal->name = astr("_e", istr(i), "_", formal->name);
+ new_formal->cname = astr("_e", istr(i), "_", formal->cname);
+ formal->defPoint->insertBefore(new_arg_def);
+ }
+
+ VarSymbol* var = new VarSymbol(formal->name);
+
+ if (workingFn->hasFlag(FLAG_PARTIAL_COPY)) {
+ for (int index = workingFn->partialCopyMap.n; --index >= 0;) {
+ SymbolMapElem& mapElem = workingFn->partialCopyMap.v[index];
+
+ if (mapElem.value == formal) {
+ mapElem.value = var;
+ break;
+ }
+ }
+ }
+
+ if (formal->hasFlag(FLAG_TYPE_VARIABLE)) {
+ var->addFlag(FLAG_TYPE_VARIABLE);
+ }
+
+ if (formal->intent == INTENT_OUT || formal->intent == INTENT_INOUT) {
+ int i = 1;
+ for_actuals(actual, tupleCall) {
+ VarSymbol* tmp = newTemp("_varargs_tmp_");
+ workingFn->insertBeforeReturnAfterLabel(new DefExpr(tmp));
+ workingFn->insertBeforeReturnAfterLabel(new CallExpr(PRIM_MOVE, tmp, new CallExpr(var, new_IntSymbol(i))));
+ workingFn->insertBeforeReturnAfterLabel(new CallExpr(PRIM_MOVE, actual->copy(),
+ new CallExpr("=", actual->copy(), tmp)));
+ i++;
+ }
+ }
- bool genericArg = false;
- for_formals(arg, fn) {
- if (!genericArg && arg->variableExpr && !isDefExpr(arg->variableExpr->body.tail))
- resolveBlock(arg->variableExpr);
+ tupleCall->insertAtHead(new_IntSymbol(n));
+ workingFn->insertAtHead(new CallExpr(PRIM_MOVE, var, tupleCall));
+ workingFn->insertAtHead(new DefExpr(var));
+ formal->defPoint->remove();
+
+ // !!!!
+ subSymbol(workingFn->body, formal, var);
+
+ if (workingFn->where) {
+ VarSymbol* var = new VarSymbol(formal->name);
+
+ if (formal->hasFlag(FLAG_TYPE_VARIABLE)) {
+ var->addFlag(FLAG_TYPE_VARIABLE);
+ }
+
+ workingFn->where->insertAtHead(new CallExpr(PRIM_MOVE, var, tupleCall->copy()));
+ workingFn->where->insertAtHead(new DefExpr(var));
+ subSymbol(workingFn->where, formal, var);
+ }
+ }
+ }
+}
- //
- // set genericArg to true if a generic argument appears before the
- // argument with the variable expression
- //
+static FnSymbol*
+expandVarArgs(FnSymbol* origFn, int numActuals) {
+
+ bool genericArgSeen = false;
+ FnSymbol* workingFn = origFn;
+
+ SymbolMap substitutions;
+
+ static Map<FnSymbol*,Vec<FnSymbol*>*> cache;
+
+ // check for cached stamped out function
+ if (Vec<FnSymbol*>* cfns = cache.get(origFn)) {
+ forv_Vec(FnSymbol, cfn, *cfns) {
+ if (cfn->numFormals() == numActuals) return cfn;
+ }
+ }
+
+ for_formals(formal, origFn) {
+
+ if (workingFn != origFn) {
+ formal = static_cast<ArgSymbol*>(substitutions.get(formal));
+ }
+
+ if (!genericArgSeen && formal->variableExpr && !isDefExpr(formal->variableExpr->body.tail)) {
+ resolveBlock(formal->variableExpr);
+ }
+
+ /*
+ * Set genericArgSeen to true if a generic argument appears before the
+ * argument with the variable expression.
+ */
+
// INT_ASSERT(arg->type);
// Adding 'ref' intent to the "ret" arg of
// inline proc =(ref ret:syserr, x:syserr) { __primitive("=", ret, x); }
@@ -1409,97 +1501,57 @@ expandVarArgs(FnSymbol* fn, int numActuals) {
// workaround.
// A better approach would be to add a check that each formal of a function
// has a type (if that can be expected) and then fix the fault where it occurs.
- if (arg->type && arg->type->symbol->hasFlag(FLAG_GENERIC))
- genericArg = true;
+ if (formal->type && formal->type->symbol->hasFlag(FLAG_GENERIC)) {
+ genericArgSeen = true;
+ }
- if (!arg->variableExpr)
+ if (!formal->variableExpr) {
continue;
+ }
- // handle unspecified variable number of arguments
- if (DefExpr* def = toDefExpr(arg->variableExpr->body.tail)) {
-
- // check for cached stamped out function
- if (Vec<FnSymbol*>* cfns = cache.get(fn)) {
- forv_Vec(FnSymbol, cfn, *cfns) {
- if (cfn->numFormals() == numActuals)
- return cfn;
- }
- }
-
- int numCopies = numActuals - fn->numFormals() + 1;
- if (numCopies <= 0)
+ // Handle unspecified variable number of arguments.
+ if (DefExpr* def = toDefExpr(formal->variableExpr->body.tail)) {
+ int numCopies = numActuals - workingFn->numFormals() + 1;
+ if (numCopies <= 0) {
+ if (workingFn != origFn) delete workingFn;
return NULL;
+ }
- SymbolMap map;
- FnSymbol* newFn = fn->copy(&map);
- newFn->addFlag(FLAG_INVISIBLE_FN);
- fn->defPoint->insertBefore(new DefExpr(newFn));
- Symbol* sym = map.get(def->sym);
- sym->defPoint->replace(new SymExpr(new_IntSymbol(numCopies)));
-
- subSymbol(newFn, sym, new_IntSymbol(numCopies));
-
- // add new function to cache
- Vec<FnSymbol*>* cfns = cache.get(fn);
- if (!cfns)
- cfns = new Vec<FnSymbol*>();
- cfns->add(newFn);
- cache.put(fn, cfns);
-
- return expandVarArgs(newFn, numActuals);
- } else if (SymExpr* sym = toSymExpr(arg->variableExpr->body.tail)) {
-
- // handle specified number of variable arguments
- if (VarSymbol* n_var = toVarSymbol(sym->var)) {
- if (n_var->type == dtInt[INT_SIZE_DEFAULT] && n_var->immediate) {
- int n = n_var->immediate->int_value();
- CallExpr* tupleCall = new CallExpr((arg->hasFlag(FLAG_TYPE_VARIABLE)) ?
- "_type_construct__tuple" : "_construct__tuple");
- for (int i = 0; i < n; i++) {
- DefExpr* new_arg_def = arg->defPoint->copy();
- ArgSymbol* new_arg = toArgSymbol(new_arg_def->sym);
- new_arg->variableExpr = NULL;
- tupleCall->insertAtTail(new SymExpr(new_arg));
- new_arg->name = astr("_e", istr(i), "_", arg->name);
- new_arg->cname = astr("_e", istr(i), "_", arg->cname);
- arg->defPoint->insertBefore(new_arg_def);
- }
- VarSymbol* var = new VarSymbol(arg->name);
- if (arg->hasFlag(FLAG_TYPE_VARIABLE))
- var->addFlag(FLAG_TYPE_VARIABLE);
-
- if (arg->intent == INTENT_OUT || arg->intent == INTENT_INOUT) {
- int i = 1;
- for_actuals(actual, tupleCall) {
- VarSymbol* tmp = newTemp("_varargs_tmp_");
- fn->insertBeforeReturnAfterLabel(new DefExpr(tmp));
- fn->insertBeforeReturnAfterLabel(new CallExpr(PRIM_MOVE, tmp, new CallExpr(var, new_IntSymbol(i))));
- fn->insertBeforeReturnAfterLabel(new CallExpr(PRIM_MOVE, actual->copy(),
- new CallExpr("=", actual->copy(), tmp)));
- i++;
- }
- }
-
- tupleCall->insertAtHead(new_IntSymbol(n));
- fn->insertAtHead(new CallExpr(PRIM_MOVE, var, tupleCall));
- fn->insertAtHead(new DefExpr(var));
- arg->defPoint->remove();
- subSymbol(fn->body, arg, var);
- if (fn->where) {
- VarSymbol* var = new VarSymbol(arg->name);
- if (arg->hasFlag(FLAG_TYPE_VARIABLE))
- var->addFlag(FLAG_TYPE_VARIABLE);
- fn->where->insertAtHead(new CallExpr(PRIM_MOVE, var, tupleCall->copy()));
- fn->where->insertAtHead(new DefExpr(var));
- subSymbol(fn->where, arg, var);
- }
- }
+ if (workingFn == origFn) {
+ workingFn = origFn->copy(&substitutions);
+ workingFn->addFlag(FLAG_INVISIBLE_FN);
+
+ origFn->defPoint->insertBefore(new DefExpr(workingFn));
+
+ formal = static_cast<ArgSymbol*>(substitutions.get(formal));
}
- } else if (!fn->hasFlag(FLAG_GENERIC))
+ Symbol* newSym = substitutions.get(def->sym);
+ SymExpr* newSymExpr = new SymExpr(new_IntSymbol(numCopies));
+ newSym->defPoint->replace(newSymExpr);
+
+ subSymbol(workingFn, newSym, new_IntSymbol(numCopies));
+
+ handleSymExprInExpandVarArgs(workingFn, formal, newSymExpr);
+ genericArgSeen = false;
+
+ } else if (SymExpr* sym = toSymExpr(formal->variableExpr->body.tail)) {
+
+ handleSymExprInExpandVarArgs(workingFn, formal, sym);
+
+ } else if (!workingFn->hasFlag(FLAG_GENERIC)) {
INT_FATAL("bad variableExpr");
+ }
}
- return fn;
+
+ Vec<FnSymbol*>* cfns = cache.get(origFn);
+ if (cfns == NULL) {
+ cfns = new Vec<FnSymbol*>();
+ }
+ cfns->add(workingFn);
+ cache.put(origFn, cfns);
+
+ return workingFn;
}
@@ -1566,7 +1618,7 @@ filterConcreteCandidate(Vec<ResolutionCandidate*>& candidates,
* be instantiated before it is.
*/
resolveFormals(currCandidate->fn);
-
+
int coindex = -1;
for_formals(formal, currCandidate->fn) {
if (Symbol* actual = currCandidate->alignedActuals.v[++coindex]) {
@@ -1644,7 +1696,7 @@ filterGenericCandidate(Vec<ResolutionCandidate*>& candidates,
* reject it.
*/
if (currCandidate->substitutions.n > 0) {
- currCandidate->fn = instantiate(currCandidate->fn, &(currCandidate->substitutions), info.call);
+ currCandidate->fn = instantiateSignature(currCandidate->fn, currCandidate->substitutions, info.call);
if (currCandidate->fn != NULL) {
filterCandidate(candidates, currCandidate, info);
@@ -2892,11 +2944,12 @@ static void resolveNormalCall(CallExpr* call, bool errorCheck) {
ResolutionCandidate* best = disambiguateByMatch(candidates, DC);
- if (best && best->fn &&
- ((explainCallLine && explainCallMatch(call)) ||
- call->id == explainCallID))
- {
- USR_PRINT(best->fn, "best candidate is: %s", toString(best->fn));
+ if (best && best->fn) {
+ instantiateBody(best->fn);
+
+ if (explainCallLine && explainCallMatch(call)) {
+ USR_PRINT(best->fn, "best candidate is: %s", toString(best->fn));
+ }
}
if (call->partialTag && (!best || !best->fn->hasFlag(FLAG_NO_PARENS))) {
@@ -3288,10 +3341,13 @@ static void resolveMove(CallExpr* call) {
// do not resolve function return type yet
// except for constructors
- if (fn && fn->getReturnSymbol() == lhs && fn->_this != lhs)
+ if (fn && call->parentExpr != fn->where && call->parentExpr != fn->retExprType &&
+ fn->getReturnSymbol() == lhs && fn->_this != lhs) {
+
if (fn->retType == dtUnknown) {
return;
}
+ }
Type* rhsType = rhs->typeInfo();
@@ -5622,8 +5678,6 @@ resolveFns(FnSymbol* fn) {
}
}
-
-
if (fn->hasFlag(FLAG_ITERATOR_FN) && !fn->iteratorInfo) {
protoIteratorClass(fn);
}
@@ -5774,7 +5828,7 @@ addToVirtualMaps(FnSymbol* pfn, AggregateType* ct) {
}
FnSymbol* fn = cfn;
if (subs.n) {
- fn = instantiate(fn, &subs, NULL);
+ fn = instantiate(fn, subs, NULL);
if (fn) {
if (type->defaultTypeConstructor->instantiationPoint)
fn->instantiationPoint = type->defaultTypeConstructor->instantiationPoint;
diff --git a/compiler/resolution/generics.cpp b/compiler/resolution/generics.cpp
index 8e6e9d3..298430c 100644
--- a/compiler/resolution/generics.cpp
+++ b/compiler/resolution/generics.cpp
@@ -11,7 +11,6 @@
#include "stmt.h"
#include "symbol.h"
-
static int explainInstantiationLine = -2;
static ModuleSymbol* explainInstantiationModule = NULL;
@@ -94,38 +93,61 @@ copyGenericSub(SymbolMap& subs, FnSymbol* root, FnSymbol* fn, Symbol* key, Symbo
static void
-instantiate_tuple(FnSymbol* fn) {
+instantiate_tuple_signature(FnSymbol* fn) {
AggregateType* tuple = toAggregateType(fn->retType);
//
// tuple is the return type for the type constructor
// tuple is NULL for the default constructor
//
+ fn->numPreTupleFormals = fn->formals.length;
+
int64_t size = toVarSymbol(fn->substitutions.v[0].value)->immediate->int_value();
- Expr* last = fn->body->body.last();
- for (int i = 1; i <= size; i++) {
+
+ for (int i = 1; i <= size; ++i) {
const char* name = astr("x", istr(i));
- ArgSymbol* arg = new ArgSymbol(INTENT_BLANK, name, dtAny, NULL, new SymExpr(gTypeDefaultToken));
- if (tuple)
- arg->addFlag(FLAG_TYPE_VARIABLE);
- fn->insertFormalAtTail(arg);
- last->insertBefore(new CallExpr(PRIM_SET_MEMBER, fn->_this,
- new_IntSymbol(i), arg));
- if (tuple)
+ ArgSymbol* formal = new ArgSymbol(INTENT_BLANK, name, dtAny, NULL, new SymExpr(gTypeDefaultToken));
+
+ if (tuple) {
+ formal->addFlag(FLAG_TYPE_VARIABLE);
tuple->fields.insertAtTail(new DefExpr(new VarSymbol(name)));
+ }
+
+ fn->insertFormalAtTail(formal);
}
+
fn->removeFlag(FLAG_TUPLE);
+
+ fn->addFlag(FLAG_PARTIAL_TUPLE);
fn->addFlag(FLAG_ALLOW_REF);
}
+// BODY
+static void
+instantiate_tuple_body(FnSymbol* fn) {
+ Expr* last = fn->body->body.last();
+ int numPreTupleFormals = fn->numPreTupleFormals;
+
+ for (int i = numPreTupleFormals + 1; i <= fn->formals.length; ++i) {
+ ArgSymbol* formal = fn->getFormal(i);
+
+ last->insertBefore(new CallExpr(PRIM_SET_MEMBER, fn->_this, new_IntSymbol(i - numPreTupleFormals), formal));
+ }
+
+ fn->removeFlag(FLAG_PARTIAL_TUPLE);
+}
+
+
static void
instantiate_tuple_hash( FnSymbol* fn) {
- if (fn->numFormals() != 1)
+ if (fn->numFormals() != 1) {
INT_FATAL(fn, "tuple hash function has more than one argument");
+ }
ArgSymbol* arg = fn->getFormal(1);
AggregateType* ct = toAggregateType(arg->type);
CallExpr* call = NULL;
+
bool first = true;
for (int i=1; i<ct->fields.length; i++) {
CallExpr *field_access = new CallExpr( arg, new_IntSymbol(i));
@@ -141,9 +163,11 @@ instantiate_tuple_hash( FnSymbol* fn) {
new_IntSymbol(17)));
}
}
+
// YAH, make sure that we do not return a negative hash value for now
call = new CallExpr( "&", new_IntSymbol( 0x7fffffffffffffffLL, INT_SIZE_64), call);
CallExpr* ret = new CallExpr(PRIM_RETURN, new CallExpr("_cast", dtInt[INT_SIZE_64]->symbol, call));
+
fn->body->replace( new BlockStmt( ret));
normalize(fn);
}
@@ -168,22 +192,22 @@ instantiate_tuple_initCopy(FnSymbol* fn) {
static void
instantiate_tuple_autoCopy(FnSymbol* fn) {
- if (fn->numFormals() != 1)
+ if (fn->numFormals() != 1) {
INT_FATAL(fn, "tuple autoCopy function has more than one argument");
+ }
+
ArgSymbol *arg = fn->getFormal(1);
AggregateType *ct = toAggregateType(arg->type);
CallExpr *call = new CallExpr("_build_tuple_always_allow_ref");
BlockStmt* block = new BlockStmt();
+
for (int i=1; i<ct->fields.length; i++) {
Symbol* tmp = newTemp();
block->insertAtTail(new DefExpr(tmp));
-// if (ct->symbol->hasFlag(FLAG_STAR_TUPLE)) {
-// block->insertAtTail(new CallExpr(PRIM_MOVE, tmp, new CallExpr(PRIM_GET_SVEC_MEMBER_VALUE, arg, new_IntSymbol(i))));
-// } else {
block->insertAtTail(new CallExpr(PRIM_MOVE, tmp, new CallExpr(PRIM_GET_MEMBER_VALUE, arg, new_StringSymbol(astr("x", istr(i))))));
- // }
call->insertAtTail(new CallExpr("chpl__autoCopy", tmp));
}
+
block->insertAtTail(new CallExpr(PRIM_RETURN, call));
fn->body->replace(block);
normalize(fn);
@@ -362,7 +386,7 @@ static void renameInstantiatedTypeString(TypeSymbol* sym, VarSymbol* var)
}
static void
-renameInstantiatedType(TypeSymbol* sym, SymbolMap* subs, FnSymbol* fn) {
+renameInstantiatedType(TypeSymbol* sym, SymbolMap& subs, FnSymbol* fn) {
if (sym->name[strlen(sym->name)-1] == ')') {
// avoid "strange" instantiated type names based on partial instantiation
// instead of C(int,real)(imag) this results in C(int,real,imag)
@@ -377,7 +401,7 @@ renameInstantiatedType(TypeSymbol* sym, SymbolMap* subs, FnSymbol* fn) {
sym->cname = astr(sym->cname, "_");
bool first = false;
for_formals(formal, fn) {
- if (Symbol* value = subs->get(formal)) {
+ if (Symbol* value = subs.get(formal)) {
if (TypeSymbol* ts = toTypeSymbol(value)) {
if (!first && sym->hasFlag(FLAG_TUPLE)) {
if (sym->hasFlag(FLAG_STAR_TUPLE)) {
@@ -434,8 +458,8 @@ renameInstantiatedType(TypeSymbol* sym, SymbolMap* subs, FnSymbol* fn) {
FnSymbol*
-instantiate(FnSymbol* fn, SymbolMap* subs, CallExpr* call) {
- form_Map(SymbolMapElem, e, *subs) {
+instantiateSignature(FnSymbol* fn, SymbolMap& subs, CallExpr* call) {
+ form_Map(SymbolMapElem, e, subs) {
if (TypeSymbol* ts = toTypeSymbol(e->value)) {
if (ts->type->symbol->hasFlag(FLAG_GENERIC))
INT_FATAL(fn, "illegal instantiation with a generic type");
@@ -460,11 +484,15 @@ instantiate(FnSymbol* fn, SymbolMap* subs, CallExpr* call) {
// substitutions to refer to the root function's formal arguments
//
SymbolMap all_subs;
- if (fn->instantiatedFrom)
- form_Map(SymbolMapElem, e, fn->substitutions)
+ if (fn->instantiatedFrom) {
+ form_Map(SymbolMapElem, e, fn->substitutions) {
all_subs.put(e->key, e->value);
- form_Map(SymbolMapElem, e, *subs)
+ }
+ }
+
+ form_Map(SymbolMapElem, e, subs) {
copyGenericSub(all_subs, root, fn, e->key, e->value);
+ }
//
// use cached instantiation if possible
@@ -493,7 +521,7 @@ instantiate(FnSymbol* fn, SymbolMap* subs, CallExpr* call) {
if (!fn->hasFlag(FLAG_TUPLE) && newType->symbol->hasFlag(FLAG_TUPLE)) {
bool markStar = true;
Type* starType = NULL;
- form_Map(SymbolMapElem, e, *subs) {
+ form_Map(SymbolMapElem, e, subs) {
TypeSymbol* ts = toTypeSymbol(e->value);
INT_ASSERT(ts && ts->type);
if (starType == NULL) {
@@ -521,46 +549,50 @@ instantiate(FnSymbol* fn, SymbolMap* subs, CallExpr* call) {
if (newType->dispatchChildren.n)
INT_FATAL(fn, "generic type has subtypes");
newType->instantiatedFrom = fn->retType;
- newType->substitutions.map_union(*subs);
+ newType->substitutions.map_union(subs);
newType->symbol->removeFlag(FLAG_GENERIC);
}
//
// instantiate function
//
+
SymbolMap map;
-
- if (newType)
+
+ if (newType) {
map.put(fn->retType->symbol, newType->symbol);
-
- FnSymbol* newFn = fn->copy(&map);
-
+ }
+
+ FnSymbol* newFn = fn->partialCopy(&map);
+
addCache(genericsCache, root, newFn, &all_subs);
- //printf("newFn: %d %s\n", newFn->id, newFn->cname);
-
newFn->removeFlag(FLAG_GENERIC);
newFn->addFlag(FLAG_INVISIBLE_FN);
newFn->instantiatedFrom = fn;
+ newFn->substitutions.map_union(all_subs);
- if (call)
+ if (call) {
newFn->instantiationPoint = getVisibilityBlock(call);
-
+ }
Expr* putBefore = fn->defPoint;
if( !putBefore->list ) {
putBefore = call->parentSymbol->defPoint;
}
- putBefore->insertBefore(new DefExpr(newFn));
+
+ DefExpr* def = new DefExpr(newFn);
+
+ putBefore->insertBefore(def);
//
// add parameter instantiations to parameter map
//
- for (int i = 0; i < subs->n; i++) {
- if (ArgSymbol* arg = toArgSymbol(subs->v[i].key)) {
+ for (int i = 0; i < subs.n; i++) {
+ if (ArgSymbol* arg = toArgSymbol(subs.v[i].key)) {
if (arg->intent == INTENT_PARAM) {
Symbol* key = map.get(arg);
- Symbol* val = subs->v[i].value;
+ Symbol* val = subs.v[i].value;
if (!key || !val || isTypeSymbol(val))
INT_FATAL("error building parameter map in instantiation");
paramMap.put(key, val);
@@ -589,7 +621,7 @@ instantiate(FnSymbol* fn, SymbolMap* subs, CallExpr* call) {
//
for_formals(formal, fn) {
ArgSymbol* newFormal = toArgSymbol(map.get(formal));
- if (Symbol* value = subs->get(formal)) {
+ if (Symbol* value = subs.get(formal)) {
INT_ASSERT(formal->intent == INTENT_PARAM || isTypeSymbol(value));
if (formal->intent == INTENT_PARAM) {
newFormal->intent = INTENT_BLANK;
@@ -616,26 +648,26 @@ instantiate(FnSymbol* fn, SymbolMap* subs, CallExpr* call) {
newType->defaultTypeConstructor = newFn;
newFn->retType = newType;
}
+
+ if (fn->hasFlag(FLAG_TUPLE)) {
+ instantiate_tuple_signature(newFn);
+ }
- if (!strcmp(fn->name, "chpl__defaultHash") &&
- fn->getFormal(1)->type->symbol->hasFlag(FLAG_TUPLE))
+ if (!strcmp(fn->name, "chpl__defaultHash") && fn->getFormal(1)->type->symbol->hasFlag(FLAG_TUPLE)) {
instantiate_tuple_hash(newFn);
+ }
- if (fn->hasFlag(FLAG_INIT_COPY_FN) &&
- fn->getFormal(1)->type->symbol->hasFlag(FLAG_TUPLE))
+ if (fn->hasFlag(FLAG_INIT_COPY_FN) && fn->getFormal(1)->type->symbol->hasFlag(FLAG_TUPLE)) {
instantiate_tuple_initCopy(newFn);
+ }
- if (fn->hasFlag(FLAG_AUTO_COPY_FN) &&
- fn->getFormal(1)->type->symbol->hasFlag(FLAG_TUPLE))
+ if (fn->hasFlag(FLAG_AUTO_COPY_FN) && fn->getFormal(1)->type->symbol->hasFlag(FLAG_TUPLE)) {
instantiate_tuple_autoCopy(newFn);
-
- newFn->substitutions.append(all_subs);
-
- if (fn->hasFlag(FLAG_TUPLE))
- instantiate_tuple(newFn);
-
- if (newFn->numFormals() > 1 && newFn->getFormal(1)->type == dtMethodToken)
+ }
+
+ if (newFn->numFormals() > 1 && newFn->getFormal(1)->type == dtMethodToken) {
newFn->getFormal(2)->type->methods.add(newFn);
+ }
newFn->tag_generic();
@@ -653,8 +685,31 @@ instantiate(FnSymbol* fn, SymbolMap* subs, CallExpr* call) {
if (!newFn->hasFlag(FLAG_GENERIC) && explainInstantiationLine) {
explainInstantiation(newFn);
}
-
+
checkInstantiationLimit(fn);
+
+ return newFn;
+}
+
+void
+instantiateBody(FnSymbol* fn) {
+
+ fn->finalizeCopy();
+ if (fn->hasFlag(FLAG_PARTIAL_TUPLE)) {
+ instantiate_tuple_body(fn);
+ }
+}
+
+FnSymbol*
+instantiate(FnSymbol* fn, SymbolMap& subs, CallExpr* call) {
+ FnSymbol* newFn;
+
+ newFn = instantiateSignature(fn, subs, call);
+
+ if (newFn != NULL) {
+ instantiateBody(newFn);
+ }
+
return newFn;
}
diff --git a/compiler/resolution/resolution.h b/compiler/resolution/resolution.h
index 1737957..41fd418 100644
--- a/compiler/resolution/resolution.h
+++ b/compiler/resolution/resolution.h
@@ -23,7 +23,10 @@ const char* toString(FnSymbol* fn);
void parseExplainFlag(char* flag, int* line, ModuleSymbol** module);
-FnSymbol* instantiate(FnSymbol* fn, SymbolMap* subs, CallExpr* call);
+FnSymbol* instantiate(FnSymbol* fn, SymbolMap& subs, CallExpr* call);
+FnSymbol* instantiateSignature(FnSymbol* fn, SymbolMap& subs, CallExpr* call);
+void instantiateBody(FnSymbol* fn);
+
void resolveFormals(FnSymbol* fn);
void resolveCall(CallExpr* call, bool errorCheck = true);
void resolveBlock(Expr* body);
------------------------------------------------------------------------------
_______________________________________________
Chapel-developers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/chapel-developers