<commit_before>//===------- SemaTemplateDeduction.cpp - Template Argument Deduction ------===/
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//===----------------------------------------------------------------------===/
//
//  This file implements C++ template argument deduction.
//
//===----------------------------------------------------------------------===/

#include "Sema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/Support/Compiler.h"
using namespace clang;

/// \brief If the given expression is of a form that permits the deduction
/// of a non-type template parameter, return the declaration of that
/// non-type template parameter.
static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) {
  if (ImplicitCastExpr *IC = dyn_cast<ImplicitCastExpr>(E))
    E = IC->getSubExpr();

  if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
    return dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl());

  return 0;
}

/// \brief Deduce the value of the given non-type template parameter
/// from the given constant.
///
/// \returns true if deduction succeeded, false otherwise.
static bool DeduceNonTypeTemplateArgument(ASTContext &Context,
                                          NonTypeTemplateParmDecl *NTTP,
                                          llvm::APInt Value,
                             llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
  assert(NTTP->getDepth() == 0 &&
         "Cannot deduce non-type template argument with depth > 0");

  if (Deduced[NTTP->getIndex()].isNull()) {
    Deduced[NTTP->getIndex()] = TemplateArgument(SourceLocation(),
                                                 llvm::APSInt(Value),
                                                 NTTP->getType());
    return true;
  }

  if (Deduced[NTTP->getIndex()].getKind() != TemplateArgument::Integral)
    return false;

  // If the template argument was previously deduced to a negative value,
  // then our deduction fails.
  const llvm::APSInt *PrevValuePtr = Deduced[NTTP->getIndex()].getAsIntegral();
  assert(PrevValuePtr && "Not an integral template argument?");
  if (PrevValuePtr->isSigned() && PrevValuePtr->isNegative())
    return false;

  llvm::APInt PrevValue = *PrevValuePtr;
  if (Value.getBitWidth() > PrevValue.getBitWidth())
    PrevValue.zext(Value.getBitWidth());
  else if (Value.getBitWidth() < PrevValue.getBitWidth())
    Value.zext(PrevValue.getBitWidth());
  return Value == PrevValue;
}

/// \brief Deduce the value of the given non-type template parameter
/// from the given type- or value-dependent expression.
///
/// \returns true if deduction succeeded, false otherwise.

static bool DeduceNonTypeTemplateArgument(ASTContext &Context,
                                          NonTypeTemplateParmDecl *NTTP,
                                          Expr *Value,
                            llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
  assert(NTTP->getDepth() == 0 &&
         "Cannot deduce non-type template argument with depth > 0");
  assert((Value->isTypeDependent() || Value->isValueDependent()) &&
         "Expression template argument must be type- or value-dependent.");

  if (Deduced[NTTP->getIndex()].isNull()) {
    // FIXME: Clone the Value?
    Deduced[NTTP->getIndex()] = TemplateArgument(Value);
    return true;
  }

  if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral) {
    // Okay, we deduced a constant in one case and a dependent expression
    // in another case. FIXME: Later, we will check that instantiating the
    // dependent expression gives us the constant value.
    return true;
  }

  // FIXME: Compare the expressions for equality!
  return true;
}

static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
                                    QualType Arg,
                             llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
  // We only want to look at the canonical types, since typedefs and
  // sugar are not part of template argument deduction.
  Param = Context.getCanonicalType(Param);
  Arg = Context.getCanonicalType(Arg);

  // If the parameter type is not dependent, just compare the types
  // directly.
  if (!Param->isDependentType())
    return Param == Arg;

  // C++ [temp.deduct.type]p9:
  //
  //   A template type argument T, a template template argument TT or a
  //   template non-type argument i can be deduced if P and A have one of
  //   the following forms:
  //
  //     T
  //     cv-list T
  if (const TemplateTypeParmType *TemplateTypeParm
        = Param->getAsTemplateTypeParmType()) {
    // The argument type can not be less qualified than the parameter
    // type.
    if (Param.isMoreQualifiedThan(Arg))
      return false;

    assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0");

    unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers();
    QualType DeducedType = Arg.getQualifiedType(Quals);
	  unsigned Index = TemplateTypeParm->getIndex();

    if (Deduced[Index].isNull())
      Deduced[Index] = TemplateArgument(SourceLocation(), DeducedType);
    else {
      // C++ [temp.deduct.type]p2:
      //   [...] If type deduction cannot be done for any P/A pair, or if for
      //   any pair the deduction leads to more than one possible set of
      //   deduced values, or if different pairs yield different deduced
      //   values, or if any template argument remains neither deduced nor
      //   explicitly specified, template argument deduction fails.
      if (Deduced[Index].getAsType() != DeducedType)
        return false;
    }
    return true;
  }

  if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
    return false;

  switch (Param->getTypeClass()) {
    // No deduction possible for these types
    case Type::Builtin:
      return false;

    //     T *
    case Type::Pointer: {
      const PointerType *PointerArg = Arg->getAsPointerType();
      if (!PointerArg)
        return false;

      return DeduceTemplateArguments(Context,
                                   cast<PointerType>(Param)->getPointeeType(),
                                     PointerArg->getPointeeType(),
                                     Deduced);
    }

    //     T &
    case Type::LValueReference: {
      const LValueReferenceType *ReferenceArg = Arg->getAsLValueReferenceType();
      if (!ReferenceArg)
        return false;

      return DeduceTemplateArguments(Context,
                           cast<LValueReferenceType>(Param)->getPointeeType(),
                                     ReferenceArg->getPointeeType(),
                                     Deduced);
    }

    //     T && [C++0x]
    case Type::RValueReference: {
      const RValueReferenceType *ReferenceArg = Arg->getAsRValueReferenceType();
      if (!ReferenceArg)
        return false;

      return DeduceTemplateArguments(Context,
                           cast<RValueReferenceType>(Param)->getPointeeType(),
                                     ReferenceArg->getPointeeType(),
                                     Deduced);
    }

    //     T [] (implied, but not stated explicitly)
    case Type::IncompleteArray: {
      const IncompleteArrayType *IncompleteArrayArg =
        Context.getAsIncompleteArrayType(Arg);
      if (!IncompleteArrayArg)
        return false;

      return DeduceTemplateArguments(Context,
                     Context.getAsIncompleteArrayType(Param)->getElementType(),
                                     IncompleteArrayArg->getElementType(),
                                     Deduced);
    }

    //     T [integer-constant]
    case Type::ConstantArray: {
      const ConstantArrayType *ConstantArrayArg =
        Context.getAsConstantArrayType(Arg);
      if (!ConstantArrayArg)
        return false;

      const ConstantArrayType *ConstantArrayParm =
        Context.getAsConstantArrayType(Param);
      if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize())
        return false;

      return DeduceTemplateArguments(Context,
                                     ConstantArrayParm->getElementType(),
                                     ConstantArrayArg->getElementType(),
                                     Deduced);
    }

    //     type [i]
    case Type::DependentSizedArray: {
      const ArrayType *ArrayArg = dyn_cast<ArrayType>(Arg);
      if (!ArrayArg)
        return false;

      // Check the element type of the arrays
      const DependentSizedArrayType *DependentArrayParm
        = cast<DependentSizedArrayType>(Param);
      if (!DeduceTemplateArguments(Context,
                                   DependentArrayParm->getElementType(),
                                   ArrayArg->getElementType(),
                                   Deduced))
        return false;

      // Determine the array bound is something we can deduce.
      NonTypeTemplateParmDecl *NTTP
        = getDeducedParameterFromExpr(DependentArrayParm->getSizeExpr());
      if (!NTTP)
        return true;

      // We can perform template argument deduction for the given non-type
      // template parameter.
      assert(NTTP->getDepth() == 0 &&
             "Cannot deduce non-type template argument at depth > 0");
      if (const ConstantArrayType *ConstantArrayArg
            = dyn_cast<ConstantArrayType>(ArrayArg))
        return DeduceNonTypeTemplateArgument(Context, NTTP,
                                             ConstantArrayArg->getSize(),
                                             Deduced);
      if (const DependentSizedArrayType *DependentArrayArg
            = dyn_cast<DependentSizedArrayType>(ArrayArg))
        return DeduceNonTypeTemplateArgument(Context, NTTP,
                                             DependentArrayArg->getSizeExpr(),
                                             Deduced);

      // Incomplete type does not match a dependently-sized array type
      return false;
    }

    case Type::FunctionProto: {
      const FunctionProtoType *FunctionProtoArg =
        dyn_cast<FunctionProtoType>(Arg);
      if (!FunctionProtoArg)
        return false;

      const FunctionProtoType *FunctionProtoParam =
        cast<FunctionProtoType>(Param);

      // Check return types.
      if (!DeduceTemplateArguments(Context,
                                   FunctionProtoParam->getResultType(),
                                   FunctionProtoArg->getResultType(),
                                   Deduced))
        return false;

      if (FunctionProtoParam->getNumArgs() != FunctionProtoArg->getNumArgs())
        return false;

      for (unsigned I = 0, N = FunctionProtoParam->getNumArgs(); I != N; ++I) {
        // Check argument types.
        if (!DeduceTemplateArguments(Context,
                                     FunctionProtoParam->getArgType(I),
                                     FunctionProtoArg->getArgType(I),
                                     Deduced))
          return false;
      }

      return true;
    }

    default:
      break;
  }

  // FIXME: Many more cases to go (to go).
  return false;
}

static bool
DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param,
                        const TemplateArgument &Arg,
                        llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
  switch (Param.getKind()) {
  case TemplateArgument::Null:
    assert(false && "Null template argument in parameter list");
    break;

  case TemplateArgument::Type:
    assert(Arg.getKind() == TemplateArgument::Type && "Type/value mismatch");
    return DeduceTemplateArguments(Context, Param.getAsType(),
                                   Arg.getAsType(), Deduced);

  case TemplateArgument::Declaration:
    // FIXME: Implement this check
    assert(false && "Unimplemented template argument deduction case");
    return false;

  case TemplateArgument::Integral:
    if (Arg.getKind() == TemplateArgument::Integral) {
      // FIXME: Zero extension + sign checking here?
      return *Param.getAsIntegral() == *Arg.getAsIntegral();
    }
    if (Arg.getKind() == TemplateArgument::Expression)
      return false;

    assert(false && "Type/value mismatch");
    return false;

  case TemplateArgument::Expression: {
    if (NonTypeTemplateParmDecl *NTTP
          = getDeducedParameterFromExpr(Param.getAsExpr())) {
      if (Arg.getKind() == TemplateArgument::Integral)
        // FIXME: Sign problems here
        return DeduceNonTypeTemplateArgument(Context, NTTP,
                                             *Arg.getAsIntegral(), Deduced);
      if (Arg.getKind() == TemplateArgument::Expression)
        return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsExpr(),
                                             Deduced);

      assert(false && "Type/value mismatch");
      return false;
    }

    // Can't deduce anything, but that's okay.
    return true;
  }
  }

  return true;
}

static bool
DeduceTemplateArguments(ASTContext &Context,
                        const TemplateArgumentList &ParamList,
                        const TemplateArgumentList &ArgList,
                        llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
  assert(ParamList.size() == ArgList.size());
  for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
    if (!DeduceTemplateArguments(Context, ParamList[I], ArgList[I], Deduced))
      return false;
  }
  return true;
}

TemplateArgumentList *
Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
                              const TemplateArgumentList &TemplateArgs) {
  // Deduce the template arguments for the partial specialization
  llvm::SmallVector<TemplateArgument, 4> Deduced;
  Deduced.resize(Partial->getTemplateParameters()->size());
  if (! ::DeduceTemplateArguments(Context, Partial->getTemplateArgs(),
                                  TemplateArgs, Deduced))
    return 0;

  // FIXME: Substitute the deduced template arguments into the template
  // arguments of the class template partial specialization; the resulting
  // template arguments should match TemplateArgs exactly.

  for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
    TemplateArgument &Arg = Deduced[I];

    // FIXME: If this template argument was not deduced, but the corresponding
    // template parameter has a default argument, instantiate the default
    // argument.
    if (Arg.isNull()) // FIXME: Result->Destroy(Context);
      return 0;

    if (Arg.getKind() == TemplateArgument::Integral) {
      // FIXME: Instantiate the type, but we need some context!
      const NonTypeTemplateParmDecl *Parm
        = cast<NonTypeTemplateParmDecl>(Partial->getTemplateParameters()
                                          ->getParam(I));
      //      QualType T = InstantiateType(Parm->getType(), *Result,
      //                                   Parm->getLocation(), Parm->getDeclName());
      //      if (T.isNull()) // FIXME: Result->Destroy(Context);
      //        return 0;
      QualType T = Parm->getType();

      // FIXME: Make sure we didn't overflow our data type!
      llvm::APSInt &Value = *Arg.getAsIntegral();
      unsigned AllowedBits = Context.getTypeSize(T);
      if (Value.getBitWidth() != AllowedBits)
        Value.extOrTrunc(AllowedBits);
      Value.setIsSigned(T->isSignedIntegerType());
      Arg.setIntegralType(T);
    }
  }

  // FIXME: This is terrible. DeduceTemplateArguments should use a
  // TemplateArgumentListBuilder directly.
  TemplateArgumentListBuilder Builder(Context);
  for (unsigned I = 0, N = Deduced.size(); I != N; ++I)
    Builder.push_back(Deduced[I]);

  return new (Context) TemplateArgumentList(Context, Builder, /*CopyArgs=*/true,
                                            /*FlattenArgs=*/true);
}
<commit_msg>Document the template argument deduction patterns that Anders' patch supports<commit_after>//===------- SemaTemplateDeduction.cpp - Template Argument Deduction ------===/
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//===----------------------------------------------------------------------===/
//
//  This file implements C++ template argument deduction.
//
//===----------------------------------------------------------------------===/

#include "Sema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/Support/Compiler.h"
using namespace clang;

/// \brief If the given expression is of a form that permits the deduction
/// of a non-type template parameter, return the declaration of that
/// non-type template parameter.
static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) {
  if (ImplicitCastExpr *IC = dyn_cast<ImplicitCastExpr>(E))
    E = IC->getSubExpr();

  if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
    return dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl());

  return 0;
}

/// \brief Deduce the value of the given non-type template parameter
/// from the given constant.
///
/// \returns true if deduction succeeded, false otherwise.
static bool DeduceNonTypeTemplateArgument(ASTContext &Context,
                                          NonTypeTemplateParmDecl *NTTP,
                                          llvm::APInt Value,
                             llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
  assert(NTTP->getDepth() == 0 &&
         "Cannot deduce non-type template argument with depth > 0");

  if (Deduced[NTTP->getIndex()].isNull()) {
    Deduced[NTTP->getIndex()] = TemplateArgument(SourceLocation(),
                                                 llvm::APSInt(Value),
                                                 NTTP->getType());
    return true;
  }

  if (Deduced[NTTP->getIndex()].getKind() != TemplateArgument::Integral)
    return false;

  // If the template argument was previously deduced to a negative value,
  // then our deduction fails.
  const llvm::APSInt *PrevValuePtr = Deduced[NTTP->getIndex()].getAsIntegral();
  assert(PrevValuePtr && "Not an integral template argument?");
  if (PrevValuePtr->isSigned() && PrevValuePtr->isNegative())
    return false;

  llvm::APInt PrevValue = *PrevValuePtr;
  if (Value.getBitWidth() > PrevValue.getBitWidth())
    PrevValue.zext(Value.getBitWidth());
  else if (Value.getBitWidth() < PrevValue.getBitWidth())
    Value.zext(PrevValue.getBitWidth());
  return Value == PrevValue;
}

/// \brief Deduce the value of the given non-type template parameter
/// from the given type- or value-dependent expression.
///
/// \returns true if deduction succeeded, false otherwise.

static bool DeduceNonTypeTemplateArgument(ASTContext &Context,
                                          NonTypeTemplateParmDecl *NTTP,
                                          Expr *Value,
                            llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
  assert(NTTP->getDepth() == 0 &&
         "Cannot deduce non-type template argument with depth > 0");
  assert((Value->isTypeDependent() || Value->isValueDependent()) &&
         "Expression template argument must be type- or value-dependent.");

  if (Deduced[NTTP->getIndex()].isNull()) {
    // FIXME: Clone the Value?
    Deduced[NTTP->getIndex()] = TemplateArgument(Value);
    return true;
  }

  if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral) {
    // Okay, we deduced a constant in one case and a dependent expression
    // in another case. FIXME: Later, we will check that instantiating the
    // dependent expression gives us the constant value.
    return true;
  }

  // FIXME: Compare the expressions for equality!
  return true;
}

static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
                                    QualType Arg,
                             llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
  // We only want to look at the canonical types, since typedefs and
  // sugar are not part of template argument deduction.
  Param = Context.getCanonicalType(Param);
  Arg = Context.getCanonicalType(Arg);

  // If the parameter type is not dependent, just compare the types
  // directly.
  if (!Param->isDependentType())
    return Param == Arg;

  // C++ [temp.deduct.type]p9:
  //
  //   A template type argument T, a template template argument TT or a
  //   template non-type argument i can be deduced if P and A have one of
  //   the following forms:
  //
  //     T
  //     cv-list T
  if (const TemplateTypeParmType *TemplateTypeParm
        = Param->getAsTemplateTypeParmType()) {
    // The argument type can not be less qualified than the parameter
    // type.
    if (Param.isMoreQualifiedThan(Arg))
      return false;

    assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0");

    unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers();
    QualType DeducedType = Arg.getQualifiedType(Quals);
	  unsigned Index = TemplateTypeParm->getIndex();

    if (Deduced[Index].isNull())
      Deduced[Index] = TemplateArgument(SourceLocation(), DeducedType);
    else {
      // C++ [temp.deduct.type]p2:
      //   [...] If type deduction cannot be done for any P/A pair, or if for
      //   any pair the deduction leads to more than one possible set of
      //   deduced values, or if different pairs yield different deduced
      //   values, or if any template argument remains neither deduced nor
      //   explicitly specified, template argument deduction fails.
      if (Deduced[Index].getAsType() != DeducedType)
        return false;
    }
    return true;
  }

  if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
    return false;

  switch (Param->getTypeClass()) {
    // No deduction possible for these types
    case Type::Builtin:
      return false;

    //     T *
    case Type::Pointer: {
      const PointerType *PointerArg = Arg->getAsPointerType();
      if (!PointerArg)
        return false;

      return DeduceTemplateArguments(Context,
                                   cast<PointerType>(Param)->getPointeeType(),
                                     PointerArg->getPointeeType(),
                                     Deduced);
    }

    //     T &
    case Type::LValueReference: {
      const LValueReferenceType *ReferenceArg = Arg->getAsLValueReferenceType();
      if (!ReferenceArg)
        return false;

      return DeduceTemplateArguments(Context,
                           cast<LValueReferenceType>(Param)->getPointeeType(),
                                     ReferenceArg->getPointeeType(),
                                     Deduced);
    }

    //     T && [C++0x]
    case Type::RValueReference: {
      const RValueReferenceType *ReferenceArg = Arg->getAsRValueReferenceType();
      if (!ReferenceArg)
        return false;

      return DeduceTemplateArguments(Context,
                           cast<RValueReferenceType>(Param)->getPointeeType(),
                                     ReferenceArg->getPointeeType(),
                                     Deduced);
    }

    //     T [] (implied, but not stated explicitly)
    case Type::IncompleteArray: {
      const IncompleteArrayType *IncompleteArrayArg =
        Context.getAsIncompleteArrayType(Arg);
      if (!IncompleteArrayArg)
        return false;

      return DeduceTemplateArguments(Context,
                     Context.getAsIncompleteArrayType(Param)->getElementType(),
                                     IncompleteArrayArg->getElementType(),
                                     Deduced);
    }

    //     T [integer-constant]
    case Type::ConstantArray: {
      const ConstantArrayType *ConstantArrayArg =
        Context.getAsConstantArrayType(Arg);
      if (!ConstantArrayArg)
        return false;

      const ConstantArrayType *ConstantArrayParm =
        Context.getAsConstantArrayType(Param);
      if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize())
        return false;

      return DeduceTemplateArguments(Context,
                                     ConstantArrayParm->getElementType(),
                                     ConstantArrayArg->getElementType(),
                                     Deduced);
    }

    //     type [i]
    case Type::DependentSizedArray: {
      const ArrayType *ArrayArg = dyn_cast<ArrayType>(Arg);
      if (!ArrayArg)
        return false;

      // Check the element type of the arrays
      const DependentSizedArrayType *DependentArrayParm
        = cast<DependentSizedArrayType>(Param);
      if (!DeduceTemplateArguments(Context,
                                   DependentArrayParm->getElementType(),
                                   ArrayArg->getElementType(),
                                   Deduced))
        return false;

      // Determine the array bound is something we can deduce.
      NonTypeTemplateParmDecl *NTTP
        = getDeducedParameterFromExpr(DependentArrayParm->getSizeExpr());
      if (!NTTP)
        return true;

      // We can perform template argument deduction for the given non-type
      // template parameter.
      assert(NTTP->getDepth() == 0 &&
             "Cannot deduce non-type template argument at depth > 0");
      if (const ConstantArrayType *ConstantArrayArg
            = dyn_cast<ConstantArrayType>(ArrayArg))
        return DeduceNonTypeTemplateArgument(Context, NTTP,
                                             ConstantArrayArg->getSize(),
                                             Deduced);
      if (const DependentSizedArrayType *DependentArrayArg
            = dyn_cast<DependentSizedArrayType>(ArrayArg))
        return DeduceNonTypeTemplateArgument(Context, NTTP,
                                             DependentArrayArg->getSizeExpr(),
                                             Deduced);

      // Incomplete type does not match a dependently-sized array type
      return false;
    }

    //     type(*)(T)
    //     T(*)()
    //     T(*)(T)
    case Type::FunctionProto: {
      const FunctionProtoType *FunctionProtoArg =
        dyn_cast<FunctionProtoType>(Arg);
      if (!FunctionProtoArg)
        return false;

      const FunctionProtoType *FunctionProtoParam =
        cast<FunctionProtoType>(Param);

      // Check return types.
      if (!DeduceTemplateArguments(Context,
                                   FunctionProtoParam->getResultType(),
                                   FunctionProtoArg->getResultType(),
                                   Deduced))
        return false;

      if (FunctionProtoParam->getNumArgs() != FunctionProtoArg->getNumArgs())
        return false;

      for (unsigned I = 0, N = FunctionProtoParam->getNumArgs(); I != N; ++I) {
        // Check argument types.
        if (!DeduceTemplateArguments(Context,
                                     FunctionProtoParam->getArgType(I),
                                     FunctionProtoArg->getArgType(I),
                                     Deduced))
          return false;
      }

      return true;
    }

    default:
      break;
  }

  // FIXME: Many more cases to go (to go).
  return false;
}

static bool
DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param,
                        const TemplateArgument &Arg,
                        llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
  switch (Param.getKind()) {
  case TemplateArgument::Null:
    assert(false && "Null template argument in parameter list");
    break;

  case TemplateArgument::Type:
    assert(Arg.getKind() == TemplateArgument::Type && "Type/value mismatch");
    return DeduceTemplateArguments(Context, Param.getAsType(),
                                   Arg.getAsType(), Deduced);

  case TemplateArgument::Declaration:
    // FIXME: Implement this check
    assert(false && "Unimplemented template argument deduction case");
    return false;

  case TemplateArgument::Integral:
    if (Arg.getKind() == TemplateArgument::Integral) {
      // FIXME: Zero extension + sign checking here?
      return *Param.getAsIntegral() == *Arg.getAsIntegral();
    }
    if (Arg.getKind() == TemplateArgument::Expression)
      return false;

    assert(false && "Type/value mismatch");
    return false;

  case TemplateArgument::Expression: {
    if (NonTypeTemplateParmDecl *NTTP
          = getDeducedParameterFromExpr(Param.getAsExpr())) {
      if (Arg.getKind() == TemplateArgument::Integral)
        // FIXME: Sign problems here
        return DeduceNonTypeTemplateArgument(Context, NTTP,
                                             *Arg.getAsIntegral(), Deduced);
      if (Arg.getKind() == TemplateArgument::Expression)
        return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsExpr(),
                                             Deduced);

      assert(false && "Type/value mismatch");
      return false;
    }

    // Can't deduce anything, but that's okay.
    return true;
  }
  }

  return true;
}

static bool
DeduceTemplateArguments(ASTContext &Context,
                        const TemplateArgumentList &ParamList,
                        const TemplateArgumentList &ArgList,
                        llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
  assert(ParamList.size() == ArgList.size());
  for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
    if (!DeduceTemplateArguments(Context, ParamList[I], ArgList[I], Deduced))
      return false;
  }
  return true;
}

TemplateArgumentList *
Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
                              const TemplateArgumentList &TemplateArgs) {
  // Deduce the template arguments for the partial specialization
  llvm::SmallVector<TemplateArgument, 4> Deduced;
  Deduced.resize(Partial->getTemplateParameters()->size());
  if (! ::DeduceTemplateArguments(Context, Partial->getTemplateArgs(),
                                  TemplateArgs, Deduced))
    return 0;

  // FIXME: Substitute the deduced template arguments into the template
  // arguments of the class template partial specialization; the resulting
  // template arguments should match TemplateArgs exactly.

  for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
    TemplateArgument &Arg = Deduced[I];

    // FIXME: If this template argument was not deduced, but the corresponding
    // template parameter has a default argument, instantiate the default
    // argument.
    if (Arg.isNull()) // FIXME: Result->Destroy(Context);
      return 0;

    if (Arg.getKind() == TemplateArgument::Integral) {
      // FIXME: Instantiate the type, but we need some context!
      const NonTypeTemplateParmDecl *Parm
        = cast<NonTypeTemplateParmDecl>(Partial->getTemplateParameters()
                                          ->getParam(I));
      //      QualType T = InstantiateType(Parm->getType(), *Result,
      //                                   Parm->getLocation(), Parm->getDeclName());
      //      if (T.isNull()) // FIXME: Result->Destroy(Context);
      //        return 0;
      QualType T = Parm->getType();

      // FIXME: Make sure we didn't overflow our data type!
      llvm::APSInt &Value = *Arg.getAsIntegral();
      unsigned AllowedBits = Context.getTypeSize(T);
      if (Value.getBitWidth() != AllowedBits)
        Value.extOrTrunc(AllowedBits);
      Value.setIsSigned(T->isSignedIntegerType());
      Arg.setIntegralType(T);
    }
  }

  // FIXME: This is terrible. DeduceTemplateArguments should use a
  // TemplateArgumentListBuilder directly.
  TemplateArgumentListBuilder Builder(Context);
  for (unsigned I = 0, N = Deduced.size(); I != N; ++I)
    Builder.push_back(Deduced[I]);

  return new (Context) TemplateArgumentList(Context, Builder, /*CopyArgs=*/true,
                                            /*FlattenArgs=*/true);
}
<|endoftext|>


<commit_before>
// Copyright 2010-2012 University of Washington. All Rights Reserved.
// LICENSE_PLACEHOLDER
// This software was created with Government support under DE
// AC05-76RL01830 awarded by the United States Department of
// Energy. The Government has certain rights in the software.

#ifndef __DELEGATE_HPP__
#define __DELEGATE_HPP__

#include "Grappa.hpp"
#include "Message.hpp"
#include "FullEmptyLocal.hpp"
#include "Message.hpp"
#include "ConditionVariable.hpp"
#include "LegacyDelegate.hpp"
#include "MessagePool.hpp"
#include <type_traits>

GRAPPA_DECLARE_STAT(SummarizingStatistic<uint64_t>, flat_combiner_fetch_and_add_amount);
GRAPPA_DECLARE_STAT(SimpleStatistic<uint64_t>, delegate_ops_short_circuited);

GRAPPA_DECLARE_STAT(SummarizingStatistic<double>, delegate_op_roundtrip_latency);

namespace Grappa {
    /// @addtogroup Delegates
    /// @{

  namespace impl {

    /// Overloaded version for func with void return type.
    template <typename F>
    inline void call(Core dest, F func, void (F::*mf)() const) {
      delegate_stats.count_op();
      Core origin = Grappa::mycore();

      if (dest == origin) {
        // short-circuit if local
        delegate_ops_short_circuited++;
        return func();
      } else {
        int64_t network_time = 0;
        int64_t start_time = Grappa_get_timestamp();
        FullEmpty<bool> result;
        send_message(dest, [&result, origin, func, &network_time, start_time] {
          delegate_stats.count_op_am();

          func();

          // TODO: replace with handler-safe send_message
          send_heap_message(origin, [&result, &network_time, start_time] {
            network_time = Grappa_get_timestamp();
            delegate_stats.record_network_latency(start_time);
            result.writeXF(true);
          });
        }); // send message

        // ... and wait for the call to complete
        result.readFF();
        delegate_stats.record_wakeup_latency(start_time, network_time);
        return;
      }
    }

    template <typename F>
    inline auto call(Core dest, F func, decltype(func()) (F::*mf)() const) -> decltype(func()) {
      // Note: code below (calling call_async) could be used to avoid duplication of code,
      // but call_async adds some overhead (object creation overhead, especially for short
      // -circuit case and extra work in MessagePool)
      //   AsyncHandle<decltype(func())> a;
      //   MessagePool<sizeof(Message<F>)> pool;
      //   a.call_async(pool, dest, func);
      //   return a.get_result();
      // TODO: find a way to implement using async version that doesn't introduce overhead

      delegate_stats.count_op();
      using R = decltype(func());
      Core origin = Grappa::mycore();

      if (dest == origin) {
        // short-circuit if local
        delegate_ops_short_circuited++;
        return func();
      } else {
        FullEmpty<R> result;
        int64_t network_time = 0;
        int64_t start_time = Grappa_get_timestamp();

        send_message(dest, [&result, origin, func, &network_time, start_time] {
          delegate_stats.count_op_am();
          R val = func();

          // TODO: replace with handler-safe send_message
          send_heap_message(origin, [&result, val, &network_time, start_time] {
            network_time = Grappa_get_timestamp();
            delegate_stats.record_network_latency(start_time);
            result.writeXF(val); // can't block in message, assumption is that result is already empty
          });
        }); // send message
        // ... and wait for the result
        R r = result.readFE();
        delegate_stats.record_wakeup_latency(start_time, network_time);
        return r;
      }
    }

  } // namespace impl

  namespace delegate {

    /// Implements essentially a blocking remote procedure call. Callable object (lambda,
    /// function pointer, or functor object) is called from the `dest` core and the return
    /// value is sent back to the calling task.
    template <typename F>
    inline auto call(Core dest, F func) -> decltype(func()) {
      return impl::call(dest, func, &F::operator());
    }

    /// Helper that makes it easier to implement custom delegate operations on global
    /// addresses specifically.
    ///
    /// Example:
    /// @code
    ///   GlobalAddress<int> xa;
    ///   bool is_zero = delegate::call(xa, [](int* x){ return *x == 0; });
    /// @endcode
    template< typename T, typename F >
    inline auto call(GlobalAddress<T> target, F func) -> decltype(func(target.pointer())) {
      return call(target.core(), [target,func]{ return func(target.pointer()); });
    }

    /// Try lock on remote mutex. Does *not* lock or unlock, suspends if lock has already
    /// been taken.
    template< typename M, typename F >
    inline auto call(Core dest, M mutex, F func) -> decltype(func(mutex())) {
      using R = decltype(func(mutex()));
      delegate_stats.count_op();

      if (dest == mycore()) {
        delegate_ops_short_circuited++;
        // auto l = mutex();
        // lock(l);
        auto r = func(mutex());
        // unlock(l);
        return r;
      } else {
        FullEmpty<R> result;
        auto result_addr = make_global(&result);
        auto set_result = [result_addr](const R& val){
          send_heap_message(result_addr.core(), [result_addr,val]{
            result_addr->writeXF(val);
          });
        };

        send_message(dest, [set_result,mutex,func] {
          auto l = mutex();
          if (is_unlocked(l)) { // if lock is not held
            // lock(l);
            set_result(func(l));
          } else {
            add_waiter(l, new_continuation([set_result,func,l]{
              // lock(l);
              CHECK(is_unlocked(l));
              set_result(func(l));
            }));
          }
        });
        auto r = result.readFE();
        return r;
      }
    }

    template <typename F>
    inline auto call_suspendable(Core dest, F func) -> decltype(func()) {
      delegate_stats.count_op();
      using R = decltype(func());
      Core origin = Grappa::mycore();

      if (dest == origin) {
        delegate_ops_short_circuited++;
        return func();
      } else {
        FullEmpty<R> result;
        int64_t network_time = 0;
        int64_t start_time = Grappa_get_timestamp();

        send_message(dest, [&result, origin, func, &network_time, start_time] {
          delegate_stats.count_op_am();

          privateTask([&result, origin, func, &network_time, start_time] {
            R val = func();
            // TODO: replace with handler-safe send_message
            send_heap_message(origin, [&result, val, &network_time, start_time] {
              network_time = Grappa_get_timestamp();
              delegate_stats.record_network_latency(start_time);
              result.writeXF(val); // can't block in message, assumption is that result is already empty
            });
          });
        }); // send message
        // ... and wait for the result
        R r = result.readFE();
        delegate_stats.record_wakeup_latency(start_time, network_time);
        return r;
      }
    }

    /// Read the value (potentially remote) at the given GlobalAddress, blocks the calling task until
    /// round-trip communication is complete.
    /// @warning Target object must lie on a single node (not span blocks in global address space).
    template< typename T >
    T read(GlobalAddress<T> target) {
      delegate_stats.count_word_read();
      return call(target.node(), [target]() -> T {
        delegate_stats.count_word_read_am();
        return *target.pointer();
      });
    }

    /// Blocking remote write.
    /// @warning Target object must lie on a single node (not span blocks in global address space).
    template< typename T, typename U >
    void write(GlobalAddress<T> target, U value) {
      delegate_stats.count_word_write();
      // TODO: don't return any val, requires changes to `delegate::call()`.
      return call(target.node(), [target, value] {
        delegate_stats.count_word_write_am();
        *target.pointer() = value;
      });
    }

    /// Fetch the value at `target`, increment the value stored there with `inc` and return the
    /// original value to blocking thread.
    /// @warning Target object must lie on a single node (not span blocks in global address space).
    template< typename T, typename U >
    T fetch_and_add(GlobalAddress<T> target, U inc) {
      delegate_stats.count_word_fetch_add();
      return call(target.node(), [target, inc]() -> T {
        delegate_stats.count_word_fetch_add_am();
        T* p = target.pointer();
        T r = *p;
        *p += inc;
        return r;
      });
    }

    /// Flat combines fetch_and_add to a single global address
    /// @warning Target object must lie on a single node (not span blocks in global address space).
    template < typename T, typename U >
    class FlatCombiner {
      // TODO: generalize to define other types of combiners
      private:
        // configuration
        const GlobalAddress<T> target;
        const U initVal;
        const uint64_t flush_threshold;

        // state
        T result;
        U increment;
        uint64_t committed;
        uint64_t participant_count;
        uint64_t ready_waiters;
        bool outstanding;
        ConditionVariable untilNotOutstanding;
        ConditionVariable untilReceived;

        // wait until fetch add unit is in aggregate mode
        // TODO: add concurrency (multiple fetch add units)
        void block_until_ready() {
          while ( outstanding ) {
            ready_waiters++;
            Grappa::wait(&untilNotOutstanding);
            ready_waiters--;
          }
        }

        void set_ready() {
          outstanding = false;
          Grappa::broadcast(&untilNotOutstanding);
        }

        void set_not_ready() {
          outstanding = true;
        }

      public:
        FlatCombiner( GlobalAddress<T> target, uint64_t flush_threshold, U initVal )
         : target( target )
         , initVal( initVal )
         , flush_threshold( flush_threshold )
         , result()
         , increment( initVal )
         , committed( 0 )
         , participant_count( 0 )
         , ready_waiters( 0 )
         , outstanding( false )
         , untilNotOutstanding()
         , untilReceived()
         {}

        /// Promise that in the future
        /// you will call `fetch_and_add`.
        ///
        /// Must be called before a call to `fetch_and_add`
        ///
        /// After calling promise, this task must NOT have a dependence on any
        /// `fetch_and_add` occurring before it calls `fetch_and_add` itself
        /// or deadlock may occur.
        ///
        /// For good performance, should allow other
        /// tasks to run before calling `fetch_and_add`
        void promise() {
          committed += 1;
        }
        // because tasks run serially, promise() replaces the flat combining tree

        T fetch_and_add( U inc ) {

          block_until_ready();

          // fetch add unit is now aggregating so add my inc

          participant_count++;
          committed--;
          increment += inc;

          // if I'm the last entered client and either the flush threshold
          // is reached or there are no more committed participants then start the flush
          if ( ready_waiters == 0 && (participant_count >= flush_threshold || committed == 0 )) {
            set_not_ready();
            uint64_t increment_total = increment;
            flat_combiner_fetch_and_add_amount += increment_total;
            auto t = target;
            result = call(target.node(), [t, increment_total]() -> U {
              T * p = t.pointer();
              uint64_t r = *p;
              *p += increment_total;
              return r;
            });
            // tell the others that the result has arrived
            Grappa::broadcast(&untilReceived);
          } else {
            // someone else will start the flush
            Grappa::wait(&untilReceived);
          }

          uint64_t my_start = result;
          result += inc;
          participant_count--;
          increment -= inc;   // for validation purposes (could just set to 0)
          CHECK( increment >= 0 );
          if ( participant_count == 0 ) {
            CHECK( increment == 0 ) << "increment = " << increment << " even though all participants are done";
            set_ready();
          }

          return my_start;
        }
    };

    /// If value at `target` equals `cmp_val`, set the value to `new_val` and return `true`,
    /// otherwise do nothing and return `false`.
    /// @warning Target object must lie on a single node (not span blocks in global address space).
    template< typename T, typename U, typename V >
    bool compare_and_swap(GlobalAddress<T> target, U cmp_val, V new_val) {
      delegate_stats.count_word_compare_swap();
      return call(target.node(), [target, cmp_val, new_val]() -> bool {
        T * p = target.pointer();
        delegate_stats.count_word_compare_swap_am();
        if (cmp_val == *p) {
          *p = new_val;
          return true;
        } else {
          return false;
        }
      });
    }

    /// @}
  } // namespace delegate
} // namespace Grappa

#endif
<commit_msg>Add documentation for delegate::call_suspendable<commit_after>
// Copyright 2010-2012 University of Washington. All Rights Reserved.
// LICENSE_PLACEHOLDER
// This software was created with Government support under DE
// AC05-76RL01830 awarded by the United States Department of
// Energy. The Government has certain rights in the software.

#ifndef __DELEGATE_HPP__
#define __DELEGATE_HPP__

#include "Grappa.hpp"
#include "Message.hpp"
#include "FullEmptyLocal.hpp"
#include "Message.hpp"
#include "ConditionVariable.hpp"
#include "LegacyDelegate.hpp"
#include "MessagePool.hpp"
#include <type_traits>

GRAPPA_DECLARE_STAT(SummarizingStatistic<uint64_t>, flat_combiner_fetch_and_add_amount);
GRAPPA_DECLARE_STAT(SimpleStatistic<uint64_t>, delegate_ops_short_circuited);

GRAPPA_DECLARE_STAT(SummarizingStatistic<double>, delegate_op_roundtrip_latency);

namespace Grappa {
    /// @addtogroup Delegates
    /// @{

  namespace impl {

    /// Overloaded version for func with void return type.
    template <typename F>
    inline void call(Core dest, F func, void (F::*mf)() const) {
      delegate_stats.count_op();
      Core origin = Grappa::mycore();

      if (dest == origin) {
        // short-circuit if local
        delegate_ops_short_circuited++;
        return func();
      } else {
        int64_t network_time = 0;
        int64_t start_time = Grappa_get_timestamp();
        FullEmpty<bool> result;
        send_message(dest, [&result, origin, func, &network_time, start_time] {
          delegate_stats.count_op_am();

          func();

          // TODO: replace with handler-safe send_message
          send_heap_message(origin, [&result, &network_time, start_time] {
            network_time = Grappa_get_timestamp();
            delegate_stats.record_network_latency(start_time);
            result.writeXF(true);
          });
        }); // send message

        // ... and wait for the call to complete
        result.readFF();
        delegate_stats.record_wakeup_latency(start_time, network_time);
        return;
      }
    }

    template <typename F>
    inline auto call(Core dest, F func, decltype(func()) (F::*mf)() const) -> decltype(func()) {
      // Note: code below (calling call_async) could be used to avoid duplication of code,
      // but call_async adds some overhead (object creation overhead, especially for short
      // -circuit case and extra work in MessagePool)
      //   AsyncHandle<decltype(func())> a;
      //   MessagePool<sizeof(Message<F>)> pool;
      //   a.call_async(pool, dest, func);
      //   return a.get_result();
      // TODO: find a way to implement using async version that doesn't introduce overhead

      delegate_stats.count_op();
      using R = decltype(func());
      Core origin = Grappa::mycore();

      if (dest == origin) {
        // short-circuit if local
        delegate_ops_short_circuited++;
        return func();
      } else {
        FullEmpty<R> result;
        int64_t network_time = 0;
        int64_t start_time = Grappa_get_timestamp();

        send_message(dest, [&result, origin, func, &network_time, start_time] {
          delegate_stats.count_op_am();
          R val = func();

          // TODO: replace with handler-safe send_message
          send_heap_message(origin, [&result, val, &network_time, start_time] {
            network_time = Grappa_get_timestamp();
            delegate_stats.record_network_latency(start_time);
            result.writeXF(val); // can't block in message, assumption is that result is already empty
          });
        }); // send message
        // ... and wait for the result
        R r = result.readFE();
        delegate_stats.record_wakeup_latency(start_time, network_time);
        return r;
      }
    }

  } // namespace impl

  namespace delegate {

    /// Implements essentially a blocking remote procedure call. Callable object (lambda,
    /// function pointer, or functor object) is called from the `dest` core and the return
    /// value is sent back to the calling task.
    template <typename F>
    inline auto call(Core dest, F func) -> decltype(func()) {
      return impl::call(dest, func, &F::operator());
    }

    /// Helper that makes it easier to implement custom delegate operations on global
    /// addresses specifically.
    ///
    /// Example:
    /// @code
    ///   GlobalAddress<int> xa;
    ///   bool is_zero = delegate::call(xa, [](int* x){ return *x == 0; });
    /// @endcode
    template< typename T, typename F >
    inline auto call(GlobalAddress<T> target, F func) -> decltype(func(target.pointer())) {
      return call(target.core(), [target,func]{ return func(target.pointer()); });
    }

    /// Try lock on remote mutex. Does \b not lock or unlock, creates a Continuation if lock has already
    /// been taken, which is triggered on unlocking of the Mutex.
    template< typename M, typename F >
    inline auto call(Core dest, M mutex, F func) -> decltype(func(mutex())) {
      using R = decltype(func(mutex()));
      delegate_stats.count_op();

      if (dest == mycore()) {
        delegate_ops_short_circuited++;
        // auto l = mutex();
        // lock(l);
        auto r = func(mutex());
        // unlock(l);
        return r;
      } else {
        FullEmpty<R> result;
        auto result_addr = make_global(&result);
        auto set_result = [result_addr](const R& val){
          send_heap_message(result_addr.core(), [result_addr,val]{
            result_addr->writeXF(val);
          });
        };

        send_message(dest, [set_result,mutex,func] {
          auto l = mutex();
          if (is_unlocked(l)) { // if lock is not held
            // lock(l);
            set_result(func(l));
          } else {
            add_waiter(l, new_continuation([set_result,func,l]{
              // lock(l);
              CHECK(is_unlocked(l));
              set_result(func(l));
            }));
          }
        });
        auto r = result.readFE();
        return r;
      }
    }

    /// Alternative version of delegate::call that spawns a privateTask to allow the delegate
    /// to perform suspending actions.
    ///
    /// @note Use of this is not advised: suspending violates much of the assumptions about
    /// delegates we usually make, and can easily cause deadlock if no workers are available
    /// to execute the spawned privateTask. A better option for possibly-blocking delegates
    /// is to use the Mutex version of delegate::call(Core,M,F).
    template <typename F>
    inline auto call_suspendable(Core dest, F func) -> decltype(func()) {
      delegate_stats.count_op();
      using R = decltype(func());
      Core origin = Grappa::mycore();

      if (dest == origin) {
        delegate_ops_short_circuited++;
        return func();
      } else {
        FullEmpty<R> result;
        int64_t network_time = 0;
        int64_t start_time = Grappa_get_timestamp();

        send_message(dest, [&result, origin, func, &network_time, start_time] {
          delegate_stats.count_op_am();

          privateTask([&result, origin, func, &network_time, start_time] {
            R val = func();
            // TODO: replace with handler-safe send_message
            send_heap_message(origin, [&result, val, &network_time, start_time] {
              network_time = Grappa_get_timestamp();
              delegate_stats.record_network_latency(start_time);
              result.writeXF(val); // can't block in message, assumption is that result is already empty
            });
          });
        }); // send message
        // ... and wait for the result
        R r = result.readFE();
        delegate_stats.record_wakeup_latency(start_time, network_time);
        return r;
      }
    }

    /// Read the value (potentially remote) at the given GlobalAddress, blocks the calling task until
    /// round-trip communication is complete.
    /// @warning Target object must lie on a single node (not span blocks in global address space).
    template< typename T >
    T read(GlobalAddress<T> target) {
      delegate_stats.count_word_read();
      return call(target.node(), [target]() -> T {
        delegate_stats.count_word_read_am();
        return *target.pointer();
      });
    }

    /// Blocking remote write.
    /// @warning Target object must lie on a single node (not span blocks in global address space).
    template< typename T, typename U >
    void write(GlobalAddress<T> target, U value) {
      delegate_stats.count_word_write();
      // TODO: don't return any val, requires changes to `delegate::call()`.
      return call(target.node(), [target, value] {
        delegate_stats.count_word_write_am();
        *target.pointer() = value;
      });
    }

    /// Fetch the value at `target`, increment the value stored there with `inc` and return the
    /// original value to blocking thread.
    /// @warning Target object must lie on a single node (not span blocks in global address space).
    template< typename T, typename U >
    T fetch_and_add(GlobalAddress<T> target, U inc) {
      delegate_stats.count_word_fetch_add();
      return call(target.node(), [target, inc]() -> T {
        delegate_stats.count_word_fetch_add_am();
        T* p = target.pointer();
        T r = *p;
        *p += inc;
        return r;
      });
    }

    /// Flat combines fetch_and_add to a single global address
    /// @warning Target object must lie on a single node (not span blocks in global address space).
    template < typename T, typename U >
    class FlatCombiner {
      // TODO: generalize to define other types of combiners
      private:
        // configuration
        const GlobalAddress<T> target;
        const U initVal;
        const uint64_t flush_threshold;

        // state
        T result;
        U increment;
        uint64_t committed;
        uint64_t participant_count;
        uint64_t ready_waiters;
        bool outstanding;
        ConditionVariable untilNotOutstanding;
        ConditionVariable untilReceived;

        // wait until fetch add unit is in aggregate mode
        // TODO: add concurrency (multiple fetch add units)
        void block_until_ready() {
          while ( outstanding ) {
            ready_waiters++;
            Grappa::wait(&untilNotOutstanding);
            ready_waiters--;
          }
        }

        void set_ready() {
          outstanding = false;
          Grappa::broadcast(&untilNotOutstanding);
        }

        void set_not_ready() {
          outstanding = true;
        }

      public:
        FlatCombiner( GlobalAddress<T> target, uint64_t flush_threshold, U initVal )
         : target( target )
         , initVal( initVal )
         , flush_threshold( flush_threshold )
         , result()
         , increment( initVal )
         , committed( 0 )
         , participant_count( 0 )
         , ready_waiters( 0 )
         , outstanding( false )
         , untilNotOutstanding()
         , untilReceived()
         {}

        /// Promise that in the future
        /// you will call `fetch_and_add`.
        ///
        /// Must be called before a call to `fetch_and_add`
        ///
        /// After calling promise, this task must NOT have a dependence on any
        /// `fetch_and_add` occurring before it calls `fetch_and_add` itself
        /// or deadlock may occur.
        ///
        /// For good performance, should allow other
        /// tasks to run before calling `fetch_and_add`
        void promise() {
          committed += 1;
        }
        // because tasks run serially, promise() replaces the flat combining tree

        T fetch_and_add( U inc ) {

          block_until_ready();

          // fetch add unit is now aggregating so add my inc

          participant_count++;
          committed--;
          increment += inc;

          // if I'm the last entered client and either the flush threshold
          // is reached or there are no more committed participants then start the flush
          if ( ready_waiters == 0 && (participant_count >= flush_threshold || committed == 0 )) {
            set_not_ready();
            uint64_t increment_total = increment;
            flat_combiner_fetch_and_add_amount += increment_total;
            auto t = target;
            result = call(target.node(), [t, increment_total]() -> U {
              T * p = t.pointer();
              uint64_t r = *p;
              *p += increment_total;
              return r;
            });
            // tell the others that the result has arrived
            Grappa::broadcast(&untilReceived);
          } else {
            // someone else will start the flush
            Grappa::wait(&untilReceived);
          }

          uint64_t my_start = result;
          result += inc;
          participant_count--;
          increment -= inc;   // for validation purposes (could just set to 0)
          CHECK( increment >= 0 );
          if ( participant_count == 0 ) {
            CHECK( increment == 0 ) << "increment = " << increment << " even though all participants are done";
            set_ready();
          }

          return my_start;
        }
    };

    /// If value at `target` equals `cmp_val`, set the value to `new_val` and return `true`,
    /// otherwise do nothing and return `false`.
    /// @warning Target object must lie on a single node (not span blocks in global address space).
    template< typename T, typename U, typename V >
    bool compare_and_swap(GlobalAddress<T> target, U cmp_val, V new_val) {
      delegate_stats.count_word_compare_swap();
      return call(target.node(), [target, cmp_val, new_val]() -> bool {
        T * p = target.pointer();
        delegate_stats.count_word_compare_swap_am();
        if (cmp_val == *p) {
          *p = new_val;
          return true;
        } else {
          return false;
        }
      });
    }

    /// @}
  } // namespace delegate
} // namespace Grappa

#endif
<|endoftext|>


<commit_before>
// Copyright 2010-2012 University of Washington. All Rights Reserved.
// LICENSE_PLACEHOLDER
// This software was created with Government support under DE
// AC05-76RL01830 awarded by the United States Department of
// Energy. The Government has certain rights in the software.

#ifndef __DELEGATE_HPP__
#define __DELEGATE_HPP__

#include "Grappa.hpp"
#include "Message.hpp"
#include "FullEmpty.hpp"
#include "Message.hpp"
#include "ConditionVariable.hpp"
#include "LegacyDelegate.hpp"
#include "MessagePool.hpp"
#include <type_traits>

GRAPPA_DECLARE_STAT(SummarizingStatistic<uint64_t>, flat_combiner_fetch_and_add_amount);
GRAPPA_DECLARE_STAT(SimpleStatistic<uint64_t>, delegate_ops_short_circuited);

namespace Grappa {
  namespace delegate {
    /// @addtogroup Delegates
    /// @{

    template <typename F>
    inline auto call(Core dest, F func)
        -> typename std::enable_if<std::is_void<decltype(func())>::value, void>::type {
      delegate_stats.count_op();
      Core origin = Grappa::mycore();

      if (dest == origin) {
        // short-circuit if local
        delegate_ops_short_circuited++;
        return func();
      } else {
        int64_t network_time = 0;
        int64_t start_time = Grappa_get_timestamp();
        ConditionVariable cv;
        send_message(dest, [&cv, origin, func, &network_time, start_time] {
          delegate_stats.count_op_am();

          func();

          // TODO: replace with handler-safe send_message
          send_heap_message(origin, [&cv, &network_time, start_time] {
            network_time = Grappa_get_timestamp();
            delegate_stats.record_network_latency(start_time);
            signal(&cv);
          });
        }); // send message

        // ... and wait for the call to complete
        wait(&cv);
        delegate_stats.record_wakeup_latency(start_time, network_time);
        return;
      }
    }

    /// Implements essentially a blocking remote procedure call. Callable object (lambda,
    /// function pointer, or functor object) is called from the `dest` core and the return
    /// value is sent back to the calling task.
    template <typename F>
    inline auto call(Core dest, F func)
      -> typename std::enable_if<!std::is_void<decltype(func())>::value, decltype(func())>::type {
      // Note: code below (calling call_async) could be used to avoid duplication of code,
      // but call_async adds some overhead (object creation overhead, especially for short
      // -circuit case and extra work in MessagePool)
      //   AsyncHandle<decltype(func())> a;
      //   MessagePool<sizeof(Message<F>)> pool;
      //   a.call_async(pool, dest, func);
      //   return a.get_result();
      // TODO: find a way to implement using async version that doesn't introduce overhead

      delegate_stats.count_op();
      using R = decltype(func());
      Core origin = Grappa::mycore();

      if (dest == origin) {
        // short-circuit if local
        return func();
      } else {
        FullEmpty<R> result;
        int64_t network_time = 0;
        int64_t start_time = Grappa_get_timestamp();

        send_message(dest, [&result, origin, func, &network_time, start_time] {
          delegate_stats.count_op_am();
          R val = func();

          // TODO: replace with handler-safe send_message
          send_heap_message(origin, [&result, val, &network_time, start_time] {
            network_time = Grappa_get_timestamp();
            delegate_stats.record_network_latency(start_time);
            result.writeXF(val); // can't block in message, assumption is that result is already empty
          });
        }); // send message
        // ... and wait for the result
        R r = result.readFE();
        delegate_stats.record_wakeup_latency(start_time, network_time);
        return r;
      }
    }

    /// Read the value (potentially remote) at the given GlobalAddress, blocks the calling task until
    /// round-trip communication is complete.
    /// @warning { Target object must lie on a single node (not span blocks in global address space). }
    template< typename T >
    T read(GlobalAddress<T> target) {
      delegate_stats.count_word_read();
      return call(target.node(), [target]() -> T {
        delegate_stats.count_word_read_am();
        return *target.pointer();
      });
    }

    /// Blocking remote write.
    /// @warning { Target object must lie on a single node (not span blocks in global address space). }
    template< typename T, typename U >
    void write(GlobalAddress<T> target, U value) {
      delegate_stats.count_word_write();
      // TODO: don't return any val, requires changes to `delegate::call()`.
      return call(target.node(), [target, value] {
        delegate_stats.count_word_write_am();
        *target.pointer() = value;
      });
    }

    /// Fetch the value at `target`, increment the value stored there with `inc` and return the
    /// original value to blocking thread.
    /// @warning { Target object must lie on a single node (not span blocks in global address space). }
    template< typename T, typename U >
    T fetch_and_add(GlobalAddress<T> target, U inc) {
      delegate_stats.count_word_fetch_add();
      T * p = target.pointer();
      return call(target.node(), [p, inc]() -> T {
        delegate_stats.count_word_fetch_add_am();
        T r = *p;
        *p += inc;
        return r;
      });
    }

    /// Flat combines fetch_and_add to a single global address
    /// @warning { Target object must lie on a single node (not span blocks in global address space). }
    template < typename T, typename U >
    class FlatCombiner {
      // TODO: generalize to define other types of combiners
      private:
        // configuration
        const GlobalAddress<T> target;
        const U initVal;
        const uint64_t flush_threshold;

        // state
        T result;
        U increment;
        uint64_t committed;
        uint64_t participant_count;
        uint64_t ready_waiters;
        bool outstanding;
        ConditionVariable untilNotOutstanding;
        ConditionVariable untilReceived;

        // wait until fetch add unit is in aggregate mode
        // TODO: add concurrency (multiple fetch add units)
        void block_until_ready() {
          while ( outstanding ) {
            ready_waiters++;
            Grappa::wait(&untilNotOutstanding);
            ready_waiters--;
          }
        }

        void set_ready() {
          outstanding = false;
          Grappa::broadcast(&untilNotOutstanding);
        }

        void set_not_ready() {
          outstanding = true;
        }

      public:
        FlatCombiner( GlobalAddress<T> target, uint64_t flush_threshold, U initVal )
         : target( target )
         , initVal( initVal )
         , flush_threshold( flush_threshold )
         , result()
         , increment( initVal )
         , committed( 0 )
         , participant_count( 0 )
         , ready_waiters( 0 )
         , outstanding( false )
         , untilNotOutstanding()
         , untilReceived()
         {}

        /// Promise that in the future
        /// you will call `fetch_and_add`.
        ///
        /// Must be called before a call to `fetch_and_add`
        ///
        /// After calling promise, this task must NOT have a dependence on any
        /// `fetch_and_add` occurring before it calls `fetch_and_add` itself
        /// or deadlock may occur.
        ///
        /// For good performance, should allow other
        /// tasks to run before calling `fetch_and_add`
        void promise() {
          committed += 1;
        }
        // because tasks run serially, promise() replaces the flat combining tree

        T fetch_and_add( U inc ) {

          block_until_ready();

          // fetch add unit is now aggregating so add my inc

          participant_count++;
          committed--;
          increment += inc;

          // if I'm the last entered client and either the flush threshold
          // is reached or there are no more committed participants then start the flush
          if ( ready_waiters == 0 && (participant_count >= flush_threshold || committed == 0 )) {
            set_not_ready();
            T * p = target.pointer();
            uint64_t increment_total = increment;
            flat_combiner_fetch_and_add_amount += increment_total;
            result = call(target.node(), [p, increment_total]() -> U {
              uint64_t r = *p;
              *p += increment_total;
              return r;
            });
            // tell the others that the result has arrived
            Grappa::broadcast(&untilReceived);
          } else {
            // someone else will start the flush
            Grappa::wait(&untilReceived);
          }

          uint64_t my_start = result;
          result += inc;
          participant_count--;
          increment -= inc;   // for validation purposes (could just set to 0)
          CHECK( increment >= 0 );
          if ( participant_count == 0 ) {
            CHECK( increment == 0 ) << "increment = " << increment << " even though all participants are done";
            set_ready();
          }

          return my_start;
        }
    };

    /// If value at `target` equals `cmp_val`, set the value to `new_val` and return `true`,
    /// otherwise do nothing and return `false`.
    /// @warning { Target object must lie on a single node (not span blocks in global address space). }
    template< typename T, typename U, typename V >
    bool compare_and_swap(GlobalAddress<T> target, U cmp_val, V new_val) {
      delegate_stats.count_word_compare_swap();
      T * p = target.pointer();
      return call(target.node(), [p, cmp_val, new_val]() -> bool {
        delegate_stats.count_word_compare_swap_am();
        if (cmp_val == *p) {
          *p = new_val;
          return true;
        } else {
          return false;
        }
      });
    }

    /// @}
  } // namespace delegate
} // namespace Grappa

#endif
<commit_msg>In Delegate: Fix ConditionVariable signal problem with FEbit.<commit_after>
// Copyright 2010-2012 University of Washington. All Rights Reserved.
// LICENSE_PLACEHOLDER
// This software was created with Government support under DE
// AC05-76RL01830 awarded by the United States Department of
// Energy. The Government has certain rights in the software.

#ifndef __DELEGATE_HPP__
#define __DELEGATE_HPP__

#include "Grappa.hpp"
#include "Message.hpp"
#include "FullEmpty.hpp"
#include "Message.hpp"
#include "ConditionVariable.hpp"
#include "LegacyDelegate.hpp"
#include "MessagePool.hpp"
#include <type_traits>

GRAPPA_DECLARE_STAT(SummarizingStatistic<uint64_t>, flat_combiner_fetch_and_add_amount);
GRAPPA_DECLARE_STAT(SimpleStatistic<uint64_t>, delegate_ops_short_circuited);

namespace Grappa {
  namespace delegate {
    /// @addtogroup Delegates
    /// @{

    template <typename F>
    inline auto call(Core dest, F func)
        -> typename std::enable_if<std::is_void<decltype(func())>::value, void>::type {
      delegate_stats.count_op();
      Core origin = Grappa::mycore();

      if (dest == origin) {
        // short-circuit if local
        delegate_ops_short_circuited++;
        return func();
      } else {
        int64_t network_time = 0;
        int64_t start_time = Grappa_get_timestamp();
        FullEmpty<bool> result;
        send_message(dest, [&result, origin, func, &network_time, start_time] {
          delegate_stats.count_op_am();

          func();

          // TODO: replace with handler-safe send_message
          send_heap_message(origin, [&result, &network_time, start_time] {
            network_time = Grappa_get_timestamp();
            delegate_stats.record_network_latency(start_time);
            result.writeXF(true);
          });
        }); // send message

        // ... and wait for the call to complete
        result.readFF();
        delegate_stats.record_wakeup_latency(start_time, network_time);
        return;
      }
    }

    /// Implements essentially a blocking remote procedure call. Callable object (lambda,
    /// function pointer, or functor object) is called from the `dest` core and the return
    /// value is sent back to the calling task.
    template <typename F>
    inline auto call(Core dest, F func)
      -> typename std::enable_if<!std::is_void<decltype(func())>::value, decltype(func())>::type {
      // Note: code below (calling call_async) could be used to avoid duplication of code,
      // but call_async adds some overhead (object creation overhead, especially for short
      // -circuit case and extra work in MessagePool)
      //   AsyncHandle<decltype(func())> a;
      //   MessagePool<sizeof(Message<F>)> pool;
      //   a.call_async(pool, dest, func);
      //   return a.get_result();
      // TODO: find a way to implement using async version that doesn't introduce overhead

      delegate_stats.count_op();
      using R = decltype(func());
      Core origin = Grappa::mycore();

      if (dest == origin) {
        // short-circuit if local
        return func();
      } else {
        FullEmpty<R> result;
        int64_t network_time = 0;
        int64_t start_time = Grappa_get_timestamp();

        send_message(dest, [&result, origin, func, &network_time, start_time] {
          delegate_stats.count_op_am();
          R val = func();

          // TODO: replace with handler-safe send_message
          send_heap_message(origin, [&result, val, &network_time, start_time] {
            network_time = Grappa_get_timestamp();
            delegate_stats.record_network_latency(start_time);
            result.writeXF(val); // can't block in message, assumption is that result is already empty
          });
        }); // send message
        // ... and wait for the result
        R r = result.readFE();
        delegate_stats.record_wakeup_latency(start_time, network_time);
        return r;
      }
    }

    /// Read the value (potentially remote) at the given GlobalAddress, blocks the calling task until
    /// round-trip communication is complete.
    /// @warning { Target object must lie on a single node (not span blocks in global address space). }
    template< typename T >
    T read(GlobalAddress<T> target) {
      delegate_stats.count_word_read();
      return call(target.node(), [target]() -> T {
        delegate_stats.count_word_read_am();
        return *target.pointer();
      });
    }

    /// Blocking remote write.
    /// @warning { Target object must lie on a single node (not span blocks in global address space). }
    template< typename T, typename U >
    void write(GlobalAddress<T> target, U value) {
      delegate_stats.count_word_write();
      // TODO: don't return any val, requires changes to `delegate::call()`.
      return call(target.node(), [target, value] {
        delegate_stats.count_word_write_am();
        *target.pointer() = value;
      });
    }

    /// Fetch the value at `target`, increment the value stored there with `inc` and return the
    /// original value to blocking thread.
    /// @warning { Target object must lie on a single node (not span blocks in global address space). }
    template< typename T, typename U >
    T fetch_and_add(GlobalAddress<T> target, U inc) {
      delegate_stats.count_word_fetch_add();
      T * p = target.pointer();
      return call(target.node(), [p, inc]() -> T {
        delegate_stats.count_word_fetch_add_am();
        T r = *p;
        *p += inc;
        return r;
      });
    }

    /// Flat combines fetch_and_add to a single global address
    /// @warning { Target object must lie on a single node (not span blocks in global address space). }
    template < typename T, typename U >
    class FlatCombiner {
      // TODO: generalize to define other types of combiners
      private:
        // configuration
        const GlobalAddress<T> target;
        const U initVal;
        const uint64_t flush_threshold;

        // state
        T result;
        U increment;
        uint64_t committed;
        uint64_t participant_count;
        uint64_t ready_waiters;
        bool outstanding;
        ConditionVariable untilNotOutstanding;
        ConditionVariable untilReceived;

        // wait until fetch add unit is in aggregate mode
        // TODO: add concurrency (multiple fetch add units)
        void block_until_ready() {
          while ( outstanding ) {
            ready_waiters++;
            Grappa::wait(&untilNotOutstanding);
            ready_waiters--;
          }
        }

        void set_ready() {
          outstanding = false;
          Grappa::broadcast(&untilNotOutstanding);
        }

        void set_not_ready() {
          outstanding = true;
        }

      public:
        FlatCombiner( GlobalAddress<T> target, uint64_t flush_threshold, U initVal )
         : target( target )
         , initVal( initVal )
         , flush_threshold( flush_threshold )
         , result()
         , increment( initVal )
         , committed( 0 )
         , participant_count( 0 )
         , ready_waiters( 0 )
         , outstanding( false )
         , untilNotOutstanding()
         , untilReceived()
         {}

        /// Promise that in the future
        /// you will call `fetch_and_add`.
        ///
        /// Must be called before a call to `fetch_and_add`
        ///
        /// After calling promise, this task must NOT have a dependence on any
        /// `fetch_and_add` occurring before it calls `fetch_and_add` itself
        /// or deadlock may occur.
        ///
        /// For good performance, should allow other
        /// tasks to run before calling `fetch_and_add`
        void promise() {
          committed += 1;
        }
        // because tasks run serially, promise() replaces the flat combining tree

        T fetch_and_add( U inc ) {

          block_until_ready();

          // fetch add unit is now aggregating so add my inc

          participant_count++;
          committed--;
          increment += inc;

          // if I'm the last entered client and either the flush threshold
          // is reached or there are no more committed participants then start the flush
          if ( ready_waiters == 0 && (participant_count >= flush_threshold || committed == 0 )) {
            set_not_ready();
            T * p = target.pointer();
            uint64_t increment_total = increment;
            flat_combiner_fetch_and_add_amount += increment_total;
            result = call(target.node(), [p, increment_total]() -> U {
              uint64_t r = *p;
              *p += increment_total;
              return r;
            });
            // tell the others that the result has arrived
            Grappa::broadcast(&untilReceived);
          } else {
            // someone else will start the flush
            Grappa::wait(&untilReceived);
          }

          uint64_t my_start = result;
          result += inc;
          participant_count--;
          increment -= inc;   // for validation purposes (could just set to 0)
          CHECK( increment >= 0 );
          if ( participant_count == 0 ) {
            CHECK( increment == 0 ) << "increment = " << increment << " even though all participants are done";
            set_ready();
          }

          return my_start;
        }
    };

    /// If value at `target` equals `cmp_val`, set the value to `new_val` and return `true`,
    /// otherwise do nothing and return `false`.
    /// @warning { Target object must lie on a single node (not span blocks in global address space). }
    template< typename T, typename U, typename V >
    bool compare_and_swap(GlobalAddress<T> target, U cmp_val, V new_val) {
      delegate_stats.count_word_compare_swap();
      T * p = target.pointer();
      return call(target.node(), [p, cmp_val, new_val]() -> bool {
        delegate_stats.count_word_compare_swap_am();
        if (cmp_val == *p) {
          *p = new_val;
          return true;
        } else {
          return false;
        }
      });
    }

    /// @}
  } // namespace delegate
} // namespace Grappa

#endif
<|endoftext|>


<commit_before>/*
Copyright (c) 2017-2018, Intel Corporation
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
    * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

// written by Patrick Lu
#define HACK_TO_REMOVE_DUPLICATE_ERROR
#include "cpucounters.h"
#ifdef _MSC_VER
#pragma warning(disable : 4996) // for sprintf
#include <windows.h>
#include "../PCM_Win/windriver.h"
#else
#include <unistd.h>
#endif
#include <iostream>
#include <stdlib.h>
#include <cstdint>
#ifdef _MSC_VER
#include "freegetopt/getopt.h"
#endif

#include "lspci.h"
using namespace std;

void scanBus(int bus, const PCIDB & pciDB)
{
    if(!PciHandleType::exists(0, bus, 8, 2)) return;

    std::cout << "BUS 0x" << std::hex << bus << std::dec << endl;

    struct iio_skx iio_skx;

    PciHandleType h(0, bus, 8, 2);
    uint32 cpubusno = 0;

    h.read32(0xcc, &cpubusno); // CPUBUSNO register
    iio_skx.stacks[0].busno = cpubusno & 0xff;
    iio_skx.stacks[1].busno = (cpubusno >> 8) & 0xff;
    iio_skx.stacks[2].busno = (cpubusno >> 16) & 0xff;
    iio_skx.stacks[3].busno = (cpubusno >> 24) & 0xff;
    h.read32(0xd0, &cpubusno); // CPUBUSNO1 register
    iio_skx.stacks[4].busno = cpubusno & 0xff;
    iio_skx.stacks[5].busno = (cpubusno >> 8) & 0xff;

    for (uint8_t stack = 0; stack < 6; stack++) {
        uint8_t busno = iio_skx.stacks[stack].busno;
        std::cout << "stack" << unsigned(stack) << std::hex << ":0x" << unsigned(busno) << std::dec << ",(" << unsigned(busno) << ")\n";
        for (uint8_t part = 0; part < 3; part++) {
                struct pci *pci = &iio_skx.stacks[stack].parts[part].root_pci_dev;
                struct bdf *bdf = &pci->bdf;
                bdf->busno = busno;
                bdf->devno = part;
                bdf->funcno = 0;
                if (stack != 0 && busno == 0) /* This is a workaround to catch some IIO stack does not exist */
                    pci->exist = false;
                else
                    probe_pci(pci);
            }
        }
    for (uint8_t stack = 0; stack < 6; stack++) {
        for (uint8_t part = 0; part < 4; part++) {
            struct pci p = iio_skx.stacks[stack].parts[part].root_pci_dev;
            if (!p.exist)
                continue;
            for (uint8_t b = p.secondary_bus_number; b <= p.subordinate_bus_number; b++) { /* FIXME: for 0:0.0, we may need to scan from secondary switch down */
                for (uint8_t d = 0; d < 32; d++) {
                    for (uint8_t f = 0; f < 8; f++) {
                        struct pci pci;
                        pci.exist = false;
                        pci.bdf.busno = b;
                        pci.bdf.devno = d;
                        pci.bdf.funcno = f;
                        probe_pci(&pci);
                        if (pci.exist)
                            iio_skx.stacks[stack].parts[part].child_pci_devs.push_back(pci);
                    }
                }
            }
        }
    }

    for (uint8_t stack = 1; stack < 6; stack++) { /* XXX: Maybe there is no point to display all built-in devices on DMI/CBDMA stacks, if so, change stack = 1 */
        for (uint8_t part = 0; part < 4; part++) {
            vector<struct pci> v = iio_skx.stacks[stack].parts[part].child_pci_devs;
            struct pci pp = iio_skx.stacks[stack].parts[part].root_pci_dev;
            if (pp.exist)
                print_pci(pp, pciDB);
            for (vector<struct pci>::const_iterator iunit = v.begin(); iunit != v.end(); ++iunit) {
                struct pci p = *iunit;
                if (p.exist)
                    print_pci(p, pciDB);
            }
        }
    }
}

int main(int argc, char * argv[])
{
    PCIDB pciDB;
    load_PCIDB(pciDB);
    PCM::getInstance();
    std::cout << "\n Display PCI tree information\n\n";
    for(int bus=0; bus < 256; ++bus)
        scanBus(bus, pciDB);
}
<commit_msg>Replace endl with \n to get rid of many unnecessary flushes<commit_after>/*
Copyright (c) 2017-2018, Intel Corporation
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
    * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

// written by Patrick Lu
#define HACK_TO_REMOVE_DUPLICATE_ERROR
#include "cpucounters.h"
#ifdef _MSC_VER
#pragma warning(disable : 4996) // for sprintf
#include <windows.h>
#include "../PCM_Win/windriver.h"
#else
#include <unistd.h>
#endif
#include <iostream>
#include <stdlib.h>
#include <cstdint>
#ifdef _MSC_VER
#include "freegetopt/getopt.h"
#endif

#include "lspci.h"
using namespace std;

void scanBus(int bus, const PCIDB & pciDB)
{
    if(!PciHandleType::exists(0, bus, 8, 2)) return;

    std::cout << "BUS 0x" << std::hex << bus << std::dec << "\n";

    struct iio_skx iio_skx;

    PciHandleType h(0, bus, 8, 2);
    uint32 cpubusno = 0;

    h.read32(0xcc, &cpubusno); // CPUBUSNO register
    iio_skx.stacks[0].busno = cpubusno & 0xff;
    iio_skx.stacks[1].busno = (cpubusno >> 8) & 0xff;
    iio_skx.stacks[2].busno = (cpubusno >> 16) & 0xff;
    iio_skx.stacks[3].busno = (cpubusno >> 24) & 0xff;
    h.read32(0xd0, &cpubusno); // CPUBUSNO1 register
    iio_skx.stacks[4].busno = cpubusno & 0xff;
    iio_skx.stacks[5].busno = (cpubusno >> 8) & 0xff;

    for (uint8_t stack = 0; stack < 6; stack++) {
        uint8_t busno = iio_skx.stacks[stack].busno;
        std::cout << "stack" << unsigned(stack) << std::hex << ":0x" << unsigned(busno) << std::dec << ",(" << unsigned(busno) << ")\n";
        for (uint8_t part = 0; part < 3; part++) {
                struct pci *pci = &iio_skx.stacks[stack].parts[part].root_pci_dev;
                struct bdf *bdf = &pci->bdf;
                bdf->busno = busno;
                bdf->devno = part;
                bdf->funcno = 0;
                if (stack != 0 && busno == 0) /* This is a workaround to catch some IIO stack does not exist */
                    pci->exist = false;
                else
                    probe_pci(pci);
            }
        }
    for (uint8_t stack = 0; stack < 6; stack++) {
        for (uint8_t part = 0; part < 4; part++) {
            struct pci p = iio_skx.stacks[stack].parts[part].root_pci_dev;
            if (!p.exist)
                continue;
            for (uint8_t b = p.secondary_bus_number; b <= p.subordinate_bus_number; b++) { /* FIXME: for 0:0.0, we may need to scan from secondary switch down */
                for (uint8_t d = 0; d < 32; d++) {
                    for (uint8_t f = 0; f < 8; f++) {
                        struct pci pci;
                        pci.exist = false;
                        pci.bdf.busno = b;
                        pci.bdf.devno = d;
                        pci.bdf.funcno = f;
                        probe_pci(&pci);
                        if (pci.exist)
                            iio_skx.stacks[stack].parts[part].child_pci_devs.push_back(pci);
                    }
                }
            }
        }
    }

    for (uint8_t stack = 1; stack < 6; stack++) { /* XXX: Maybe there is no point to display all built-in devices on DMI/CBDMA stacks, if so, change stack = 1 */
        for (uint8_t part = 0; part < 4; part++) {
            vector<struct pci> v = iio_skx.stacks[stack].parts[part].child_pci_devs;
            struct pci pp = iio_skx.stacks[stack].parts[part].root_pci_dev;
            if (pp.exist)
                print_pci(pp, pciDB);
            for (vector<struct pci>::const_iterator iunit = v.begin(); iunit != v.end(); ++iunit) {
                struct pci p = *iunit;
                if (p.exist)
                    print_pci(p, pciDB);
            }
        }
    }
}

int main(int argc, char * argv[])
{
    PCIDB pciDB;
    load_PCIDB(pciDB);
    PCM::getInstance();
    std::cout << "\n Display PCI tree information\n\n";
    for(int bus=0; bus < 256; ++bus)
        scanBus(bus, pciDB);
}
<|endoftext|>


<commit_before>#include	"FTFace.h"
#include	"FTFont.h"
#include	"FTGlyph.h" // for FTBbox
#ifdef FTGL_DEBUG
	#include "mmgr.h"
#endif

FTFont::FTFont()
:	numFaces(0),
	glyphList(0),
	numGlyphs(0),
	preCache(true),
	err(0)
{
	pen.x = 0;
	pen.y = 0;
}

FTFont::~FTFont()
{
	Close();
}

bool FTFont::Open( const char* fontname, bool p)
{
	preCache = p;

	if( face.Open( fontname))
	{
		FT_Face* ftFace = face.Face();
		numGlyphs = (*ftFace)->num_glyphs;

		return true;
	}
	else
	{
		err = face.Error();
		return false;
	}
}

void FTFont::Close()
{
	delete glyphList;
}

bool FTFont::FaceSize( const unsigned int size, const unsigned int res )
{
	charSize = face.Size( size, res);

	if( glyphList)
		delete glyphList;

	glyphList = new FTGlyphContainer( &face, numGlyphs, preCache);

	if( MakeGlyphList())
	{
		return true;
	}
	else
	{
		return false;
	}
}

bool FTFont::CharMap( FT_Encoding encoding)
{
	err = face.CharMap( encoding);
	return !err;
}

bool FTFont::MakeGlyphList()
{
    for( unsigned int c = 0; c < numGlyphs; ++c)
    {
        if( preCache)
        {
            glyphList->Add( MakeGlyph( c), c);
        }
        else
        {
            glyphList->Add( NULL, c);
        }
    }

    return !err; // From derived class MakeGlyph()
}

void FTFont::BBox( const char* string,
                    float& llx, float& lly, float& llz, float& urx, float& ury, float& urz)
{
	const unsigned char* c = (unsigned char*)string;
	llx = lly = llz = urx = ury = urz = 0;
	FTBBox bbox;

	while( *c)
	{
		if( !glyphList->Glyph( static_cast<unsigned int>(*c)))
		{
			unsigned int g = face.CharIndex( static_cast<unsigned int>(*c));
			glyphList->Add( MakeGlyph( g), g);
		}

		bbox = glyphList->BBox( *c);

		// Lower extent
		lly = lly < bbox.y1 ? lly: bbox.y1;
		// Upper extent
		ury = ury > bbox.y2 ? ury: bbox.y2;
		// Depth
		urz = urz < bbox.z2 ? urz: bbox.z2;

		// Width
		urx += glyphList->Advance( *c, *(c + 1));
		++c;
	}

	//Final adjustments
	llx = glyphList->BBox( *string).x1;
	urx -= glyphList->Advance( *(c - 1), 0);
	urx += bbox.x2;

}

void FTFont::BBox( const wchar_t* string,
                    float& llx, float& lly, float& llz, float& urx, float& ury, float& urz)
{
	const wchar_t* c = string;
	llx = lly = llz = urx = ury = urz = 0;
	FTBBox bbox;

	while( *c)
	{
		if( !glyphList->Glyph( static_cast<unsigned int>(*c)))
		{
			unsigned int g = face.CharIndex( static_cast<unsigned int>(*c));
			glyphList->Add( MakeGlyph( g), g);
		}

		bbox = glyphList->BBox( *c);

		// Lower extent
		lly = lly < bbox.y1 ? lly: bbox.y1;
		// Upper extent
		ury = ury > bbox.y2 ? ury: bbox.y2;
		// Depth
		urz = urz < bbox.z2 ? urz: bbox.z2;

		// Width
		urx += glyphList->Advance( *c, *(c + 1));
		++c;
	}

	//Final adjustments
	llx = glyphList->BBox( *string).x1;
	urx -= glyphList->Advance( *(c - 1), 0);
	urx += bbox.x2;

}

float FTFont::Advance( const wchar_t* string)
{
	const wchar_t* c = string;
	float width = 0;

	while( *c)
	{
		width += doAdvance( *c, *(c + 1));
		++c;
	}

	return width;
}

float FTFont::Advance( const char* string)
{
	const unsigned char* c = (unsigned char*)string;
	float width = 0;

	while( *c)
	{
		width += doAdvance( *c, *(c + 1));
		++c;
	}

	return width;
}

float FTFont::doAdvance( const unsigned int chr, const unsigned int nextChr)
{
	if( !glyphList->Glyph( chr))
	{
		unsigned int g = face.CharIndex( chr);
		glyphList->Add( MakeGlyph( g), g);
	}

	return glyphList->Advance( chr, nextChr);
}

void FTFont::render( const char* string )
{
	const unsigned char* c = (unsigned char*)string;
	pen.x = 0; pen.y = 0;

	while( *c)
	{
		doRender( *c, *(c + 1));
		++c;
	}
}

void FTFont::render( const wchar_t* string )
{
	const wchar_t* c = string;
	pen.x = 0; pen.y = 0;

	while( *c)
	{
		doRender( *c, *(c + 1));
		++c;
	}
}

void FTFont::doRender( const unsigned int chr, const unsigned int nextChr)
{
	if( !glyphList->Glyph( chr))
	{
		unsigned int g = face.CharIndex( chr);
		glyphList->Add( MakeGlyph( g), g);
	}

	FT_Vector kernAdvance = glyphList->render( chr, nextChr, pen);

	pen.x += kernAdvance.x;
	pen.y += kernAdvance.y;
}

<commit_msg>Put glyphcontainer back in<commit_after>#include	"FTFace.h"
#include	"FTFont.h"
#include	"FTGlyphContainer.h"
#include	"FTGlyph.h" // for FTBbox
#ifdef FTGL_DEBUG
	#include "mmgr.h"
#endif

FTFont::FTFont()
:	numFaces(0),
	glyphList(0),
	numGlyphs(0),
	preCache(true),
	err(0)
{
	pen.x = 0;
	pen.y = 0;
}

FTFont::~FTFont()
{
	Close();
}

bool FTFont::Open( const char* fontname, bool p)
{
	preCache = p;

	if( face.Open( fontname))
	{
		FT_Face* ftFace = face.Face();
		numGlyphs = (*ftFace)->num_glyphs;

		return true;
	}
	else
	{
		err = face.Error();
		return false;
	}
}

void FTFont::Close()
{
	delete glyphList;
}

bool FTFont::FaceSize( const unsigned int size, const unsigned int res )
{
	charSize = face.Size( size, res);

	if( glyphList)
		delete glyphList;

	glyphList = new FTGlyphContainer( &face, numGlyphs, preCache);

	if( MakeGlyphList())
	{
		return true;
	}
	else
	{
		return false;
	}
}

bool FTFont::CharMap( FT_Encoding encoding)
{
	err = face.CharMap( encoding);
	return !err;
}

bool FTFont::MakeGlyphList()
{
    for( unsigned int c = 0; c < numGlyphs; ++c)
    {
        if( preCache)
        {
            glyphList->Add( MakeGlyph( c), c);
        }
        else
        {
            glyphList->Add( NULL, c);
        }
    }

    return !err; // From derived class MakeGlyph()
}

void FTFont::BBox( const char* string,
                    float& llx, float& lly, float& llz, float& urx, float& ury, float& urz)
{
	const unsigned char* c = (unsigned char*)string;
	llx = lly = llz = urx = ury = urz = 0;
	FTBBox bbox;

	while( *c)
	{
		if( !glyphList->Glyph( static_cast<unsigned int>(*c)))
		{
			unsigned int g = face.CharIndex( static_cast<unsigned int>(*c));
			glyphList->Add( MakeGlyph( g), g);
		}

		bbox = glyphList->BBox( *c);

		// Lower extent
		lly = lly < bbox.y1 ? lly: bbox.y1;
		// Upper extent
		ury = ury > bbox.y2 ? ury: bbox.y2;
		// Depth
		urz = urz < bbox.z2 ? urz: bbox.z2;

		// Width
		urx += glyphList->Advance( *c, *(c + 1));
		++c;
	}

	//Final adjustments
	llx = glyphList->BBox( *string).x1;
	urx -= glyphList->Advance( *(c - 1), 0);
	urx += bbox.x2;

}

void FTFont::BBox( const wchar_t* string,
                    float& llx, float& lly, float& llz, float& urx, float& ury, float& urz)
{
	const wchar_t* c = string;
	llx = lly = llz = urx = ury = urz = 0;
	FTBBox bbox;

	while( *c)
	{
		if( !glyphList->Glyph( static_cast<unsigned int>(*c)))
		{
			unsigned int g = face.CharIndex( static_cast<unsigned int>(*c));
			glyphList->Add( MakeGlyph( g), g);
		}

		bbox = glyphList->BBox( *c);

		// Lower extent
		lly = lly < bbox.y1 ? lly: bbox.y1;
		// Upper extent
		ury = ury > bbox.y2 ? ury: bbox.y2;
		// Depth
		urz = urz < bbox.z2 ? urz: bbox.z2;

		// Width
		urx += glyphList->Advance( *c, *(c + 1));
		++c;
	}

	//Final adjustments
	llx = glyphList->BBox( *string).x1;
	urx -= glyphList->Advance( *(c - 1), 0);
	urx += bbox.x2;

}

float FTFont::Advance( const wchar_t* string)
{
	const wchar_t* c = string;
	float width = 0;

	while( *c)
	{
		width += doAdvance( *c, *(c + 1));
		++c;
	}

	return width;
}

float FTFont::Advance( const char* string)
{
	const unsigned char* c = (unsigned char*)string;
	float width = 0;

	while( *c)
	{
		width += doAdvance( *c, *(c + 1));
		++c;
	}

	return width;
}

float FTFont::doAdvance( const unsigned int chr, const unsigned int nextChr)
{
	if( !glyphList->Glyph( chr))
	{
		unsigned int g = face.CharIndex( chr);
		glyphList->Add( MakeGlyph( g), g);
	}

	return glyphList->Advance( chr, nextChr);
}

void FTFont::render( const char* string )
{
	const unsigned char* c = (unsigned char*)string;
	pen.x = 0; pen.y = 0;

	while( *c)
	{
		doRender( *c, *(c + 1));
		++c;
	}
}

void FTFont::render( const wchar_t* string )
{
	const wchar_t* c = string;
	pen.x = 0; pen.y = 0;

	while( *c)
	{
		doRender( *c, *(c + 1));
		++c;
	}
}

void FTFont::doRender( const unsigned int chr, const unsigned int nextChr)
{
	if( !glyphList->Glyph( chr))
	{
		unsigned int g = face.CharIndex( chr);
		glyphList->Add( MakeGlyph( g), g);
	}

	FT_Vector kernAdvance = glyphList->render( chr, nextChr, pen);

	pen.x += kernAdvance.x;
	pen.y += kernAdvance.y;
}

<|endoftext|>