forv_Vec(CallExpr, call, gCallExprs) { if (call->isPrimitive(PRIM_CHECK_ERROR)) { SET_LINENO(call); SymExpr* errSe = toSymExpr(call->get(1)); Symbol* errorVar= errSe->symbol(); VarSymbol* errorExistsVar = newTemp("errorExists", dtBool); DefExpr* def = new DefExpr(errorExistsVar); CallExpr* errorExists = new CallExpr(PRIM_NOTEQUAL, errorVar, gNil); CallExpr* move = new CallExpr(PRIM_MOVE, errorExistsVar, errorExists); Expr* stmt = call->getStmtExpr(); stmt->insertBefore(def); def->insertAfter(move); call->replace(new SymExpr(errorExistsVar)); } }
FnSymbol* ReturnByRef::theTransformableFunction(CallExpr* call) { // The common case of a user-level call to a resolved function FnSymbol* theCall = call->isResolved(); // Also handle the PRIMOP for a virtual method call if (theCall == NULL) { if (call->isPrimitive(PRIM_VIRTUAL_METHOD_CALL) == true) { SymExpr* arg1 = toSymExpr(call->get(1)); theCall = toFnSymbol(arg1->var); } } return (theCall && isTransformableFunction(theCall)) ? theCall : NULL; }
// Find the block stmt that encloses the target of this gotoStmt static BlockStmt* findBlockForTarget(GotoStmt* stmt) { BlockStmt* retval = NULL; if (stmt != NULL && stmt->isGotoReturn() == false) { SymExpr* labelSymExpr = toSymExpr(stmt->label); Expr* ptr = labelSymExpr->symbol()->defPoint; while (ptr != NULL && isBlockStmt(ptr) == false) { ptr = ptr->parentExpr; } retval = toBlockStmt(ptr); INT_ASSERT(retval); } return retval; }
// // GotoStmt // bool AstDumpToHtml::enterGotoStmt(GotoStmt* node) { fprintf(mFP, "<DL>\n"); switch (node->gotoTag) { case GOTO_NORMAL: fprintf(mFP, "<B>goto</B> "); break; case GOTO_BREAK: fprintf(mFP, "<B>break</B> "); break; case GOTO_CONTINUE: fprintf(mFP, "<B>continue</B> "); break; case GOTO_RETURN: fprintf(mFP, "<B>gotoReturn</B> "); break; case GOTO_GETITER_END: fprintf(mFP, "<B>gotoGetiterEnd</B> "); break; case GOTO_ITER_RESUME: fprintf(mFP, "<B>gotoIterResume</B> "); break; case GOTO_ITER_END: fprintf(mFP, "<B>gotoIterEnd</B> "); break; } if (SymExpr* label = toSymExpr(node->label)) if (label->var != gNil) writeSymbol(label->var, true); return true; }
void localizeGlobals() { if (fNoGlobalConstOpt) return; forv_Vec(FnSymbol, fn, gFnSymbols) { Map<Symbol*,VarSymbol*> globals; std::vector<BaseAST*> asts; collect_asts(fn->body, asts); for_vector(BaseAST, ast, asts) { if (SymExpr* se = toSymExpr(ast)) { Symbol* var = se->var; ModuleSymbol* parentmod = toModuleSymbol(var->defPoint->parentSymbol); CallExpr* parentExpr = toCallExpr(se->parentExpr); bool inAddrOf = parentExpr && parentExpr->isPrimitive(PRIM_ADDR_OF); // Is var a global constant? // Don't replace the var name in its init function since that's // where we're setting the value. Similarly, dont replace them // inside initStringLiterals // If the parentSymbol is the rootModule, the var is 'void,' // 'false,' '0,' ... // Also don't replace it when it's in an addr of primitive. if (parentmod && fn != parentmod->initFn && fn != initStringLiterals && !inAddrOf && var->hasFlag(FLAG_CONST) && var->defPoint->parentSymbol != rootModule) { VarSymbol* local_global = globals.get(var); SET_LINENO(se); // Set the se line number for output if (!local_global) { const char * newname = astr("local_", var->cname); local_global = newTemp(newname, var->type); fn->insertAtHead(new CallExpr(PRIM_MOVE, local_global, var)); fn->insertAtHead(new DefExpr(local_global)); globals.put(var, local_global); } se->replace(new SymExpr(toSymbol(local_global))); } } } }
Expr* postFold(Expr* expr) { SET_LINENO(expr); Expr* retval = expr; INT_ASSERT(expr->inTree()); if (CallExpr* call = toCallExpr(expr)) { if (call->isResolved() == true) { retval = postFoldNormal(call); } else if (call->isPrimitive() == true) { retval = postFoldPrimop(call); } } else if (SymExpr* sym = toSymExpr(expr)) { retval = postFoldSymExpr(sym); } return retval; }
static QualifiedType returnInfoGetMember(CallExpr* call) { AggregateType* ct = toAggregateType(call->get(1)->typeInfo()); if (ct->symbol->hasFlag(FLAG_REF)) ct = toAggregateType(ct->getValType()); if (!ct) INT_FATAL(call, "bad member primitive"); SymExpr* sym = toSymExpr(call->get(2)); if (!sym) INT_FATAL(call, "bad member primitive"); VarSymbol* var = toVarSymbol(sym->symbol()); if (!var) INT_FATAL(call, "bad member primitive"); if (var->immediate) { const char* name = var->immediate->v_string; for_fields(field, ct) { if (!strcmp(field->name, name)) return field->qualType(); } } else return sym->qualType();
void ForallIntents::verifyFI(BlockStmt* parentB) { Expr* parentE = (Expr*)parentB; int nv = numVars(); INT_ASSERT((int)(fiVars.size()) == nv); INT_ASSERT((int)(fIntents.size()) == nv); INT_ASSERT((int)(riSpecs.size()) == nv); for (int i = 0; i < nv; i++) { Expr* fiVar = fiVars[i]; if (SymExpr* fiVarSE = toSymExpr(fiVar)) { INT_ASSERT(isVarSymbol(fiVarSE->symbol()) || isArgSymbol(fiVarSE->symbol())); // no modules, fns, etc. } else { // fiVars[i] is either resolved or unresolved sym expr; never NULL. INT_ASSERT(isUnresolvedSymExpr(fiVar)); // These should be resolved during scopeResolve. INT_ASSERT(!normalized); } verifyNotOnList(fiVar); INT_ASSERT(fiVar->parentExpr == parentE); Expr* ri = riSpecs[i]; INT_ASSERT(isReduce(i) == !!ri); if (ri) { // ri can be UnresolvedSymExpr, SymExpr, CallExpr, ... (?) verifyNotOnList(ri); INT_ASSERT(ri->parentExpr == parentE); } } INT_ASSERT(!iterRec || iterRec->parentExpr == parentE); INT_ASSERT(!leadIdx || leadIdx->parentExpr == parentE); INT_ASSERT(!leadIdxCopy || leadIdxCopy->parentExpr == parentE); verifyNotOnList(iterRec); verifyNotOnList(leadIdx); verifyNotOnList(leadIdxCopy); // ForallIntents are gone during resolve(). INT_ASSERT(!resolved); }
GenRet GotoStmt::codegen() { GenInfo* info = gGenInfo; FILE* outfile = info->cfile; GenRet ret; codegenStmt(this); if( outfile ) { info->cStatements.push_back("goto " + label->codegen().c + ";\n"); } else { #ifdef HAVE_LLVM llvm::Function *func = info->builder->GetInsertBlock()->getParent(); const char *cname; if(isDefExpr(label)) { cname = toDefExpr(label)->sym->cname; } else { cname = toSymExpr(label)->symbol()->cname; } llvm::BasicBlock *blockLabel; if(!(blockLabel = info->lvt->getBlock(cname))) { blockLabel = llvm::BasicBlock::Create(info->module->getContext(), cname); info->lvt->addBlock(cname, blockLabel); } info->builder->CreateBr(blockLabel); getFunction()->codegenUniqueNum++; llvm::BasicBlock *afterGoto = llvm::BasicBlock::Create( info->module->getContext(), FNAME("afterGoto")); func->getBasicBlockList().push_back(afterGoto); info->builder->SetInsertPoint(afterGoto); #endif } return ret; }
// // Removes gotos where the label immediately follows the goto and // unused labels // void removeUnnecessaryGotos(FnSymbol* fn) { std::vector<BaseAST*> asts; std::set<BaseAST*> labels; collect_asts_STL(fn, asts); for_vector(BaseAST, ast, asts) { if (GotoStmt* gotoStmt = toGotoStmt(ast)) { DefExpr* def = toDefExpr(gotoStmt->next); SymExpr* label = toSymExpr(gotoStmt->label); INT_ASSERT(label); if (def && def->sym == label->var) gotoStmt->remove(); else labels.insert(label->var); } } for_vector(BaseAST, ast2, asts) { if (DefExpr* def = toDefExpr(ast2)) if (LabelSymbol* label = toLabelSymbol(def->sym)) if (labels.find(label) == labels.end()) def->remove(); } }
// // Assumes 'parent' is a PRIM_MOVE or PRIM_ASSIGN // // Returns false if the LHS of the move/assign indicates that the rhs cannot // be a const-ref. For example, if we have a case like this: // // (move A, (set-reference B)) // // where 'A' and 'B' are references, B cannot be a const-ref if A is not a // const-ref. // // In the case of a dereference, (move A, (deref B)), this function will return // true because we're simply reading B. // static bool canRHSBeConstRef(CallExpr* parent, SymExpr* use) { INT_ASSERT(isMoveOrAssign(parent)); SymExpr* LHS = toSymExpr(parent->get(1)); CallExpr* rhs = toCallExpr(parent->get(2)); INT_ASSERT(rhs); switch (rhs->primitive->tag) { case PRIM_GET_MEMBER_VALUE: case PRIM_GET_SVEC_MEMBER_VALUE: if (LHS->isRef() == false && isClass(LHS->typeInfo()) == false) { return true; } // fallthrough case PRIM_GET_MEMBER: case PRIM_GET_SVEC_MEMBER: case PRIM_GET_REAL: case PRIM_GET_IMAG: case PRIM_ADDR_OF: case PRIM_SET_REFERENCE: { // If LHS is a reference and is not a const-ref, the reference in 'rhs' // should not be considered a const-ref either. // // For the get-member primitives, I intend this to be a safe approach // until we know what const-ref means for fields. Basically, if any field // might be modified I do not consider the base object to be const-ref. // // Note that the get-*-value primitives may return a reference if the // field is a reference. if (LHS->isRef()) { return inferConstRef(LHS->symbol()); } } default: break; } return isSafeRefPrimitive(use); }
// Does 'fn' return the result of a call to 'se' ? static bool isReturnedValue(FnSymbol* fn, SymExpr* se) { Symbol* currSym = fn->getReturnSymbol(); // Traverse the chain of moves. Like in stripReturnScaffolding(). while (true) { if (SymExpr* defSE = currSym->getSingleDef()) if (CallExpr* defMove = toCallExpr(defSE->parentExpr)) if (defMove->isPrimitive(PRIM_MOVE)) { Expr* defSrc = defMove->get(2); if (CallExpr* srcCall = toCallExpr(defSrc)) if (srcCall->baseExpr == se) return true; // found it if (SymExpr* srcSE = toSymExpr(defSrc)) { currSym = srcSE->symbol(); continue; // continue traversing the chain of moves } } // The chain of moves is over. Return false. break; } return false; }
void collectSymExprs(BaseAST* ast, Vec<SymExpr*>& symExprs) { AST_CHILDREN_CALL(ast, collectSymExprs, symExprs); if (SymExpr* symExpr = toSymExpr(ast)) symExprs.add(symExpr); }
// // Attempts to replace references with the variables the references point to, // provided the references have a single definition. // // For example: // var foo : int; // ref A : int; // (move A (addr-of foo)) // // (move B (deref A)) ---> (move B foo) // void eliminateSingleAssignmentReference(Map<Symbol*,Vec<SymExpr*>*>& defMap, Map<Symbol*,Vec<SymExpr*>*>& useMap, Symbol* var) { if (CallExpr* move = findRefDef(defMap, var)) { if (CallExpr* rhs = toCallExpr(move->get(2))) { if (rhs->isPrimitive(PRIM_ADDR_OF) || rhs->isPrimitive(PRIM_SET_REFERENCE)) { bool stillAlive = false; for_uses(se, useMap, var) { CallExpr* parent = toCallExpr(se->parentExpr); SET_LINENO(se); if (parent && (parent->isPrimitive(PRIM_DEREF) || isDerefMove(parent))) { SymExpr* se = toSymExpr(rhs->get(1)->copy()); INT_ASSERT(se); Expr* toReplace = parent; if (isMoveOrAssign(parent)) { toReplace = parent->get(2); } toReplace->replace(se); ++s_ref_repl_count; addUse(useMap, se); } else if (parent && (parent->isPrimitive(PRIM_GET_MEMBER_VALUE) || parent->isPrimitive(PRIM_GET_MEMBER) || parent->isPrimitive(PRIM_GET_MEMBER_VALUE) || parent->isPrimitive(PRIM_GET_MEMBER))) { SymExpr* se = toSymExpr(rhs->get(1)->copy()); INT_ASSERT(se); parent->get(1)->replace(se); ++s_ref_repl_count; addUse(useMap, se); } else if (parent && (parent->isPrimitive(PRIM_MOVE) || parent->isPrimitive(PRIM_SET_REFERENCE))) { CallExpr* rhsCopy = rhs->copy(); if (parent->isPrimitive(PRIM_SET_REFERENCE)) { // Essentially a pointer copy like a (move refA refB) parent = toCallExpr(parent->parentExpr); INT_ASSERT(parent && isMoveOrAssign(parent)); } parent->get(2)->replace(rhsCopy); ++s_ref_repl_count; SymExpr* se = toSymExpr(rhsCopy->get(1)); INT_ASSERT(se); addUse(useMap, se); // BHARSH TODO: Is it possible to handle the following case safely // for PRIM_ASSIGN? // // ref i_foo : T; // (move i_foo (set reference bar)) // (= call_tmp i_foo) // // Should that turn into (= call_tmp bar)? } else if (parent && parent->isPrimitive(PRIM_ASSIGN) && parent->get(1) == se) { // for_defs should handle this case } else if (parent && parent->isResolved()) { stillAlive = true; // TODO -- a reference argument can be passed directly } else { stillAlive = true; } } for_defs(se, defMap, var) { CallExpr* parent = toCallExpr(se->parentExpr); SET_LINENO(se); if (parent == move) continue; if (parent && isMoveOrAssign(parent)) { SymExpr* se = toSymExpr(rhs->get(1)->copy()); INT_ASSERT(se); parent->get(1)->replace(se); ++s_ref_repl_count; addDef(defMap, se); } else stillAlive = true; } if (!stillAlive) { var->defPoint->remove(); Vec<SymExpr*>* defs = defMap.get(var); if (defs == NULL) { INT_FATAL(var, "Expected var to be defined"); } // Remove the first definition from the AST. defs->v[0]->getStmtExpr()->remove(); } } else if (rhs->isPrimitive(PRIM_GET_MEMBER) ||
// This routine looks for loops in which the condition variable is *not* // updated within the body of the loop, and issues a warning for places // in the code where that occurs. void WhileStmt::checkConstLoops() { SymExpr* tmpVar = condExprForTmpVariableGet(); // Get the loop condition variable. if (VarSymbol* condSym = toVarSymbol(tmpVar->symbol())) { // Look for definitions of the loop condition variable // within the body of the loop. if (SymExpr* condDef = getWhileCondDef(condSym)) { // Get the call expression that updates the condition variable. if (CallExpr* outerCall = toCallExpr(condDef->parentExpr)) { // Assume the outer call is a move expression and that its LHS is // the (SymExpr that contains the) loop condition variable. if (outerCall->get(1) == condDef) { if (outerCall->isPrimitive(PRIM_MOVE)) { // Expect the update to be the result of a call to _cond_test. if (CallExpr* innerCall = toCallExpr(outerCall->get(2))) { FnSymbol* fn = innerCall->resolvedFunction(); if (innerCall->numActuals() == 1 && strcmp(fn->name, "_cond_test") == 0) { checkWhileLoopCondition(innerCall->get(1)); } else { INT_FATAL(innerCall, "Expected the update of a loop conditional " "to be piped through _cond_test()."); } } // The RHS of the move can also be a SymExpr as the result of param // folding ... else if (SymExpr* moveSrc = toSymExpr(outerCall->get(2))) { // ... in which case, the literal should be 'true' or 'false'. if (moveSrc->symbol() == gTrue) { // while true do ... ; -- probably OK. // User said to loop forever ... . } else if (moveSrc->symbol() == gFalse) { // while false do ...; -- probably nothing to worry about // We probably don't get here unless fRemoveUnreachableBlocks // is false. } else { INT_FATAL(moveSrc, "Expected const loop condition variable to be " "true or false."); } } else { // The RHS was neither a CallExpr nor a SymExpr. INT_FATAL(outerCall, "Invalid RHS in a loop condition variable update " "expression."); } } else { INT_FATAL(outerCall, "Expected a loop condition variable update to " "be a MOVE."); } } else { // Note that this being true depends on the compiler inserting a temp // that is the result of applying _cond_test to a more-general loop // conditional expression. // Copy propagation could potentially make this false again.... INT_FATAL(condDef, "Expected loop condition variable to be only " "updated (not read)."); } } else { INT_FATAL(condDef, "The update of a loop condition variable could not " "be converted to a call."); } } else { // There was no update of the loop condition variable in the // body of the loop. // It could be an infinite loop, or it could have a // 'break' or 'return' in it. } } else { INT_FATAL(tmpVar, "The loop condition variable could not be converted " "to a VarSymbol."); } }
static bool inferRefToConst(Symbol* sym) { INT_ASSERT(sym->isRef()); bool isConstRef = sym->qualType().getQual() == QUAL_CONST_REF; const bool wasRefToConst = sym->hasFlag(FLAG_REF_TO_CONST); ConstInfo* info = infoMap[sym]; // If this ref isn't const, then it can't point to a const thing if (info == NULL) { return false; } else if (info->finalizedRefToConst || wasRefToConst || !isConstRef) { return wasRefToConst; } bool isFirstCall = false; if (info->alreadyCalled == false) { isFirstCall = true; info->alreadyCalled = true; } bool isRefToConst = true; if (isArgSymbol(sym)) { // Check each call and set isRefToConst to false if any actual is not a ref // to a const. FnSymbol* fn = toFnSymbol(sym->defPoint->parentSymbol); if (fn->hasFlag(FLAG_VIRTUAL) || fn->hasFlag(FLAG_EXPORT) || fn->hasFlag(FLAG_EXTERN)) { // Not sure how to best handle virtual calls, so simply set false for now // // For export or extern functions, return false because we don't have // all the information about how the function is called. isRefToConst = false; } else { // Need this part to be re-entrant in case of recursive functions while (info->fnUses != NULL && isRefToConst) { SymExpr* se = info->fnUses; info->fnUses = se->symbolSymExprsNext; CallExpr* call = toCallExpr(se->parentExpr); INT_ASSERT(call && call->isResolved()); Symbol* actual = toSymExpr(formal_to_actual(call, sym))->symbol(); if (actual->isRef()) { // I don't think we technically need to skip if the actual is the // same symbol as the formal, but it makes things simpler. if (actual != sym && !inferRefToConst(actual)) { isRefToConst = false; } } else { // Passing a non-ref actual to a reference formal is currently // considered to be the same as an addr-of if (actual->qualType().getQual() != QUAL_CONST_VAL) { isRefToConst = false; } } } } } while (info->hasMore() && isRefToConst) { SymExpr* use = info->next(); CallExpr* call = toCallExpr(use->parentExpr); if (call == NULL) continue; if (isMoveOrAssign(call)) { if (use == call->get(1)) { if (SymExpr* se = toSymExpr(call->get(2))) { if (se->isRef() && !inferRefToConst(se->symbol())) { isRefToConst = false; } } else { CallExpr* RHS = toCallExpr(call->get(2)); INT_ASSERT(RHS); if (RHS->isPrimitive(PRIM_ADDR_OF) || RHS->isPrimitive(PRIM_SET_REFERENCE)) { SymExpr* src = toSymExpr(RHS->get(1)); if (src->isRef()) { if (!inferRefToConst(src->symbol())) { isRefToConst = false; } } else { if (src->symbol()->qualType().getQual() != QUAL_CONST_VAL) { isRefToConst = false; } } } else { isRefToConst = false; } } } } else if (call->isResolved()) { isRefToConst = true; } else { isRefToConst = isSafeRefPrimitive(use); } } if (isFirstCall) { if (isRefToConst) { INT_ASSERT(info->finalizedRefToConst == false); sym->addFlag(FLAG_REF_TO_CONST); } info->reset(); info->finalizedRefToConst = true; } else if (!isRefToConst) { info->finalizedRefToConst = true; } return isRefToConst; }
// 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; }
// // If call has the potential to cause communication, assert that the wide // reference that might cause communication is local and remove its wide-ness // // The organization of this function follows the order of CallExpr::codegen() // leaving out primitives that don't communicate. // static void localizeCall(CallExpr* call) { if (call->primitive) { switch (call->primitive->tag) { case PRIM_ARRAY_SET: /* Fallthru */ case PRIM_ARRAY_SET_FIRST: if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) { insertLocalTemp(call->get(1)); } break; case PRIM_MOVE: case PRIM_ASSIGN: // Not sure about this one. if (CallExpr* rhs = toCallExpr(call->get(2))) { if (rhs->isPrimitive(PRIM_DEREF)) { if (rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF) || rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) { insertLocalTemp(rhs->get(1)); if (!rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_REF)) { INT_ASSERT(rhs->get(1)->typeInfo() == dtString); // special handling for wide strings rhs->replace(rhs->get(1)->remove()); } } break; } else if (rhs->isPrimitive(PRIM_GET_MEMBER) || rhs->isPrimitive(PRIM_GET_SVEC_MEMBER) || rhs->isPrimitive(PRIM_GET_MEMBER_VALUE) || rhs->isPrimitive(PRIM_GET_SVEC_MEMBER_VALUE)) { if (rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF) || rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) { SymExpr* sym = toSymExpr(rhs->get(2)); INT_ASSERT(sym); if (!sym->var->hasFlag(FLAG_SUPER_CLASS)) { insertLocalTemp(rhs->get(1)); } } break; } else if (rhs->isPrimitive(PRIM_ARRAY_GET) || rhs->isPrimitive(PRIM_ARRAY_GET_VALUE)) { if (rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) { SymExpr* lhs = toSymExpr(call->get(1)); Expr* stmt = call->getStmtExpr(); INT_ASSERT(lhs && stmt); SET_LINENO(stmt); insertLocalTemp(rhs->get(1)); VarSymbol* localVar = NULL; if (rhs->isPrimitive(PRIM_ARRAY_GET)) localVar = newTemp(astr("local_", lhs->var->name), lhs->var->type->getField("addr")->type); else localVar = newTemp(astr("local_", lhs->var->name), lhs->var->type); stmt->insertBefore(new DefExpr(localVar)); lhs->replace(new SymExpr(localVar)); stmt->insertAfter(new CallExpr(PRIM_MOVE, lhs, new SymExpr(localVar))); } break; } else if (rhs->isPrimitive(PRIM_GET_UNION_ID)) { if (rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF)) { insertLocalTemp(rhs->get(1)); } break; } else if (rhs->isPrimitive(PRIM_TESTCID) || rhs->isPrimitive(PRIM_GETCID)) { if (rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) { insertLocalTemp(rhs->get(1)); } break; } ; } if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS) && !call->get(2)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) { break; } if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF) && !call->get(2)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF) && !call->get(2)->typeInfo()->symbol->hasFlag(FLAG_REF)) { insertLocalTemp(call->get(1)); } break; case PRIM_DYNAMIC_CAST: if (call->get(2)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) { insertLocalTemp(call->get(2)); if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS) || call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF)) { toSymExpr(call->get(1))->var->type = call->get(1)->typeInfo()->getField("addr")->type; } } break; case PRIM_SETCID: if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) { insertLocalTemp(call->get(1)); } break; case PRIM_SET_UNION_ID: if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF)) { insertLocalTemp(call->get(1)); } break; case PRIM_SET_MEMBER: case PRIM_SET_SVEC_MEMBER: if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS) || call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF)) { insertLocalTemp(call->get(1)); } break; default: break; } } }
static void list_ast(BaseAST* ast, BaseAST* parentAst = NULL, int indent = 0) { bool do_list_line = false; bool is_C_loop = false; const char* block_explain = NULL; if (Expr* expr = toExpr(ast)) { do_list_line = !parentAst || list_line(expr, parentAst); if (do_list_line) { printf("%-7d ", expr->id); for (int i = 0; i < indent; i++) printf(" "); } if (GotoStmt* e = toGotoStmt(ast)) { printf("goto "); if (SymExpr* label = toSymExpr(e->label)) { if (label->var != gNil) { list_ast(e->label, ast, indent+1); } } else { list_ast(e->label, ast, indent+1); } } else if (toBlockStmt(ast)) { block_explain = block_explanation(ast, parentAst); printf("%s{\n", block_explain); } else if (toCondStmt(ast)) { printf("if "); } else if (CallExpr* e = toCallExpr(expr)) { if (e->isPrimitive(PRIM_BLOCK_C_FOR_LOOP)) is_C_loop = true; if (e->primitive) printf("%s( ", e->primitive->name); else printf("call( "); } else if (NamedExpr* e = toNamedExpr(expr)) { printf("%s = ", e->name); } else if (toDefExpr(expr)) { printf("def "); } else if (SymExpr* e = toSymExpr(expr)) { list_sym(e->var, false); } else if (UnresolvedSymExpr* e = toUnresolvedSymExpr(expr)) { printf("%s ", e->unresolved); } } if (Symbol* sym = toSymbol(ast)) list_sym(sym); bool early_newline = toFnSymbol(ast) || toModuleSymbol(ast); if (early_newline || is_C_loop) printf("\n"); int new_indent = indent; if (isExpr(ast)) if (do_list_line) new_indent = indent+2; AST_CHILDREN_CALL(ast, list_ast, ast, new_indent); if (Expr* expr = toExpr(ast)) { CallExpr* parent_C_loop = NULL; if (CallExpr* call = toCallExpr(parentAst)) if (call->isPrimitive(PRIM_BLOCK_C_FOR_LOOP)) parent_C_loop = call; if (toCallExpr(expr)) { printf(") "); } if (toBlockStmt(ast)) { printf("%-7d ", expr->id); if (*block_explain) indent -= 2; for (int i = 0; i < indent; i++) printf(" "); if ((parent_C_loop && parent_C_loop->get(3) == expr) || *block_explain) printf("} "); else printf("}\n"); } else if (CondStmt* cond = toCondStmt(parentAst)) { if (cond->condExpr == expr) printf("\n"); } else if (!toCondStmt(expr) && do_list_line) { DefExpr* def = toDefExpr(expr); if (!(def && early_newline)) if (!parent_C_loop) printf("\n"); } } }
void ReturnByRef::updateAssignmentsFromRefTypeToValue(FnSymbol* fn) { std::vector<CallExpr*> callExprs; collectCallExprs(fn, callExprs); Map<Symbol*,Vec<SymExpr*>*> defMap; Map<Symbol*,Vec<SymExpr*>*> useMap; buildDefUseMaps(fn, defMap, useMap); for (size_t i = 0; i < callExprs.size(); i++) { CallExpr* move = callExprs[i]; if (move->isPrimitive(PRIM_MOVE) == true) { SymExpr* symLhs = toSymExpr (move->get(1)); CallExpr* callRhs = toCallExpr(move->get(2)); if (symLhs && callRhs && callRhs->isPrimitive(PRIM_DEREF)) { VarSymbol* varLhs = toVarSymbol(symLhs->symbol()); SymExpr* symRhs = toSymExpr(callRhs->get(1)); VarSymbol* varRhs = toVarSymbol(symRhs->symbol()); // MPF 2016-10-02: It seems to me that this code should also handle the // case that symRhs is an ArgSymbol, but adding that caused problems // in the handling of out argument intents. if (varLhs != NULL && varRhs != NULL) { if (isUserDefinedRecord(varLhs->type) == true && varRhs->type == varLhs->type->refType) { // HARSHBARGER 2015-12-11: // `init_untyped_var` in the `normalize` pass may insert an // initCopy, which means that we should not insert an autocopy // for that same variable. bool initCopied = false; for_uses(use, useMap, varLhs) { if (CallExpr* call = toCallExpr(use->parentExpr)) { if (FnSymbol* parentFn = call->isResolved()) { if (parentFn->hasFlag(FLAG_INIT_COPY_FN)) { initCopied = true; break; } } } } if (!initCopied) { SET_LINENO(move); SymExpr* lhsCopy0 = symLhs->copy(); SymExpr* lhsCopy1 = symLhs->copy(); FnSymbol* autoCopy = autoCopyMap.get(varLhs->type); CallExpr* copyExpr = new CallExpr(autoCopy, lhsCopy0); CallExpr* moveExpr = new CallExpr(PRIM_MOVE,lhsCopy1, copyExpr); move->insertAfter(moveExpr); } } } }
static bool symExprIsUsedAsConstRef(SymExpr* use) { if (CallExpr* call = toCallExpr(use->parentExpr)) { if (FnSymbol* calledFn = call->resolvedFunction()) { ArgSymbol* formal = actual_to_formal(use); // generally, use const-ref-return if passing to const ref formal if (formal->intent == INTENT_CONST_REF) { // but make an exception for initCopy calls if (calledFn->hasFlag(FLAG_INIT_COPY_FN)) return false; // TODO: tuples of types with blank intent // being 'in' should perhaps use the value version. return true; } } else if (call->isPrimitive(PRIM_RETURN) || call->isPrimitive(PRIM_YIELD)) { FnSymbol* inFn = toFnSymbol(call->parentSymbol); // use const-ref-return if returning by const ref intent if (inFn->retTag == RET_CONST_REF) return true; } else if (call->isPrimitive(PRIM_WIDE_GET_LOCALE) || call->isPrimitive(PRIM_WIDE_GET_NODE)) { // If we are extracting a field from the wide pointer, // we need to keep it as a pointer. // use const-ref-return if querying locale return true; } else { // Check for the case that sym is moved to a compiler-introduced // variable, possibly with PRIM_MOVE tmp, PRIM_ADDR_OF sym if (call->isPrimitive(PRIM_ADDR_OF) || call->isPrimitive(PRIM_SET_REFERENCE) || call->isPrimitive(PRIM_GET_MEMBER) || call->isPrimitive(PRIM_GET_SVEC_MEMBER)) call = toCallExpr(call->parentExpr); if (call->isPrimitive(PRIM_MOVE)) { SymExpr* lhs = toSymExpr(call->get(1)); Symbol* lhsSymbol = lhs->symbol(); if (lhsSymbol->hasFlag(FLAG_REF_VAR)) { // intended to handle 'const ref' // it would be an error to reach this point if it is not const INT_ASSERT(lhsSymbol->hasFlag(FLAG_CONST)); return true; } if (lhs != use && lhsSymbol->isRef() && symbolIsUsedAsConstRef(lhsSymbol)) return true; } } } return false; }
static void view_ast(BaseAST* ast, bool number = false, int mark = -1, int indent = 0) { if (!ast) return; if (Expr* expr = toExpr(ast)) { printf("\n"); for (int i = 0; i < indent; i++) printf(" "); printf("("); if (ast->id == mark) printf("***"); if (number) printf("%d ", ast->id); printf("%s", expr->astTagAsString()); if (isBlockStmt(expr)) if (FnSymbol* fn = toFnSymbol(expr->parentSymbol)) if (expr == fn->where) printf(" where"); if (GotoStmt *gs= toGotoStmt(ast)) { printf( " "); view_ast(gs->label, number, mark, indent+1); } if (CallExpr* call = toCallExpr(expr)) if (call->primitive) printf(" %s", call->primitive->name); if (NamedExpr* named = toNamedExpr(expr)) printf(" \"%s\"", named->name); if (toDefExpr(expr)) printf(" "); int64_t i; const char *str; if (get_int(expr, &i)) { printf(" %" PRId64, i); } else if (get_string(expr, &str)) { printf(" \"%s\"", str); } if (SymExpr* sym = toSymExpr(expr)) { printf(" "); view_sym(sym->var, number, mark); } else if (UnresolvedSymExpr* sym = toUnresolvedSymExpr(expr)) { printf(" '%s'", sym->unresolved); } } if (Symbol* sym = toSymbol(ast)) { view_sym(sym, number, mark); } AST_CHILDREN_CALL(ast, view_ast, number, mark, indent+2); if (DefExpr* def = toDefExpr(ast)) { printf(" "); writeFlags(stdout, def->sym); } if (toExpr(ast)) printf(")"); }
bool CallInfo::isWellFormed(CallExpr* callExpr) { bool retval = true; call = callExpr; if (SymExpr* se = toSymExpr(call->baseExpr)) { name = se->symbol()->name; } else if (UnresolvedSymExpr* use = toUnresolvedSymExpr(call->baseExpr)) { name = use->unresolved; } if (call->numActuals() >= 2) { if (SymExpr* se = toSymExpr(call->get(1))) { if (se->symbol() == gModuleToken) { se->remove(); se = toSymExpr(call->get(1)); INT_ASSERT(se); ModuleSymbol* mod = toModuleSymbol(se->symbol()); INT_ASSERT(mod); se->remove(); scope = mod->block; } } } for (int i = 1; i <= call->numActuals() && retval == true; i++) { Expr* actual = call->get(i); if (NamedExpr* named = toNamedExpr(actual)) { actualNames.add(named->name); actual = named->actual; } else { actualNames.add(NULL); } SymExpr* se = toSymExpr(actual); INT_ASSERT(se); Symbol* sym = se->symbol(); Type* t = sym->type; if (t == dtUnknown && sym->hasFlag(FLAG_TYPE_VARIABLE) == false) { retval = false; } else if (t->symbol->hasFlag(FLAG_GENERIC) == true) { // The _this actual to an initializer may be generic if (strcmp(name, "init") == 0 && i == 2) { actuals.add(sym); } else { retval = false; } } else { actuals.add(sym); } } return retval; }
void collectSymExprsSTL(BaseAST* ast, std::vector<SymExpr*>& symExprs) { AST_CHILDREN_CALL(ast, collectSymExprsSTL, symExprs); if (SymExpr* symExpr = toSymExpr(ast)) symExprs.push_back(symExpr); }
static void list_ast(BaseAST* ast, BaseAST* parentAst = NULL, int indent = 0) { bool do_list_line = false; bool is_C_loop = false; const char* block_explain = NULL; if (Expr* expr = toExpr(ast)) { if (ForallStmt* pfs = toForallStmt(parentAst)) { if (expr == pfs->fRecIterIRdef) { printf("fRecIterIRdef"); } else if (expr == pfs->loopBody()) { if (pfs->numShadowVars() == 0) print_on_its_own_line(indent, "with() do\n"); else print_on_its_own_line(indent, "do\n", false); indent -= 2; } } do_list_line = !parentAst || list_line(expr, parentAst); if (do_list_line) { printf("%-7d ", expr->id); print_indent(indent); } if (const char* expl = forall_explanation_start(ast, parentAst)) printf("%s", expl); if (GotoStmt* e = toGotoStmt(ast)) { printf("goto "); if (SymExpr* label = toSymExpr(e->label)) { if (label->symbol() != gNil) { list_ast(e->label, ast, indent+1); } } else { list_ast(e->label, ast, indent+1); } } else if (toBlockStmt(ast)) { block_explain = block_explanation(ast, parentAst); const char* block_kind = ast->astTagAsString(); if (!strcmp(block_kind, "BlockStmt")) block_kind = ""; printf("%s{%s\n", block_explain, block_kind); } else if (toCondStmt(ast)) { printf("if "); } else if (toIfExpr(ast)) { printf("IfExpr "); } else if (toForallStmt(ast)) { printf("forall\n"); } else if (CallExpr* e = toCallExpr(expr)) { if (e->isPrimitive(PRIM_BLOCK_C_FOR_LOOP)) is_C_loop = true; if (e->primitive) printf("%s( ", e->primitive->name); else printf("call( "); } else if (ForallExpr* e = toForallExpr(expr)) { if (e->zippered) printf("zip "); printf("forall( "); } else if (NamedExpr* e = toNamedExpr(expr)) { printf("%s = ", e->name); } else if (toDefExpr(expr)) { Symbol* sym = toDefExpr(expr)->sym; if (sym->type != NULL) { printf("def %s ", sym->qualType().qualStr()); } else { printf("def "); } } else if (SymExpr* e = toSymExpr(expr)) { list_sym(e->symbol(), false); } else if (UnresolvedSymExpr* e = toUnresolvedSymExpr(expr)) { printf("%s ", e->unresolved); } else if (isUseStmt(expr)) { printf("use "); } } if (Symbol* sym = toSymbol(ast)) list_sym(sym); bool early_newline = toFnSymbol(ast) || toModuleSymbol(ast); if (early_newline || is_C_loop) printf("\n"); int new_indent = indent; if (isExpr(ast)) if (do_list_line) new_indent = indent+2; AST_CHILDREN_CALL(ast, list_ast, ast, new_indent); if (Expr* expr = toExpr(ast)) { CallExpr* parent_C_loop = NULL; if (CallExpr* call = toCallExpr(parentAst)) if (call->isPrimitive(PRIM_BLOCK_C_FOR_LOOP)) parent_C_loop = call; if (toCallExpr(expr)) { printf(") "); } if (toBlockStmt(ast)) { printf("%-7d ", expr->id); if (*block_explain) indent -= 2; print_indent(indent); if ((parent_C_loop && parent_C_loop->get(3) == expr) || *block_explain) printf("} "); else if (isDeferStmt(parentAst)) printf("}"); // newline is coming else printf("}\n"); if (isForallLoopBody(expr) && parentAst != NULL) { print_indent(indent); printf(" end forall %d", parentAst->id); } } else if (ForallExpr* e = toForallExpr(expr)) { if (e->cond) printf(") "); else printf("} "); } else if (UseStmt* use = toUseStmt(expr)) { if (!use->isPlainUse()) { if (use->hasExceptList()) { printf("except "); } else { printf("only "); } bool first = true; for_vector(const char, str, use->named) { if (first) { first = false; } else { printf(", "); } printf("%s", str); } for (std::map<const char*, const char*>::iterator it = use->renamed.begin(); it != use->renamed.end(); ++it) { if (first) { first = false; } else { printf(", "); } printf("%s as %s", it->second, it->first); } printf("\n"); } } else if (CondStmt* cond = toCondStmt(parentAst)) {
static void collectMySymExprsHelp(BaseAST* ast, std::vector<SymExpr*>& symExprs) { if (isSymbol(ast)) return; // do not descend into nested symbols AST_CHILDREN_CALL(ast, collectMySymExprsHelp, symExprs); if (SymExpr* se = toSymExpr(ast)) symExprs.push_back(se); }