compiler/resolution/wrappers.cpp
//
// In order for fast followers to trigger, the invoking loop requires a static
// and dynamic check. They determine at compile time if the iterands implement
// a fast follower, and at runtime if all the iterands can fast follow the
// leader. Here we build up the checks for an iterator record. We basically
// convert the iterator record into a tuple and call the "zip" check. Note
// that we only stuff the components of the iterator record that actually
// require promotion into the tuple.
//
// i.e. we build up something like:
//
//    _iteratorRecord has a field for each formal in the promoted function.
//    `A + 2.0 * C` results in a record with fields for each array and the real
//
//    proc chpl__dynamicFastFollowCheck(x: _iteratorRecord, lead) {
//      // tuple that only has elements for fields that require promotion
//      var promotion_tup: recordToPromotionTuple(x);
//      var cur_tup_idx = 1;
//      for param fieldNum in 1..numFields(x.type) {
//        var field = getField(x.type, fieldNum);
//        if requiresPromotion(field.type, x) {
//          promotion_tup(cur_tup_idx) = field;
//          cur_tup_idx += 1;
//        }
//      }
//      return chpl__dynamicFastFollowCheckZip(promotion_tup, lead);
//    }
//
// However, since the iterator record isn't fully built (none of the fields
// exist yet), we use a primitive as a placeholder. When the record is filled
// in during iterator lowering, we replace the primitive with the actual field.
//
In order for fast followers to trigger, the invoking loop requires a static
and dynamic check. They determine at compile time if the iterands implement
a fast follower, and at runtime if all the iterands can fast follow the
leader. Here we build up the checks for an iterator record. We basically
convert the iterator record into a tuple and call the "zip" check. Note
that we only stuff the components of the iterator record that actually
require promotion into the tuple.



_iteratorRecord has a field for each formal in the promoted function.
`A + 2.0 * C` results in a record with fields for each array and the real



However, since the iterator record isn't fully built (none of the fields
exist yet), we use a primitive as a placeholder. When the record is filled
in during iterator lowering, we replace the primitive with the actual field.
In order for fast followers to trigger the invoking loop requires a static and dynamic check . They determine at compile time if the iterands implement a fast follower and at runtime if all the iterands can fast follow the leader . Here we build up the checks for an iterator record . We basically convert the iterator record into a tuple and call the " zip " check . Note that we only stuff the components of the iterator record that actually require promotion into the tuple . _iteratorRecord has a field for each formal in the promoted function . ` A + 2 . 0 * C ` results in a record with fields for each array and the real However since the iterator record isn ' t fully built ( none of the fields exist yet ) we use a primitive as a placeholder . When the record is filled in during iterator lowering we replace the primitive with the actual field .
static void buildFastFollowerCheck(bool                  isStatic,
                                   bool                  addLead,
                                   CallInfo&             info,
                                   FnSymbol*             wrapper,
                                   std::set<ArgSymbol*>& requiresPromotion) {
  const char* fnName     = NULL;
  FnSymbol*   checkFn    = NULL;
  ArgSymbol*  x          = new ArgSymbol(INTENT_BLANK, "x", dtIteratorRecord);
  CallExpr*   buildTuple = new CallExpr("_build_tuple_always_allow_ref");
  Symbol*     pTup       = newTemp("p_tup");
  Symbol*     returnTmp  = newTemp("p_ret");
  CallExpr*   forward    = NULL;
  returnTmp->addFlag(FLAG_EXPR_TEMP);
  returnTmp->addFlag(FLAG_MAYBE_PARAM);
  if (isStatic == true) {
    fnName          = "chpl__staticFastFollowCheck";
    checkFn         = new FnSymbol(fnName);
    checkFn->retTag = RET_PARAM;
  } else {
    fnName          = "chpl__dynamicFastFollowCheck";
    checkFn         = new FnSymbol(fnName);
    checkFn->retTag = RET_VALUE;
  }
  checkFn->addFlag(FLAG_GENERIC);
  checkFn->insertFormalAtTail(x);
  if (addLead == true) {
    ArgSymbol* lead = new ArgSymbol(INTENT_BLANK, "lead", dtAny);
    checkFn->insertFormalAtTail(lead);
    forward = new CallExpr(astr(fnName, "Zip"), pTup, lead);
  } else {
    forward = new CallExpr(astr(fnName, "Zip"), pTup);
  }
  for_formals(formal, wrapper) {
    if (requiresPromotion.count(formal) > 0) {
      Symbol*      field       = new VarSymbol(formal->name, formal->type);
      PrimitiveTag primTag     = PRIM_ITERATOR_RECORD_FIELD_VALUE_BY_FORMAL;
      CallExpr*    byFormal    = new CallExpr(primTag,   x,     formal);
      CallExpr*    moveToField = new CallExpr(PRIM_MOVE, field, byFormal);
      checkFn->insertAtTail(new DefExpr(field));
      checkFn->insertAtTail(moveToField);
      buildTuple->insertAtTail(new SymExpr(field));
    }
  }
  CallExpr* typeOfLhs = new CallExpr(PRIM_TYPEOF, x);
  CallExpr* typeOfRhs = new CallExpr(PRIM_TYPEOF, info.call->copy());
  checkFn->where = new BlockStmt(new CallExpr("==", typeOfLhs, typeOfRhs));
  checkFn->insertAtTail(new DefExpr(pTup));
  checkFn->insertAtTail(new CallExpr(PRIM_MOVE, pTup, buildTuple));
  checkFn->insertAtTail(new DefExpr(returnTmp));
  checkFn->insertAtTail(new CallExpr(PRIM_MOVE,   returnTmp, forward));
  checkFn->insertAtTail(new CallExpr(PRIM_RETURN, returnTmp));
  theProgram->block->insertAtTail(new DefExpr(checkFn));
  normalize(checkFn);
  checkFn->setInstantiationPoint(info.call);
}
static void buildFastFollowerCheck ( bool isStatic , bool addLead , CallInfo & info , FnSymbol * wrapper , std :: set < ArgSymbol * > & requiresPromotion ) { const char * fnName = NULL ; FnSymbol * checkFn = NULL ; ArgSymbol * x = new ArgSymbol ( INTENT_BLANK , " " , dtIteratorRecord ) ; CallExpr * buildTuple = new CallExpr ( " " ) ; Symbol * pTup = newTemp ( " " ) ; Symbol * returnTmp = newTemp ( " " ) ; CallExpr * forward = NULL ; returnTmp -> addFlag ( FLAG_EXPR_TEMP ) ; returnTmp -> addFlag ( FLAG_MAYBE_PARAM ) ; if ( isStatic == true ) { fnName = " " ; checkFn = new FnSymbol ( fnName ) ; checkFn -> retTag = RET_PARAM ; } else { fnName = " " ; checkFn = new FnSymbol ( fnName ) ; checkFn -> retTag = RET_VALUE ; } checkFn -> addFlag ( FLAG_GENERIC ) ; checkFn -> insertFormalAtTail ( x ) ; if ( addLead == true ) { ArgSymbol * lead = new ArgSymbol ( INTENT_BLANK , " " , dtAny ) ; checkFn -> insertFormalAtTail ( lead ) ; forward = new CallExpr ( astr ( fnName , " " ) , pTup , lead ) ; } else { forward = new CallExpr ( astr ( fnName , " " ) , pTup ) ; } for_formals ( formal , wrapper ) { if ( requiresPromotion . count ( formal ) > 0 ) { Symbol * field = new VarSymbol ( formal -> name , formal -> type ) ; PrimitiveTag primTag = PRIM_ITERATOR_RECORD_FIELD_VALUE_BY_FORMAL ; CallExpr * byFormal = new CallExpr ( primTag , x , formal ) ; CallExpr * moveToField = new CallExpr ( PRIM_MOVE , field , byFormal ) ; checkFn -> insertAtTail ( new DefExpr ( field ) ) ; checkFn -> insertAtTail ( moveToField ) ; buildTuple -> insertAtTail ( new SymExpr ( field ) ) ; } } CallExpr * typeOfLhs = new CallExpr ( PRIM_TYPEOF , x ) ; CallExpr * typeOfRhs = new CallExpr ( PRIM_TYPEOF , info . call -> copy ( ) ) ; checkFn -> where = new BlockStmt ( new CallExpr ( " " , typeOfLhs , typeOfRhs ) ) ; checkFn -> insertAtTail ( new DefExpr ( pTup ) ) ; checkFn -> insertAtTail ( new CallExpr ( PRIM_MOVE , pTup , buildTuple ) ) ; checkFn -> insertAtTail ( new DefExpr ( returnTmp ) ) ; checkFn -> insertAtTail ( new CallExpr ( PRIM_MOVE , returnTmp , forward ) ) ; checkFn -> insertAtTail ( new CallExpr ( PRIM_RETURN , returnTmp ) ) ; theProgram -> block -> insertAtTail ( new DefExpr ( checkFn ) ) ; normalize ( checkFn ) ; checkFn -> setInstantiationPoint ( info . call ) ; }
In order for fast followers to trigger, the invoking loop requires a static
and dynamic check.
In order for fast followers to trigger the invoking loop requires a static and dynamic check .