Exemple #1
0
//
// 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;
}
void ResolutionCandidate::resolveTypeConstructor(CallInfo& info) {
  SET_LINENO(fn);

  // Ignore tuple constructors; they were generated
  // with their type constructors.
  if (fn->hasFlag(FLAG_PARTIAL_TUPLE) == false) {
    CallExpr* typeConstructorCall = new CallExpr(astr("_type", fn->name));

    for_formals(formal, fn) {
      if (formal->hasFlag(FLAG_IS_MEME) == false) {
        if (fn->_this->type->symbol->hasFlag(FLAG_TUPLE)) {
          if (formal->instantiatedFrom != NULL) {
            typeConstructorCall->insertAtTail(formal->type->symbol);

          } else if (formal->hasFlag(FLAG_INSTANTIATED_PARAM)) {
            typeConstructorCall->insertAtTail(paramMap.get(formal));
          }

        } else {
          if (strcmp(formal->name, "outer") == 0 ||
              formal->type                  == dtMethodToken) {
            typeConstructorCall->insertAtTail(formal);

          } else if (formal->instantiatedFrom != NULL) {
            SymExpr*   se = new SymExpr(formal->type->symbol);
            NamedExpr* ne = new NamedExpr(formal->name, se);

            typeConstructorCall->insertAtTail(ne);

          } else if (formal->hasFlag(FLAG_INSTANTIATED_PARAM)) {
            SymExpr*   se = new SymExpr(paramMap.get(formal));
            NamedExpr* ne = new NamedExpr(formal->name, se);

            typeConstructorCall->insertAtTail(ne);
          }
        }
      }
    }

    info.call->insertBefore(typeConstructorCall);

    // If instead we call resolveCallAndCallee(typeConstructorCall)
    // then the line number reported in an error would change
    // e.g.: domains/deitz/test_generic_class_of_sparse_domain
    // or:   classes/diten/multipledestructor
    resolveCall(typeConstructorCall);

    INT_ASSERT(typeConstructorCall->isResolved());

    resolveFunction(typeConstructorCall->resolvedFunction());

    fn->_this->type = typeConstructorCall->resolvedFunction()->retType;

    typeConstructorCall->remove();
  }
Exemple #3
0
void printCallStackCalls() {
  printf("\n" "callStack %d elms\n\n", callStack.n);
  for (int i = 0; i < callStack.n; i++) {
    CallExpr* call = callStack.v[i];
    FnSymbol* cfn = call->isResolved();
    printf("%d  %d %s  <-  %d %s\n", i,
           cfn ? cfn->id : 0, cfn ? cfn->name: "<no callee>",
           call ? call->id : 0, call ? call->stringLoc() : "<no call>");
  }
  printf("\n");
}
Exemple #4
0
//
// ref: The reference symbol we will test to see if it is only used as an
// actual where the corresponding formal has FLAG_RETARG.
//
// defCall: The CallExpr where 'ref' is set from a PRIM_ADDR_OF or
// PRIM_SET_REFERENCE. This call will be ignored while considering uses of
// the 'ref' Symbol.
//
static bool onlyUsedForRetarg(Symbol* ref, CallExpr* defCall) {
  bool isRetArgOnly = true;

  INT_ASSERT(ref->isRef());
  INT_ASSERT(defCall != NULL);

  for_SymbolSymExprs(use, ref) {
    if (use->parentExpr == defCall) {
      continue;
    }

    CallExpr* call = toCallExpr(use->parentExpr);
    if (call->isResolved()) {
      ArgSymbol* form = actual_to_formal(use);
      if (form->hasFlag(FLAG_RETARG) == false) {
        isRetArgOnly = false;
      }
    } else {
      isRetArgOnly = false;
    }
  }

  return isRetArgOnly;
}
//
// 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) ||
Exemple #6
0
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;
}
Exemple #7
0
// 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;
}
Exemple #8
0
//
// 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;
}