bool RSExportReduce::analyzeTranslationUnit() {

  RSContext &RSC = *getRSContext();
  clang::Preprocessor &PP = RSC.getPreprocessor();

  StateOfAnalyzeTranslationUnit S(
      RSC, PP, RSC.getASTContext(),
      [&PP, this] (const char *Key, const std::string &Name) {
        std::ostringstream Description;
        Description
            << Key << " " << Name << "()"
            << " for '#pragma rs " << KeyReduce << "(" << mNameReduce << ")'"
            << " (" << mLocation.printToString(PP.getSourceManager()) << ")";
        return Description.str();
      });

  S.FnInitializer  = lookupFunction(S, KeyInitializer,  mNameInitializer);
  S.FnAccumulator  = lookupFunction(S, KeyAccumulator,  mNameAccumulator);
  S.FnCombiner     = lookupFunction(S, KeyCombiner,     mNameCombiner);
  S.FnOutConverter = lookupFunction(S, KeyOutConverter, mNameOutConverter);
  S.FnHalter       = lookupFunction(S, KeyHalter,       mNameHalter);

  if (!S.Ok)
    return false;

  analyzeInitializer(S);
  analyzeAccumulator(S);
  analyzeCombiner(S);
  analyzeOutConverter(S);
  analyzeHalter(S);
  analyzeResultType(S);

  return S.Ok;
}
bool
RSExportFunc::checkParameterPacketType(llvm::StructType *ParamTy) const {
  if (ParamTy == NULL)
    return !hasParam();
  else if (!hasParam())
    return false;

  slangAssert(mParamPacketType != NULL);

  const RSExportRecordType *ERT = mParamPacketType;
  // must have same number of elements
  if (ERT->getFields().size() != ParamTy->getNumElements())
    return false;

  const llvm::StructLayout *ParamTySL =
      getRSContext()->getTargetData()->getStructLayout(ParamTy);

  unsigned Index = 0;
  for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(),
       FE = ERT->fields_end(); FI != FE; FI++, Index++) {
    const RSExportRecordType::Field *F = *FI;

    llvm::Type *T1 = F->getType()->getLLVMType();
    llvm::Type *T2 = ParamTy->getTypeAtIndex(Index);

    // Fast check
    if (T1 == T2)
      continue;

    // Check offset
    size_t T1Offset = F->getOffsetInParent();
    size_t T2Offset = ParamTySL->getElementOffset(Index);

    if (T1Offset != T2Offset)
      return false;

    // Check size
    size_t T1Size = RSExportType::GetTypeAllocSize(F->getType());
    size_t T2Size = getRSContext()->getTargetData()->getTypeAllocSize(T2);

    if (T1Size != T2Size)
      return false;
  }

  return true;
}
// does update S.Ok
clang::FunctionDecl *RSExportReduce::lookupFunction(StateOfAnalyzeTranslationUnit &S,
                                                    const char *Kind, const llvm::StringRef &Name) {
  if (Name.empty())
    return nullptr;

  clang::TranslationUnitDecl *TUDecl = getRSContext()->getASTContext().getTranslationUnitDecl();
  slangAssert(TUDecl);

  clang::FunctionDecl *Ret = nullptr;
  const clang::IdentifierInfo *II = S.PP.getIdentifierInfo(Name);
  if (II) {
    for (auto Decl : TUDecl->lookup(II)) {
      clang::FunctionDecl *FDecl = Decl->getAsFunction();
      if (!FDecl || !FDecl->isThisDeclarationADefinition())
        continue;
      if (Ret) {
        S.RSC.ReportError(mLocation,
                          "duplicate function definition for '%0(%1)' for '#pragma rs %2(%3)' (%4, %5)")
            << Kind << Name << KeyReduce << mNameReduce
            << Ret->getLocation().printToString(S.PP.getSourceManager())
            << FDecl->getLocation().printToString(S.PP.getSourceManager());
        S.Ok = false;
        return nullptr;
      }
      Ret = FDecl;
    }
  }
  if (!Ret) {
    // Either the identifier lookup failed, or we never found the function definition.
    S.RSC.ReportError(mLocation,
                      "could not find function definition for '%0(%1)' for '#pragma rs %2(%3)'")
        << Kind << Name << KeyReduce << mNameReduce;
    S.Ok = false;
    return nullptr;
  }
  if (Ret) {
    // Must have internal linkage
    if (Ret->getFormalLinkage() != clang::InternalLinkage) {
      S.RSC.ReportError(Ret->getLocation(), "%0 must be static")
          << S.DiagnosticDescription(Kind, Name);
      S.Ok = false;
    }
  }
  if (Ret == nullptr)
    S.Ok = false;
  return Ret;
}