// // Determine the index type for a ParamForLoop. // // This implementation creates a range with low/high values and then // asks for its type. // Type* ParamForLoop::indexType() { SymExpr* lse = lowExprGet(); SymExpr* hse = highExprGet(); CallExpr* range = new CallExpr("chpl_build_bounded_range", lse->copy(), hse->copy()); Type* idxType = 0; insertBefore(range); resolveCall(range); if (FnSymbol* sym = range->isResolved()) { resolveFormals(sym); DefExpr* formal = toDefExpr(sym->formals.get(1)); if (toArgSymbol(formal->sym)->typeExpr) idxType = toArgSymbol(formal->sym)->typeExpr->body.tail->typeInfo(); else idxType = formal->sym->type; range->remove(); } else { INT_FATAL("unresolved range"); } return idxType; }
ConstInfo::ConstInfo(Symbol* s) { sym = s; fnUses = NULL; Qualifier q = sym->qualType().getQual(); finalizedConstness = q == QUAL_CONST_REF || q == QUAL_CONST_VAL; if (ArgSymbol* arg = toArgSymbol(s)) { // Work around a bug where we can have an arg with the in-intent, but it's // a reference // BHARSH TODO: this shouldn't be possible in the qualified refs impl. if (arg->intent == INTENT_CONST_IN && arg->isRef()) { finalizedConstness = false; } // Since we know 'sym' is an ArgSymbol, initialize the uses of the // symbol's function. FnSymbol* fn = toFnSymbol(sym->defPoint->parentSymbol); fnUses = fn->firstSymExpr(); } finalizedRefToConst = sym->hasFlag(FLAG_REF_TO_CONST); curTodo = 0; alreadyCalled = false; }
static void list_sym(Symbol* sym, bool type = true) { if (VarSymbol* var = toVarSymbol(sym)) { if (var->immediate) { if (var->immediate->const_kind == NUM_KIND_INT) { printf("%"PRId64" ", var->immediate->int_value()); return; } else if (var->immediate->const_kind == CONST_KIND_STRING) { printf("\"%s\" ", var->immediate->v_string); return; } } } if (toFnSymbol(sym)) { printf("fn "); } else if (toArgSymbol(sym)) { printf("arg "); } else if (toTypeSymbol(sym)) { printf("type "); } printf("%s", sym->name); printf("[%d]", sym->id); if (!type) { printf(" "); } else if (FnSymbol* fn = toFnSymbol(sym)) { printf(":%s", fn->retType->symbol->name); printf("[%d] ", fn->retType->symbol->id); } else if (sym->type && sym->type->symbol) { printf(":%s", sym->type->symbol->name); printf("[%d] ", sym->type->symbol->id); } else { printf(" "); } }
static void view_sym(Symbol* sym, bool number, int mark) { putchar('\''); if (sym->id == mark) printf("***"); if (toFnSymbol(sym)) { printf("fn "); } else if (toArgSymbol(sym)) { printf("arg "); } else if (toTypeSymbol(sym)) { printf("type "); } printf("%s", sym->name); if (number) printf("[%d]", sym->id); if (FnSymbol* fn = toFnSymbol(sym)) { printf(":%s", fn->retType->symbol->name); if (number) printf("[%d]", fn->retType->symbol->id); } else if (sym->type && sym->type->symbol) { printf(":%s", sym->type->symbol->name); if (number) printf("[%d]", sym->type->symbol->id); } if (sym->hasFlag(FLAG_GENERIC)) putchar('?'); putchar('\''); }
// // A forall-intents variation on findOuterVars() in createTaskFunctions.cpp: // Find all symbols used in 'block' and defined outside of it. // static void findOuterVars(BlockStmt* block, SymbolMap* uses) { std::vector<SymExpr*> symExprs; collectSymExprsSTL(block, symExprs); for_vector(SymExpr, symExpr, symExprs) { Symbol* sym = symExpr->var; if (toVarSymbol(sym) || toArgSymbol(sym)) if (!isCorrespIndexVar(block, sym) && isOuterVar(sym, block)) uses->put(sym,gNil); }
static const char* block_explanation(BaseAST* ast, BaseAST* parentAst) { if (ArgSymbol* parentArg = toArgSymbol(parentAst)) { if (ast == parentArg->typeExpr) return " typeExpr="; if (ast == parentArg->defaultExpr) return " defaultExpr="; if (ast == parentArg->variableExpr) return " variableExpr="; } return ""; }
// // finds outer vars directly used in a function // static void findOuterVars(FnSymbol* fn, SymbolMap* uses) { Vec<BaseAST*> asts; collect_asts(fn, asts); forv_Vec(BaseAST, ast, asts) { if (SymExpr* symExpr = toSymExpr(ast)) { Symbol* sym = symExpr->var; if (toVarSymbol(sym) || toArgSymbol(sym)) if (isOuterVar(sym, fn)) uses->put(sym,gNil); } } }
bool IpeProcedure::isActualRef(Expr* actual) const { bool retval = false; if (SymExpr* symExpr = toSymExpr(actual)) { if (ArgSymbol* arg = toArgSymbol(symExpr->var)) { retval = (arg->intent & INTENT_REF) ? true : false; } } return retval; }
void viewFlags(BaseAST* ast) { if (!viewFlagsShort && !viewFlagsName && !viewFlagsComment) viewFlagsName = true; if (Symbol* sym = toSymbol(ast)) { for (int flagNum = FLAG_FIRST; flagNum <= FLAG_LAST; flagNum++) { if (sym->flags[flagNum]) { if (viewFlagsName) printf("%s ", flagNames[flagNum]); if (viewFlagsPragma) printf("%s", flagPragma[flagNum] ? "ypr " : "npr "); if (viewFlagsShort) printf("\"%s\" ", flagShortNames[flagNum]); if (viewFlagsComment) printf("// %s", *flagComments[flagNum] ? flagComments[flagNum] : "ncm"); printf("\n"); } } if (viewFlagsExtras) { if (VarSymbol* vs = toVarSymbol(sym)) { if (vs->immediate) { printf("immediate "); fprint_imm(stdout, *toVarSymbol(sym)->immediate, true); printf("\n"); } } else if (ArgSymbol* as = toArgSymbol(sym)) { printf("%s arg\n", as->intentDescrString()); } else if (toTypeSymbol(sym)) { printf("a TypeSymbol\n"); } else if (FnSymbol* fs = toFnSymbol(sym)) { printf("fn %s(%d args) %s\n", fs->_this ? intentDescrString(fs->thisTag) : "", fs->numFormals(), retTagDescrString(fs->retTag)); } else if (toEnumSymbol(sym)) { printf("an EnumSymbol\n"); } else if (ModuleSymbol* ms = toModuleSymbol(sym)) { printf("module %s\n", modTagDescrString(ms->modTag)); } else if (toLabelSymbol(sym)) { printf("a LabelSymbol\n"); } else { printf("unknown symbol kind\n"); } } } else { printf("[%d]: not a Symbol, has no flags\n", ast->id); } }
// // Consider a function that takes a formal of type Record by const ref // and that returns that value from the function. The compiler inserts // a PRIM_MOVE operation. // // This work-around inserts an autoCopy to compensate // void ReturnByRef::updateAssignmentsFromRefArgToValue(FnSymbol* fn) { std::vector<CallExpr*> callExprs; collectCallExprs(fn, callExprs); for (size_t i = 0; i < callExprs.size(); i++) { CallExpr* move = callExprs[i]; if (move->isPrimitive(PRIM_MOVE) == true) { SymExpr* lhs = toSymExpr(move->get(1)); SymExpr* rhs = toSymExpr(move->get(2)); if (lhs != NULL && rhs != NULL) { VarSymbol* symLhs = toVarSymbol(lhs->symbol()); ArgSymbol* symRhs = toArgSymbol(rhs->symbol()); if (symLhs != NULL && symRhs != NULL) { if (isUserDefinedRecord(symLhs->type) == true && symRhs->type == symLhs->type) { if (symLhs->hasFlag(FLAG_ARG_THIS) == false && (symRhs->intent == INTENT_REF || symRhs->intent == INTENT_CONST_REF)) { SET_LINENO(move); CallExpr* autoCopy = NULL; rhs->remove(); autoCopy = new CallExpr(autoCopyMap.get(symRhs->type), rhs); move->insertAtTail(autoCopy); } } } } } } }
static void log_ast_symbol(FILE* file, Symbol* sym, bool def) { if (log_need_space) putc(' ', file); log_need_space = false; if (def) if (ArgSymbol* arg = toArgSymbol(sym)) { log_need_space = true; switch (arg->intent) { case INTENT_IN: fprintf(file, "in"); break; case INTENT_INOUT: fprintf(file, "inout"); break; case INTENT_OUT: fprintf(file, "out"); break; case INTENT_CONST: fprintf(file, "const"); break; case INTENT_CONST_IN: fprintf(file, "const in"); break; case INTENT_CONST_REF: fprintf(file, "const ref"); break; case INTENT_REF: fprintf(file, "ref"); break; case INTENT_PARAM: fprintf(file, "param"); break; case INTENT_TYPE: fprintf(file, "type"); break; default: log_need_space = false; break; } log_write(file, true, "arg", true); } log_write(file, true, sym->name, true); if (fLogIds) fprintf(file, "[%d]", sym->id); if (def && !toTypeSymbol(sym) && sym->type && sym->type->symbol && sym->type != dtUnknown) { log_write(file, false, ":", false); log_ast_symbol(file, sym->type->symbol, false); } if (sym->hasFlag(FLAG_GENERIC)) log_write(file, false, "?", false); log_need_space = true; }
void Expr::replace(Expr* new_ast) { if (new_ast->parentSymbol || new_ast->parentExpr) INT_FATAL(new_ast, "Argument is already in AST in Expr::replace"); if (new_ast->list) INT_FATAL(new_ast, "Argument is in a list in Expr::replace"); if (list) { new_ast->next = next; new_ast->prev = prev; new_ast->list = list; if (next) next->prev = new_ast; else list->tail = new_ast; if (prev) prev->next = new_ast; else list->head = new_ast; next = NULL; prev = NULL; list = NULL; } else { callReplaceChild(this, new_ast); } Symbol* myParentSymbol = parentSymbol; Expr* myParentExpr = parentExpr; remove_help(this, 'p'); insert_help(new_ast, myParentExpr, myParentSymbol); // Update the _this field in a FnSymbol if necessary. if (DefExpr* def = toDefExpr(this)) if (ArgSymbol* arg = toArgSymbol(def->sym)) if (FnSymbol* fn = toFnSymbol(myParentSymbol)) if (fn->_this == arg) fn->_this = toDefExpr(new_ast)->sym; }
// Note: This function is currently not recursive static bool inferConst(Symbol* sym) { INT_ASSERT(!sym->isRef()); const bool wasConstVal = sym->qualType().getQual() == QUAL_CONST_VAL; ConstInfo* info = infoMap[sym]; // 'info' may be null if the argument is never used. In that case we can // consider 'sym' to be a const-ref. By letting the rest of the function // proceed, we'll fix up the qualifier for such symbols at the end. if (info == NULL) { return true; } else if (info->finalizedConstness || wasConstVal) { return wasConstVal; } bool isConstVal = true; int numDefs = 0; while (info->hasMore() && isConstVal) { SymExpr* use = info->next(); CallExpr* call = toCallExpr(use->parentExpr); if (call == NULL) { // Could be a DefExpr, or the condition for a while loop. // BHARSH: I'm not sure of all the possibilities continue; } CallExpr* parent = toCallExpr(call->parentExpr); if (call->isResolved()) { ArgSymbol* form = actual_to_formal(use); // // If 'sym' is constructed through a _retArg, we can consider that to // be a single 'def'. // if (form->hasFlag(FLAG_RETARG)) { numDefs += 1; } else if (form->isRef()) { if (!inferConstRef(form)) { isConstVal = false; } } } else if (parent && isMoveOrAssign(parent)) { if (call->isPrimitive(PRIM_ADDR_OF) || call->isPrimitive(PRIM_SET_REFERENCE)) { Symbol* LHS = toSymExpr(parent->get(1))->symbol(); INT_ASSERT(LHS->isRef()); if (onlyUsedForRetarg(LHS, parent)) { numDefs += 1; } else if (!inferConstRef(LHS)) { isConstVal = false; } } } else if (isMoveOrAssign(call)) { if (use == call->get(1)) { numDefs += 1; } } else { // To be safe, exit the loop with 'false' if we're unsure of how to // handle a primitive. isConstVal = false; } if (numDefs > 1) { isConstVal = false; } } if (isConstVal && !info->finalizedConstness) { if (ArgSymbol* arg = toArgSymbol(sym)) { INT_ASSERT(arg->intent & INTENT_FLAG_IN); arg->intent = INTENT_CONST_IN; } else { INT_ASSERT(isVarSymbol(sym)); sym->qual = QUAL_CONST_VAL; } } info->reset(); info->finalizedConstness = true; return isConstVal; }
// // Returns 'true' if 'sym' is (or should be) a const-ref. // If 'sym' can be a const-ref, but is not, this function will change either // the intent or qual of the Symbol to const-ref. // static bool inferConstRef(Symbol* sym) { INT_ASSERT(sym->isRef()); bool wasConstRef = sym->qualType().getQual() == QUAL_CONST_REF; if (sym->defPoint->parentSymbol->hasFlag(FLAG_EXTERN)) { return wasConstRef; } ConstInfo* info = infoMap[sym]; // 'info' may be null if the argument is never used. In that case we can // consider 'sym' to be a const-ref. By letting the rest of the function // proceed, we'll fix up the qualifier for such symbols at the end. if (info == NULL) { return true; } else if (info->finalizedConstness || wasConstRef) { return wasConstRef; } bool isFirstCall = false; if (info->alreadyCalled == false) { isFirstCall = true; info->alreadyCalled = true; } bool isConstRef = true; while (info->hasMore() && isConstRef) { SymExpr* use = info->next(); CallExpr* call = toCallExpr(use->parentExpr); INT_ASSERT(call); CallExpr* parent = toCallExpr(call->parentExpr); if (call->isResolved()) { ArgSymbol* form = actual_to_formal(use); if (form->isRef() && !inferConstRef(form)) { isConstRef = false; } } else if (parent && isMoveOrAssign(parent)) { if (!canRHSBeConstRef(parent, use)) { isConstRef = false; } } else if (call->isPrimitive(PRIM_MOVE)) { // // Handles three cases: // 1) MOVE use value - writing to a reference, so 'use' cannot be const // 2) MOVE ref use - if the LHS is not const, use cannot be const either // 3) MOVE value use - a dereference of 'use' // if (use == call->get(1)) { // CASE 1 if (!call->get(2)->isRef()) { isConstRef = false; } } else { // 'use' is the RHS of a MOVE if (call->get(1)->isRef()) { // CASE 2 SymExpr* se = toSymExpr(call->get(1)); INT_ASSERT(se); if (!inferConstRef(se->symbol())) { isConstRef = false; } } // else CASE 3: do nothing because isConstRef is already true } } else if (call->isPrimitive(PRIM_ASSIGN)) { if (use == call->get(1)) { isConstRef = false; } } else if (call->isPrimitive(PRIM_SET_MEMBER) || call->isPrimitive(PRIM_SET_SVEC_MEMBER)) { // BHARSH 2016-11-02 // In the expr (set_member base member rhs), // If use == base, I take the conservative approach and decide that 'use' // is not a const-ref. I'm not sure that we've decided what const means // for fields yet, so this seems safest. // // If use == rhs, then we would need to do analysis for the member field. // That's beyond the scope of what I'm attempting at the moment, so to // be safe we'll return false for that case. if (use == call->get(1) || use == call->get(3)) { isConstRef = false; } else { // use == member // If 'rhs' is not a ref, then we're writing into 'use'. Otherwise it's // a pointer copy and we don't care if 'rhs' is writable. if (!call->get(3)->isRef()) { isConstRef = false; } } } else { // To be safe, exit the loop with 'false' if we're unsure of how to // handle a primitive. isConstRef = false; } } if (isFirstCall) { if (isConstRef) { INT_ASSERT(info->finalizedConstness == false); if (ArgSymbol* arg = toArgSymbol(sym)) { arg->intent = INTENT_CONST_REF; } else { INT_ASSERT(isVarSymbol(sym)); sym->qual = QUAL_CONST_REF; } } info->reset(); info->finalizedConstness = true; } else if (!isConstRef) { info->finalizedConstness = true; } return isConstRef; }
// // DefExpr // bool AstDumpToHtml::enterDefExpr(DefExpr* node) { bool retval = true; if (isBlockStmt(node->parentExpr)) { fprintf(mFP, "<DL>\n"); } fprintf(mFP, " "); if (FnSymbol* fn = toFnSymbol(node->sym)) { fprintf(mFP, "<UL CLASS =\"mktree\">\n<LI>"); adjacent_passes(fn); fprintf(mFP, "<CHPLTAG=\"FN%d\">\n", fn->id); fprintf(mFP, "<B>function "); writeFnSymbol(fn); fprintf(mFP, "</B><UL>\n"); } else if (isTypeSymbol(node->sym)) { if (toAggregateType(node->sym->type)) { fprintf(mFP, "<UL CLASS =\"mktree\">\n"); fprintf(mFP, "<LI>"); if (node->sym->hasFlag(FLAG_SYNC)) fprintf(mFP, "<B>sync</B> "); if (node->sym->hasFlag(FLAG_SINGLE)) fprintf(mFP, "<B>single</B> "); fprintf(mFP, "<B>type "); writeSymbol(node->sym, true); fprintf(mFP, "</B><UL>\n"); } else { fprintf(mFP, "<B>type </B> "); writeSymbol(node->sym, true); } } else if (VarSymbol* vs = toVarSymbol(node->sym)) { if (vs->type->symbol->hasFlag(FLAG_SYNC)) fprintf(mFP, "<B>sync </B>"); if (vs->type->symbol->hasFlag(FLAG_SINGLE)) fprintf(mFP, "<B>single </B>"); fprintf(mFP, "<B>var </B> "); writeSymbol(node->sym, true); } else if (ArgSymbol* s = toArgSymbol(node->sym)) { switch (s->intent) { case INTENT_IN: fprintf(mFP, "<B>in</B> "); break; case INTENT_INOUT: fprintf(mFP, "<B>inout</B> "); break; case INTENT_OUT: fprintf(mFP, "<B>out</B> "); break; case INTENT_CONST: fprintf(mFP, "<B>const</B> "); break; case INTENT_CONST_IN: fprintf(mFP, "<B>const in</B> "); break; case INTENT_CONST_REF: fprintf(mFP, "<B>const ref</B> "); break; case INTENT_REF: fprintf(mFP, "<B>ref</B> "); break; case INTENT_PARAM: fprintf(mFP, "<B>param</B> "); break; case INTENT_TYPE: fprintf(mFP, "<B>type</B> "); break; case INTENT_BLANK: break; } fprintf(mFP, "<B>arg</B> "); writeSymbol(node->sym, true); } else if (isLabelSymbol(node->sym)) { fprintf(mFP, "<B>label</B> "); writeSymbol(node->sym, true); } else if (isModuleSymbol(node->sym)) { fprintf(mFP, "</DL>\n"); // Don't process nested modules -- they'll be handled at the top-level retval = false; } else { fprintf(mFP, "<B>def</B> "); writeSymbol(node->sym, true); } return retval; }
void IpeEnv::describe(const char* pad, int index, LcnSymbol* var) const { const char* symName = var->name; const char* typeName = ""; ArgSymbol* argSym = toArgSymbol(var); VarSymbol* varSym = toVarSymbol(var); if (var->type) typeName = var->type->symbol->name; printf("%s %5d: %-30s", pad, index, symName); if (argSym != NULL) { if (argSym->intent & INTENT_REF) printf("ref %-12s", typeName); else printf("arg %-12s", typeName); } else if (varSym->immediate != NULL) printf("const %-12s", typeName); else if (varSym->hasFlag(FLAG_CONST) == true) printf("const %-12s", typeName); else if (varSym->hasFlag(FLAG_PARAM) == true) printf("param %-12s", typeName); else printf("var %-12s", typeName); if (var->depth() >= 0 && var->offset() >= 0) printf("%4d %4d ", var->depth(), var->offset()); else printf(" "); if (argSym != NULL && (argSym->intent & INTENT_REF) != 0) { if (mFrameData != NULL) { int offset = argSym->offset(); IpeValue* ref = *((IpeValue**) (((char*) mFrameData) + offset)); printf("0x%012lX", (long) ref); } } else if (var->offset() < 0) ; else if (var->type == NULL) ; else if (var->type == gIpeTypeType) printf("%s", symName); else if (var->type == dtBool) { if (mDepth == 0 || mFrameData != NULL) printf("%s", (fetchBool(var) == true) ? "true" : "false"); } else if (var->type == dtInt[INT_SIZE_64]) { if (mDepth == 0 || mFrameData != NULL) printf("%8ld", fetchInteger(var)); } else if (var->type == dtReal[FLOAT_SIZE_64]) { if (mDepth == 0 || mFrameData != NULL) printf(" %8.2f", fetchReal(var)); } else if (var->type == gIpeTypeModule) { if (mDepth == 0 || mFrameData != NULL) { IpeModule* value = (IpeModule*) fetchPtr(var); printf("#<IpeModule %-20s 0x%012lX>", value->name(), (long) value); } } else if (var->type == gIpeTypeProcedure) { if (mDepth == 0 || mFrameData != NULL) { IpeProcedure* value = (IpeProcedure*) fetchPtr(var); if (value->methodCount() == 1) printf("#<IpeProcedure %-20s with %3d method 0x%012lX>", value->name(), value->methodCount(), (long) value); else printf("#<IpeProcedure %-20s with %3d methods 0x%012lX>", value->name(), value->methodCount(), (long) value); } } else printf("Really?? Really??"); printf("\n"); }