<commit_before>//===------------------------ ConstantnessSemaDiagnostics.cpp -------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements checks for checking whether certain arguments to some
// specific APIs are compile-time constants (see below for the definition of
// constants). In particular, this code checks whether the new os_log APIs are
// invoked with constant arguments, and whether the primitive atomic operations
// are invoked with constant "orderings". These APIs are identified through
// @_semantics attributes.
//
// A "compile-time constant" is either a literal (including
// string/integer/float/boolean/string-interpolation literal) or a call to a
// "constant_evaluable" function (or property) with compile-time constant
// arguments. A closure expression is also considered a compile-time constant
// (it is a constant of a function type).
//===----------------------------------------------------------------------===//

#include "MiscDiagnostics.h"
#include "TypeChecker.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/SemanticAttrs.h"
using namespace swift;

/// Check whether a given \p decl has a @_semantics attribute with the given
/// attribute name \c attrName.
static bool hasSemanticsAttr(ValueDecl *decl, StringRef attrName) {
  return decl->getAttrs().hasSemanticsAttr(attrName);
}

/// Return true iff  the given \p structDecl has a name that matches one of the
/// known atomic orderings structs.
static bool isAtomicOrderingDecl(StructDecl *structDecl) {
  ASTContext &astContext = structDecl->getASTContext();
  Identifier structName = structDecl->getName();
  return (structName == astContext.Id_AtomicLoadOrdering ||
          structName == astContext.Id_AtomicStoreOrdering ||
          structName == astContext.Id_AtomicUpdateOrdering);
}

/// Return true iff the given nominal type decl \p nominal has a name that
/// matches one of the known OSLog types that need not be a constant in the new
/// os_log APIs.
static bool isOSLogDynamicObject(NominalTypeDecl *nominal) {
  ASTContext &astContext = nominal->getASTContext();
  Identifier name = nominal->getName();
  return (name == astContext.Id_OSLog || name == astContext.Id_OSLogType);
}

/// Return true iff the parameter \p param of function \c funDecl is required to
/// be a constant. This is true if either the function is an os_log function or
/// it is an atomics operation and the parameter represents the ordering.
static bool isParamRequiredToBeConstant(AbstractFunctionDecl *funcDecl, ParamDecl *param) {
  assert(funcDecl && param && "funcDecl and param must not be null");
  Type paramType;
  NominalTypeDecl *nominal;
  StructDecl *structDecl;
  if (hasSemanticsAttr(funcDecl, semantics::OSLOG_REQUIRES_CONSTANT_ARGUMENTS))
    return true;
  if (hasSemanticsAttr(funcDecl, semantics::OSLOG_LOG_WITH_LEVEL)) {
    // We are looking at a top-level os_log function that accepts level and
    // possibly custom log object. Those need not be constants, but every other
    // parameter must be.
    paramType = param->getType();
    nominal = paramType->getNominalOrBoundGenericNominal();
    return !nominal || !isOSLogDynamicObject(nominal);
  }
  if (!hasSemanticsAttr(funcDecl,
                        semantics::ATOMICS_REQUIRES_CONSTANT_ORDERINGS))
    return false;
  paramType = param->getType();
  structDecl = paramType->getStructOrBoundGenericStruct();
  if (!structDecl)
    return false;
  return isAtomicOrderingDecl(structDecl);
}

/// Return true iff the \c decl is annotated as
/// @_semantics("constant_evaluable").
static bool hasConstantEvaluableAttr(ValueDecl *decl) {
  return hasSemanticsAttr(decl, semantics::CONSTANT_EVALUABLE);
}

/// Return true iff the \p decl is annotated with oslog.message.init semantics
/// attribute.
static bool isOSLogMessageInitializer(ValueDecl *decl) {
  return hasSemanticsAttr(decl, semantics::OSLOG_MESSAGE_INIT_STRING_LITERAL) ||
         hasSemanticsAttr(decl, semantics::OSLOG_MESSAGE_INIT_INTERPOLATION);
}

/// Check whether \p expr is a compile-time constant. It must either be a
/// literal_expr, which does not include array and dictionary literal, or a
/// closure expression, which is considered a compile-time constant of a
/// function type, or a call to a "constant_evaluable" function (or property)
/// whose arguments are themselves compile-time constants.
static Expr *checkConstantness(Expr *expr) {
  SmallVector<Expr *, 4> expressionsToCheck;
  expressionsToCheck.push_back(expr);
  while (!expressionsToCheck.empty()) {
    Expr *expr = expressionsToCheck.pop_back_val();
    // Lookthrough identity_expr, tuple, binary_expr and inject_into_optional expressions.
    if (IdentityExpr *identityExpr = dyn_cast<IdentityExpr>(expr)) {
      expressionsToCheck.push_back(identityExpr->getSubExpr());
      continue;
    }
    if (TupleExpr *tupleExpr = dyn_cast<TupleExpr>(expr)) {
      for (Expr *element : tupleExpr->getElements())
        expressionsToCheck.push_back(element);
      continue;
    }
    if (BinaryExpr *binaryExpr = dyn_cast<BinaryExpr>(expr)) {
      expressionsToCheck.push_back(binaryExpr->getLHS());
      expressionsToCheck.push_back(binaryExpr->getRHS());
      continue;
    }
    if (InjectIntoOptionalExpr *optionalExpr =
            dyn_cast<InjectIntoOptionalExpr>(expr)) {
      expressionsToCheck.push_back(optionalExpr->getSubExpr());
      continue;
    }
    // Literal expressions also includes InterpolatedStringLiteralExpr.
    if (isa<LiteralExpr>(expr))
      continue;
    if (isa<TypeExpr>(expr))
      continue;
    // Closure expressions are always treated as constants. They are
    // constants of function types.
    if (isa<AbstractClosureExpr>(expr))
      continue;
    // Default argument expressions of a constant_evaluable or a
    // requires_constant function must be ensured to be a constant by the
    // definition of the function.
    if (isa<DefaultArgumentExpr>(expr))
      continue;

    // If this is a member-ref, it has to be annotated constant evaluable.
    if (MemberRefExpr *memberRef = dyn_cast<MemberRefExpr>(expr)) {
      if (ValueDecl *memberDecl = memberRef->getMember().getDecl()) {
        if (hasConstantEvaluableAttr(memberDecl))
          continue;
      }
      return expr;
    }

    // If this is a variable, it has to be a known constant parameter of the
    // enclosing function.
    if (DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(expr)) {
      ValueDecl *decl = declRef->getDecl();
      if (!decl)
        return expr;
      ParamDecl *paramDecl = dyn_cast<ParamDecl>(decl);
      if (!paramDecl)
        return expr;
      Decl *declContext = paramDecl->getDeclContext()->getAsDecl();
      if (!declContext)
        return expr;
      AbstractFunctionDecl *funcDecl = dyn_cast<AbstractFunctionDecl>(declContext);
      if (!funcDecl || !isParamRequiredToBeConstant(funcDecl, paramDecl))
        return expr;
      continue;
    }

    if (!isa<ApplyExpr>(expr))
      return expr;

    ApplyExpr *apply = cast<ApplyExpr>(expr);
    ValueDecl *calledValue = apply->getCalledValue();
    if (!calledValue)
      return expr;

    // If this is an enum case, check whether the arguments are constants.
    if (isa<EnumElementDecl>(calledValue)) {
      for (auto arg : *apply->getArgs())
        expressionsToCheck.push_back(arg.getExpr());
      continue;
    }

    AbstractFunctionDecl *callee = dyn_cast<AbstractFunctionDecl>(calledValue);
    if (!callee)
      return expr;

    // If this is an application of OSLogMessage initializer, fail the check
    // as this type must be created from string interpolations.
    if (isOSLogMessageInitializer(callee))
      return expr;

    // If this is a constant_evaluable function, check whether the arguments are
    // constants.
    if (!hasConstantEvaluableAttr(callee))
      return expr;

    for (auto arg : *apply->getArgs())
      expressionsToCheck.push_back(arg.getExpr());
  }
  return nullptr;
}

/// Return true iff the given \p type is a Stdlib integer type.
static bool isIntegerType(Type type) {
  return type->isInt() || type->isInt8() || type->isInt16() ||
         type->isInt32() || type->isInt64() || type->isUInt() ||
         type->isUInt8() || type->isUInt16() || type->isUInt32() ||
         type->isUInt64();
}

/// Return true iff the given \p type is a Float type.
static bool isFloatType(Type type) {
  return type->isFloat() || type->isDouble() || type->isFloat80();
}

/// Given an error expression \p errorExpr, diagnose the error based on the type
/// of the expression. For instance, if the expression's type is expressible by
/// a literal e.g. integer, boolean etc. report that it must be a literal.
/// Otherwise, if the expression is a nominal type, report that it must be
/// static member of the type.
static void diagnoseError(Expr *errorExpr, const ASTContext &astContext,
                          AbstractFunctionDecl *funcDecl) {
  DiagnosticEngine &diags = astContext.Diags;
  Type exprType = errorExpr->getType();
  SourceLoc errorLoc = errorExpr->getLoc();

  // Diagnose atomics ordering related error here.
  if (hasSemanticsAttr(funcDecl,
                       semantics::ATOMICS_REQUIRES_CONSTANT_ORDERINGS)) {
    NominalTypeDecl *nominalDecl = exprType->getNominalOrBoundGenericNominal();
    if (!nominalDecl) {
      // This case should normally not happen. This is a safe guard against
      // possible mismatch between the atomics library and the compiler.
      diags.diagnose(errorLoc, diag::argument_must_be_constant);
    }
    diags.diagnose(errorLoc, diag::atomics_ordering_must_be_constant,
                   nominalDecl->getName());
    return;
  }

  // Diagnose os_log specific errors here.

  // Diagnose primitive stdlib types.
  if (exprType->isBool()) {
    diags.diagnose(errorLoc, diag::oslog_arg_must_be_bool_literal);
    return;
  }
  if (exprType->isString()) {
    diags.diagnose(errorLoc, diag::oslog_arg_must_be_string_literal);
    return;
  }
  if (isIntegerType(exprType)) {
    diags.diagnose(errorLoc, diag::oslog_arg_must_be_integer_literal);
    return;
  }
  if (isFloatType(exprType)) {
    diags.diagnose(errorLoc, diag::oslog_arg_must_be_float_literal);
    return;
  }
  if (exprType->is<MetatypeType>()) {
    diags.diagnose(errorLoc, diag::oslog_arg_must_be_metatype_literal);
    return;
  }
  if (exprType->is<AnyFunctionType>()) {
    diags.diagnose(errorLoc, diag::oslog_arg_must_be_closure);
    return;
  }
  if (EnumDecl *enumDecl = exprType->getEnumOrBoundGenericEnum()) {
    diags.diagnose(errorLoc, diag::oslog_arg_must_be_enum_case,
                   enumDecl->getName());
    return;
  }
  NominalTypeDecl *nominalDecl = exprType->getNominalOrBoundGenericNominal();
  if (!nominalDecl) {
    // This case should normally not happen. This is a safe guard against
    // possible mismatch between the os overlay and the compiler.
    diags.diagnose(errorLoc, diag::argument_must_be_constant);
    return;
  }
  // If this is OSLogMessage, it should be a string-interpolation literal.
  Identifier declName = nominalDecl->getName();
  if (declName == astContext.Id_OSLogMessage ||
      nominalDecl->hasSemanticsAttr(semantics::OSLOG_MESSAGE_TYPE)) {
    diags.diagnose(errorLoc, diag::oslog_message_must_be_string_interpolation);
    return;
  }
  diags.diagnose(errorLoc, diag::oslog_arg_must_be_type_member_access,
                 declName);
}

/// Given a call \c callExpr, if some or all of its arguments are required to be
/// constants, check that property on the arguments.
static void diagnoseConstantArgumentRequirementOfCall(const CallExpr *callExpr,
                                                      const ASTContext &ctx) {
  assert(callExpr && callExpr->getType() &&
         "callExpr should have a valid type");
  ValueDecl *calledDecl = callExpr->getCalledValue();
  if (!calledDecl || !isa<AbstractFunctionDecl>(calledDecl))
    return;
  AbstractFunctionDecl *callee = cast<AbstractFunctionDecl>(calledDecl);

  // Collect argument indices that are required to be constants.
  SmallVector<unsigned, 4> constantArgumentIndices;
  auto paramList = callee->getParameters();
  for (unsigned i = 0; i < paramList->size(); ++i) {
    ParamDecl *param = paramList->get(i);
    if (isParamRequiredToBeConstant(callee, param))
      constantArgumentIndices.push_back(i);
  }
  if (constantArgumentIndices.empty())
    return;

  // Check that the arguments at the constantArgumentIndices are constants.
  SmallVector<Expr *, 4> arguments;
  for (auto arg : *callExpr->getArgs())
    arguments.push_back(arg.getExpr());

  for (unsigned constantIndex : constantArgumentIndices) {
    assert(constantIndex < arguments.size() &&
           "constantIndex exceeds the number of arguments to the function");
    Expr *argument = arguments[constantIndex];
    Expr *errorExpr = checkConstantness(argument);
    if (errorExpr)
      diagnoseError(errorExpr, ctx, callee);
  }
}

void swift::diagnoseConstantArgumentRequirement(
    const Expr *expr, const DeclContext *declContext) {
  class ConstantReqCallWalker : public ASTWalker {
    DeclContext *DC;

  public:
    ConstantReqCallWalker(DeclContext *DC) : DC(DC) {}

    // Descend until we find a call expressions. Note that the input expression
    // could be an assign expression or another expression that contains the
    // call.
    std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
      // Handle closure expressions separately as we may need to
      // manually descend into the body.
      if (auto *closureExpr = dyn_cast<ClosureExpr>(expr)) {
        return walkToClosureExprPre(closureExpr);
      }
      // Interpolated expressions' bodies will be type checked
      // separately so exit early to avoid duplicate diagnostics.
      if (!expr || isa<ErrorExpr>(expr) || !expr->getType() ||
          isa<InterpolatedStringLiteralExpr>(expr))
        return {false, expr};
      if (auto *callExpr = dyn_cast<CallExpr>(expr)) {
        diagnoseConstantArgumentRequirementOfCall(callExpr, DC->getASTContext());
      }
      return {true, expr};
    }

    std::pair<bool, Expr *> walkToClosureExprPre(ClosureExpr *closure) {
      if (closure->hasSingleExpressionBody()) {
        // Single expression closure bodies are not visited directly
        // by the ASTVisitor, so we must descend into the body manually
        // and set the DeclContext to that of the closure.
        DC = closure;
        return {true, closure};
      }
      return {false, closure};
    }

    Expr *walkToExprPost(Expr *expr) override {
      if (auto *closureExpr = dyn_cast<ClosureExpr>(expr)) {
        // Reset the DeclContext to the outer scope if we descended
        // into a closure expr.
        DC = closureExpr->getParent();
      }
      return expr;
    }

    std::pair<bool, Stmt *> walkToStmtPre(Stmt *stmt) override {
      return {true, stmt};
    }
  };

  ConstantReqCallWalker walker(const_cast<DeclContext *>(declContext));
  const_cast<Expr *>(expr)->walk(walker);
}
<commit_msg>[TypeChecker/Constness] Diagnostics: Walk into multi-statement closures when inference is enabled<commit_after>//===------------------------ ConstantnessSemaDiagnostics.cpp -------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements checks for checking whether certain arguments to some
// specific APIs are compile-time constants (see below for the definition of
// constants). In particular, this code checks whether the new os_log APIs are
// invoked with constant arguments, and whether the primitive atomic operations
// are invoked with constant "orderings". These APIs are identified through
// @_semantics attributes.
//
// A "compile-time constant" is either a literal (including
// string/integer/float/boolean/string-interpolation literal) or a call to a
// "constant_evaluable" function (or property) with compile-time constant
// arguments. A closure expression is also considered a compile-time constant
// (it is a constant of a function type).
//===----------------------------------------------------------------------===//

#include "MiscDiagnostics.h"
#include "TypeChecker.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/SemanticAttrs.h"
using namespace swift;

/// Check whether a given \p decl has a @_semantics attribute with the given
/// attribute name \c attrName.
static bool hasSemanticsAttr(ValueDecl *decl, StringRef attrName) {
  return decl->getAttrs().hasSemanticsAttr(attrName);
}

/// Return true iff  the given \p structDecl has a name that matches one of the
/// known atomic orderings structs.
static bool isAtomicOrderingDecl(StructDecl *structDecl) {
  ASTContext &astContext = structDecl->getASTContext();
  Identifier structName = structDecl->getName();
  return (structName == astContext.Id_AtomicLoadOrdering ||
          structName == astContext.Id_AtomicStoreOrdering ||
          structName == astContext.Id_AtomicUpdateOrdering);
}

/// Return true iff the given nominal type decl \p nominal has a name that
/// matches one of the known OSLog types that need not be a constant in the new
/// os_log APIs.
static bool isOSLogDynamicObject(NominalTypeDecl *nominal) {
  ASTContext &astContext = nominal->getASTContext();
  Identifier name = nominal->getName();
  return (name == astContext.Id_OSLog || name == astContext.Id_OSLogType);
}

/// Return true iff the parameter \p param of function \c funDecl is required to
/// be a constant. This is true if either the function is an os_log function or
/// it is an atomics operation and the parameter represents the ordering.
static bool isParamRequiredToBeConstant(AbstractFunctionDecl *funcDecl, ParamDecl *param) {
  assert(funcDecl && param && "funcDecl and param must not be null");
  Type paramType;
  NominalTypeDecl *nominal;
  StructDecl *structDecl;
  if (hasSemanticsAttr(funcDecl, semantics::OSLOG_REQUIRES_CONSTANT_ARGUMENTS))
    return true;
  if (hasSemanticsAttr(funcDecl, semantics::OSLOG_LOG_WITH_LEVEL)) {
    // We are looking at a top-level os_log function that accepts level and
    // possibly custom log object. Those need not be constants, but every other
    // parameter must be.
    paramType = param->getType();
    nominal = paramType->getNominalOrBoundGenericNominal();
    return !nominal || !isOSLogDynamicObject(nominal);
  }
  if (!hasSemanticsAttr(funcDecl,
                        semantics::ATOMICS_REQUIRES_CONSTANT_ORDERINGS))
    return false;
  paramType = param->getType();
  structDecl = paramType->getStructOrBoundGenericStruct();
  if (!structDecl)
    return false;
  return isAtomicOrderingDecl(structDecl);
}

/// Return true iff the \c decl is annotated as
/// @_semantics("constant_evaluable").
static bool hasConstantEvaluableAttr(ValueDecl *decl) {
  return hasSemanticsAttr(decl, semantics::CONSTANT_EVALUABLE);
}

/// Return true iff the \p decl is annotated with oslog.message.init semantics
/// attribute.
static bool isOSLogMessageInitializer(ValueDecl *decl) {
  return hasSemanticsAttr(decl, semantics::OSLOG_MESSAGE_INIT_STRING_LITERAL) ||
         hasSemanticsAttr(decl, semantics::OSLOG_MESSAGE_INIT_INTERPOLATION);
}

/// Check whether \p expr is a compile-time constant. It must either be a
/// literal_expr, which does not include array and dictionary literal, or a
/// closure expression, which is considered a compile-time constant of a
/// function type, or a call to a "constant_evaluable" function (or property)
/// whose arguments are themselves compile-time constants.
static Expr *checkConstantness(Expr *expr) {
  SmallVector<Expr *, 4> expressionsToCheck;
  expressionsToCheck.push_back(expr);
  while (!expressionsToCheck.empty()) {
    Expr *expr = expressionsToCheck.pop_back_val();
    // Lookthrough identity_expr, tuple, binary_expr and inject_into_optional expressions.
    if (IdentityExpr *identityExpr = dyn_cast<IdentityExpr>(expr)) {
      expressionsToCheck.push_back(identityExpr->getSubExpr());
      continue;
    }
    if (TupleExpr *tupleExpr = dyn_cast<TupleExpr>(expr)) {
      for (Expr *element : tupleExpr->getElements())
        expressionsToCheck.push_back(element);
      continue;
    }
    if (BinaryExpr *binaryExpr = dyn_cast<BinaryExpr>(expr)) {
      expressionsToCheck.push_back(binaryExpr->getLHS());
      expressionsToCheck.push_back(binaryExpr->getRHS());
      continue;
    }
    if (InjectIntoOptionalExpr *optionalExpr =
            dyn_cast<InjectIntoOptionalExpr>(expr)) {
      expressionsToCheck.push_back(optionalExpr->getSubExpr());
      continue;
    }
    // Literal expressions also includes InterpolatedStringLiteralExpr.
    if (isa<LiteralExpr>(expr))
      continue;
    if (isa<TypeExpr>(expr))
      continue;
    // Closure expressions are always treated as constants. They are
    // constants of function types.
    if (isa<AbstractClosureExpr>(expr))
      continue;
    // Default argument expressions of a constant_evaluable or a
    // requires_constant function must be ensured to be a constant by the
    // definition of the function.
    if (isa<DefaultArgumentExpr>(expr))
      continue;

    // If this is a member-ref, it has to be annotated constant evaluable.
    if (MemberRefExpr *memberRef = dyn_cast<MemberRefExpr>(expr)) {
      if (ValueDecl *memberDecl = memberRef->getMember().getDecl()) {
        if (hasConstantEvaluableAttr(memberDecl))
          continue;
      }
      return expr;
    }

    // If this is a variable, it has to be a known constant parameter of the
    // enclosing function.
    if (DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(expr)) {
      ValueDecl *decl = declRef->getDecl();
      if (!decl)
        return expr;
      ParamDecl *paramDecl = dyn_cast<ParamDecl>(decl);
      if (!paramDecl)
        return expr;
      Decl *declContext = paramDecl->getDeclContext()->getAsDecl();
      if (!declContext)
        return expr;
      AbstractFunctionDecl *funcDecl = dyn_cast<AbstractFunctionDecl>(declContext);
      if (!funcDecl || !isParamRequiredToBeConstant(funcDecl, paramDecl))
        return expr;
      continue;
    }

    if (!isa<ApplyExpr>(expr))
      return expr;

    ApplyExpr *apply = cast<ApplyExpr>(expr);
    ValueDecl *calledValue = apply->getCalledValue();
    if (!calledValue)
      return expr;

    // If this is an enum case, check whether the arguments are constants.
    if (isa<EnumElementDecl>(calledValue)) {
      for (auto arg : *apply->getArgs())
        expressionsToCheck.push_back(arg.getExpr());
      continue;
    }

    AbstractFunctionDecl *callee = dyn_cast<AbstractFunctionDecl>(calledValue);
    if (!callee)
      return expr;

    // If this is an application of OSLogMessage initializer, fail the check
    // as this type must be created from string interpolations.
    if (isOSLogMessageInitializer(callee))
      return expr;

    // If this is a constant_evaluable function, check whether the arguments are
    // constants.
    if (!hasConstantEvaluableAttr(callee))
      return expr;

    for (auto arg : *apply->getArgs())
      expressionsToCheck.push_back(arg.getExpr());
  }
  return nullptr;
}

/// Return true iff the given \p type is a Stdlib integer type.
static bool isIntegerType(Type type) {
  return type->isInt() || type->isInt8() || type->isInt16() ||
         type->isInt32() || type->isInt64() || type->isUInt() ||
         type->isUInt8() || type->isUInt16() || type->isUInt32() ||
         type->isUInt64();
}

/// Return true iff the given \p type is a Float type.
static bool isFloatType(Type type) {
  return type->isFloat() || type->isDouble() || type->isFloat80();
}

/// Given an error expression \p errorExpr, diagnose the error based on the type
/// of the expression. For instance, if the expression's type is expressible by
/// a literal e.g. integer, boolean etc. report that it must be a literal.
/// Otherwise, if the expression is a nominal type, report that it must be
/// static member of the type.
static void diagnoseError(Expr *errorExpr, const ASTContext &astContext,
                          AbstractFunctionDecl *funcDecl) {
  DiagnosticEngine &diags = astContext.Diags;
  Type exprType = errorExpr->getType();
  SourceLoc errorLoc = errorExpr->getLoc();

  // Diagnose atomics ordering related error here.
  if (hasSemanticsAttr(funcDecl,
                       semantics::ATOMICS_REQUIRES_CONSTANT_ORDERINGS)) {
    NominalTypeDecl *nominalDecl = exprType->getNominalOrBoundGenericNominal();
    if (!nominalDecl) {
      // This case should normally not happen. This is a safe guard against
      // possible mismatch between the atomics library and the compiler.
      diags.diagnose(errorLoc, diag::argument_must_be_constant);
    }
    diags.diagnose(errorLoc, diag::atomics_ordering_must_be_constant,
                   nominalDecl->getName());
    return;
  }

  // Diagnose os_log specific errors here.

  // Diagnose primitive stdlib types.
  if (exprType->isBool()) {
    diags.diagnose(errorLoc, diag::oslog_arg_must_be_bool_literal);
    return;
  }
  if (exprType->isString()) {
    diags.diagnose(errorLoc, diag::oslog_arg_must_be_string_literal);
    return;
  }
  if (isIntegerType(exprType)) {
    diags.diagnose(errorLoc, diag::oslog_arg_must_be_integer_literal);
    return;
  }
  if (isFloatType(exprType)) {
    diags.diagnose(errorLoc, diag::oslog_arg_must_be_float_literal);
    return;
  }
  if (exprType->is<MetatypeType>()) {
    diags.diagnose(errorLoc, diag::oslog_arg_must_be_metatype_literal);
    return;
  }
  if (exprType->is<AnyFunctionType>()) {
    diags.diagnose(errorLoc, diag::oslog_arg_must_be_closure);
    return;
  }
  if (EnumDecl *enumDecl = exprType->getEnumOrBoundGenericEnum()) {
    diags.diagnose(errorLoc, diag::oslog_arg_must_be_enum_case,
                   enumDecl->getName());
    return;
  }
  NominalTypeDecl *nominalDecl = exprType->getNominalOrBoundGenericNominal();
  if (!nominalDecl) {
    // This case should normally not happen. This is a safe guard against
    // possible mismatch between the os overlay and the compiler.
    diags.diagnose(errorLoc, diag::argument_must_be_constant);
    return;
  }
  // If this is OSLogMessage, it should be a string-interpolation literal.
  Identifier declName = nominalDecl->getName();
  if (declName == astContext.Id_OSLogMessage ||
      nominalDecl->hasSemanticsAttr(semantics::OSLOG_MESSAGE_TYPE)) {
    diags.diagnose(errorLoc, diag::oslog_message_must_be_string_interpolation);
    return;
  }
  diags.diagnose(errorLoc, diag::oslog_arg_must_be_type_member_access,
                 declName);
}

/// Given a call \c callExpr, if some or all of its arguments are required to be
/// constants, check that property on the arguments.
static void diagnoseConstantArgumentRequirementOfCall(const CallExpr *callExpr,
                                                      const ASTContext &ctx) {
  assert(callExpr && callExpr->getType() &&
         "callExpr should have a valid type");
  ValueDecl *calledDecl = callExpr->getCalledValue();
  if (!calledDecl || !isa<AbstractFunctionDecl>(calledDecl))
    return;
  AbstractFunctionDecl *callee = cast<AbstractFunctionDecl>(calledDecl);

  // Collect argument indices that are required to be constants.
  SmallVector<unsigned, 4> constantArgumentIndices;
  auto paramList = callee->getParameters();
  for (unsigned i = 0; i < paramList->size(); ++i) {
    ParamDecl *param = paramList->get(i);
    if (isParamRequiredToBeConstant(callee, param))
      constantArgumentIndices.push_back(i);
  }
  if (constantArgumentIndices.empty())
    return;

  // Check that the arguments at the constantArgumentIndices are constants.
  SmallVector<Expr *, 4> arguments;
  for (auto arg : *callExpr->getArgs())
    arguments.push_back(arg.getExpr());

  for (unsigned constantIndex : constantArgumentIndices) {
    assert(constantIndex < arguments.size() &&
           "constantIndex exceeds the number of arguments to the function");
    Expr *argument = arguments[constantIndex];
    Expr *errorExpr = checkConstantness(argument);
    if (errorExpr)
      diagnoseError(errorExpr, ctx, callee);
  }
}

void swift::diagnoseConstantArgumentRequirement(
    const Expr *expr, const DeclContext *declContext) {
  class ConstantReqCallWalker : public ASTWalker {
    DeclContext *DC;

  public:
    ConstantReqCallWalker(DeclContext *DC) : DC(DC) {}

    // Descend until we find a call expressions. Note that the input expression
    // could be an assign expression or another expression that contains the
    // call.
    std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
      // Handle closure expressions separately as we may need to
      // manually descend into the body.
      if (auto *closureExpr = dyn_cast<ClosureExpr>(expr)) {
        return walkToClosureExprPre(closureExpr);
      }
      // Interpolated expressions' bodies will be type checked
      // separately so exit early to avoid duplicate diagnostics.
      if (!expr || isa<ErrorExpr>(expr) || !expr->getType() ||
          isa<InterpolatedStringLiteralExpr>(expr))
        return {false, expr};
      if (auto *callExpr = dyn_cast<CallExpr>(expr)) {
        diagnoseConstantArgumentRequirementOfCall(callExpr, DC->getASTContext());
      }
      return {true, expr};
    }

    std::pair<bool, Expr *> walkToClosureExprPre(ClosureExpr *closure) {
      auto &ctx = DC->getASTContext();

      if (closure->hasSingleExpressionBody() ||
          ctx.TypeCheckerOpts.EnableMultiStatementClosureInference) {
        // Closure bodies are not visited directly by the ASTVisitor,
        // so we must descend into the body manuall and set the
        // DeclContext to that of the closure.
        DC = closure;
        return {true, closure};
      }
      return {false, closure};
    }

    Expr *walkToExprPost(Expr *expr) override {
      if (auto *closureExpr = dyn_cast<ClosureExpr>(expr)) {
        // Reset the DeclContext to the outer scope if we descended
        // into a closure expr.
        DC = closureExpr->getParent();
      }
      return expr;
    }

    std::pair<bool, Stmt *> walkToStmtPre(Stmt *stmt) override {
      return {true, stmt};
    }
  };

  ConstantReqCallWalker walker(const_cast<DeclContext *>(declContext));
  const_cast<Expr *>(expr)->walk(walker);
}
<|endoftext|>


<commit_before>//===-- SIShrinkInstructions.cpp - Shrink Instructions --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
/// The pass tries to use the 32-bit encoding for instructions when possible.
//===----------------------------------------------------------------------===//
//

#include "AMDGPU.h"
#include "SIInstrInfo.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetMachine.h"

#define DEBUG_TYPE "si-shrink-instructions"

STATISTIC(NumInstructionsShrunk,
          "Number of 64-bit instruction reduced to 32-bit.");
STATISTIC(NumLiteralConstantsFolded,
          "Number of literal constants folded into 32-bit instructions.");

namespace llvm {
  void initializeSIShrinkInstructionsPass(PassRegistry&);
}

using namespace llvm;

namespace {

class SIShrinkInstructions : public MachineFunctionPass {
public:
  static char ID;

public:
  SIShrinkInstructions() : MachineFunctionPass(ID) {
  }

  virtual bool runOnMachineFunction(MachineFunction &MF) override;

  virtual const char *getPassName() const override {
    return "SI Shrink Instructions";
  }

  virtual void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.setPreservesCFG();
    MachineFunctionPass::getAnalysisUsage(AU);
  }
};

} // End anonymous namespace.

INITIALIZE_PASS_BEGIN(SIShrinkInstructions, DEBUG_TYPE,
                      "SI Lower il Copies", false, false)
INITIALIZE_PASS_END(SIShrinkInstructions, DEBUG_TYPE,
                    "SI Lower il Copies", false, false)

char SIShrinkInstructions::ID = 0;

FunctionPass *llvm::createSIShrinkInstructionsPass() {
  return new SIShrinkInstructions();
}

static bool isVGPR(const MachineOperand *MO, const SIRegisterInfo &TRI,
                   const MachineRegisterInfo &MRI) {
  if (!MO->isReg())
    return false;

  if (TargetRegisterInfo::isVirtualRegister(MO->getReg()))
    return TRI.hasVGPRs(MRI.getRegClass(MO->getReg()));

  return TRI.hasVGPRs(TRI.getPhysRegClass(MO->getReg()));
}

static bool canShrink(MachineInstr &MI, const SIInstrInfo *TII,
                      const SIRegisterInfo &TRI,
                      const MachineRegisterInfo &MRI) {

  const MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
  // Can't shrink instruction with three operands.
  if (Src2)
    return false;

  const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
  const MachineOperand *Src1Mod =
      TII->getNamedOperand(MI, AMDGPU::OpName::src1_modifiers);

  if (Src1 && (!isVGPR(Src1, TRI, MRI) || (Src1Mod && Src1Mod->getImm() != 0)))
    return false;

  // We don't need to check src0, all input types are legal, so just make
  // sure src0 isn't using any modifiers.
  const MachineOperand *Src0Mod =
      TII->getNamedOperand(MI, AMDGPU::OpName::src0_modifiers);
  if (Src0Mod && Src0Mod->getImm() != 0)
    return false;

  // Check output modifiers
  const MachineOperand *Omod = TII->getNamedOperand(MI, AMDGPU::OpName::omod);
  if (Omod && Omod->getImm() != 0)
    return false;

  const MachineOperand *Clamp = TII->getNamedOperand(MI, AMDGPU::OpName::clamp);
  return !Clamp || Clamp->getImm() == 0;
}

/// \brief This function checks \p MI for operands defined by a move immediate
/// instruction and then folds the literal constant into the instruction if it
/// can.  This function assumes that \p MI is a VOP1, VOP2, or VOPC instruction
/// and will only fold literal constants if we are still in SSA.
static void foldImmediates(MachineInstr &MI, const SIInstrInfo *TII,
                           MachineRegisterInfo &MRI, bool TryToCommute = true) {

  if (!MRI.isSSA())
    return;

  assert(TII->isVOP1(MI.getOpcode()) || TII->isVOP2(MI.getOpcode()) ||
         TII->isVOPC(MI.getOpcode()));

  const SIRegisterInfo &TRI = TII->getRegisterInfo();
  MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);

  // Only one literal constant is allowed per instruction, so if src0 is a
  // literal constant then we can't do any folding.
  if (Src0->isImm() && TII->isLiteralConstant(*Src0))
    return;

  // Literal constants and SGPRs can only be used in Src0, so if Src0 is an
  // SGPR, we cannot commute the instruction, so we can't fold any literal
  // constants.
  if (Src0->isReg() && !isVGPR(Src0, TRI, MRI))
    return;

  // Try to fold Src0
  if (Src0->isReg()) {
    unsigned Reg = Src0->getReg();
    MachineInstr *Def = MRI.getUniqueVRegDef(Reg);
    if (Def && Def->isMoveImmediate()) {
      MachineOperand &MovSrc = Def->getOperand(1);
      bool ConstantFolded = false;

      if (MovSrc.isImm() && isUInt<32>(MovSrc.getImm())) {
        Src0->ChangeToImmediate(MovSrc.getImm());
        ConstantFolded = true;
      } else if (MovSrc.isFPImm()) {
        const APFloat &APF = MovSrc.getFPImm()->getValueAPF();
        if (&APF.getSemantics() == &APFloat::IEEEsingle) {
          MRI.removeRegOperandFromUseList(Src0);
          Src0->ChangeToImmediate(APF.bitcastToAPInt().getZExtValue());
          ConstantFolded = true;
        }
      }
      if (ConstantFolded) {
        for (MachineOperand &Use : MRI.use_operands(Reg))
          Use.getParent()->dump();
        if (MRI.use_empty(Reg))
          Def->eraseFromParent();
        ++NumLiteralConstantsFolded;
        return;
      }
    }
  }

  // We have failed to fold src0, so commute the instruction and try again.
  if (TryToCommute && MI.isCommutable() && TII->commuteInstruction(&MI))
    foldImmediates(MI, TII, MRI, false);

}

bool SIShrinkInstructions::runOnMachineFunction(MachineFunction &MF) {
  MachineRegisterInfo &MRI = MF.getRegInfo();
  const SIInstrInfo *TII = static_cast<const SIInstrInfo *>(
      MF.getTarget().getInstrInfo());
  const SIRegisterInfo &TRI = TII->getRegisterInfo();
  std::vector<unsigned> I1Defs;

  for (MachineFunction::iterator BI = MF.begin(), BE = MF.end();
                                                  BI != BE; ++BI) {

    MachineBasicBlock &MBB = *BI;
    MachineBasicBlock::iterator I, Next;
    for (I = MBB.begin(); I != MBB.end(); I = Next) {
      Next = std::next(I);
      MachineInstr &MI = *I;

      if (!TII->hasVALU32BitEncoding(MI.getOpcode()))
        continue;

      if (!canShrink(MI, TII, TRI, MRI)) {
        // Try commtuing the instruction and see if that enables us to shrink
        // it.
        if (!MI.isCommutable() || !TII->commuteInstruction(&MI) ||
            !canShrink(MI, TII, TRI, MRI))
          continue;
      }

      int Op32 = AMDGPU::getVOPe32(MI.getOpcode());

      // Op32 could be -1 here if we started with an instruction that had a
      // a 32-bit encoding and then commuted it to an instruction that did not.
      if (Op32 == -1)
        continue;

      if (TII->isVOPC(Op32)) {
        unsigned DstReg = MI.getOperand(0).getReg();
        if (TargetRegisterInfo::isVirtualRegister(DstReg)) {
          // VOPC instructions can only write to the VCC register.  We can't
          // force them to use VCC here, because the register allocator
          // has trouble with sequences like this, which cause the allocator
          // to run out of registes if vreg0 and vreg1 belong to the VCCReg
          // register class:
          // vreg0 = VOPC;
          // vreg1 = VOPC;
          // S_AND_B64 vreg0, vreg1
          //
          // So, instead of forcing the instruction to write to VCC, we provide a
          // hint to the register allocator to use VCC and then we
          // we will run this pass again after RA and shrink it if it outpus to
          // VCC.
          MRI.setRegAllocationHint(MI.getOperand(0).getReg(), 0, AMDGPU::VCC);
          continue;
        }
        if (DstReg != AMDGPU::VCC)
          continue;
      }

      // We can shrink this instruction
      DEBUG(dbgs() << "Shrinking "; MI.dump(); dbgs() << '\n';);

      MachineInstrBuilder Inst32 =
          BuildMI(MBB, I, MI.getDebugLoc(), TII->get(Op32));

      // dst
      Inst32.addOperand(MI.getOperand(0));

      Inst32.addOperand(*TII->getNamedOperand(MI, AMDGPU::OpName::src0));

      const MachineOperand *Src1 =
          TII->getNamedOperand(MI, AMDGPU::OpName::src1);
      if (Src1)
        Inst32.addOperand(*Src1);

      ++NumInstructionsShrunk;
      MI.eraseFromParent();

      foldImmediates(*Inst32, TII, MRI);
      DEBUG(dbgs() << "e32 MI = " << *Inst32 << '\n');

    }
  }
  return false;
}
<commit_msg>R600/SI: Remove leftover debugging code<commit_after>//===-- SIShrinkInstructions.cpp - Shrink Instructions --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
/// The pass tries to use the 32-bit encoding for instructions when possible.
//===----------------------------------------------------------------------===//
//

#include "AMDGPU.h"
#include "SIInstrInfo.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetMachine.h"

#define DEBUG_TYPE "si-shrink-instructions"

STATISTIC(NumInstructionsShrunk,
          "Number of 64-bit instruction reduced to 32-bit.");
STATISTIC(NumLiteralConstantsFolded,
          "Number of literal constants folded into 32-bit instructions.");

namespace llvm {
  void initializeSIShrinkInstructionsPass(PassRegistry&);
}

using namespace llvm;

namespace {

class SIShrinkInstructions : public MachineFunctionPass {
public:
  static char ID;

public:
  SIShrinkInstructions() : MachineFunctionPass(ID) {
  }

  virtual bool runOnMachineFunction(MachineFunction &MF) override;

  virtual const char *getPassName() const override {
    return "SI Shrink Instructions";
  }

  virtual void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.setPreservesCFG();
    MachineFunctionPass::getAnalysisUsage(AU);
  }
};

} // End anonymous namespace.

INITIALIZE_PASS_BEGIN(SIShrinkInstructions, DEBUG_TYPE,
                      "SI Lower il Copies", false, false)
INITIALIZE_PASS_END(SIShrinkInstructions, DEBUG_TYPE,
                    "SI Lower il Copies", false, false)

char SIShrinkInstructions::ID = 0;

FunctionPass *llvm::createSIShrinkInstructionsPass() {
  return new SIShrinkInstructions();
}

static bool isVGPR(const MachineOperand *MO, const SIRegisterInfo &TRI,
                   const MachineRegisterInfo &MRI) {
  if (!MO->isReg())
    return false;

  if (TargetRegisterInfo::isVirtualRegister(MO->getReg()))
    return TRI.hasVGPRs(MRI.getRegClass(MO->getReg()));

  return TRI.hasVGPRs(TRI.getPhysRegClass(MO->getReg()));
}

static bool canShrink(MachineInstr &MI, const SIInstrInfo *TII,
                      const SIRegisterInfo &TRI,
                      const MachineRegisterInfo &MRI) {

  const MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
  // Can't shrink instruction with three operands.
  if (Src2)
    return false;

  const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
  const MachineOperand *Src1Mod =
      TII->getNamedOperand(MI, AMDGPU::OpName::src1_modifiers);

  if (Src1 && (!isVGPR(Src1, TRI, MRI) || (Src1Mod && Src1Mod->getImm() != 0)))
    return false;

  // We don't need to check src0, all input types are legal, so just make
  // sure src0 isn't using any modifiers.
  const MachineOperand *Src0Mod =
      TII->getNamedOperand(MI, AMDGPU::OpName::src0_modifiers);
  if (Src0Mod && Src0Mod->getImm() != 0)
    return false;

  // Check output modifiers
  const MachineOperand *Omod = TII->getNamedOperand(MI, AMDGPU::OpName::omod);
  if (Omod && Omod->getImm() != 0)
    return false;

  const MachineOperand *Clamp = TII->getNamedOperand(MI, AMDGPU::OpName::clamp);
  return !Clamp || Clamp->getImm() == 0;
}

/// \brief This function checks \p MI for operands defined by a move immediate
/// instruction and then folds the literal constant into the instruction if it
/// can.  This function assumes that \p MI is a VOP1, VOP2, or VOPC instruction
/// and will only fold literal constants if we are still in SSA.
static void foldImmediates(MachineInstr &MI, const SIInstrInfo *TII,
                           MachineRegisterInfo &MRI, bool TryToCommute = true) {

  if (!MRI.isSSA())
    return;

  assert(TII->isVOP1(MI.getOpcode()) || TII->isVOP2(MI.getOpcode()) ||
         TII->isVOPC(MI.getOpcode()));

  const SIRegisterInfo &TRI = TII->getRegisterInfo();
  MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);

  // Only one literal constant is allowed per instruction, so if src0 is a
  // literal constant then we can't do any folding.
  if (Src0->isImm() && TII->isLiteralConstant(*Src0))
    return;

  // Literal constants and SGPRs can only be used in Src0, so if Src0 is an
  // SGPR, we cannot commute the instruction, so we can't fold any literal
  // constants.
  if (Src0->isReg() && !isVGPR(Src0, TRI, MRI))
    return;

  // Try to fold Src0
  if (Src0->isReg()) {
    unsigned Reg = Src0->getReg();
    MachineInstr *Def = MRI.getUniqueVRegDef(Reg);
    if (Def && Def->isMoveImmediate()) {
      MachineOperand &MovSrc = Def->getOperand(1);
      bool ConstantFolded = false;

      if (MovSrc.isImm() && isUInt<32>(MovSrc.getImm())) {
        Src0->ChangeToImmediate(MovSrc.getImm());
        ConstantFolded = true;
      } else if (MovSrc.isFPImm()) {
        const APFloat &APF = MovSrc.getFPImm()->getValueAPF();
        if (&APF.getSemantics() == &APFloat::IEEEsingle) {
          MRI.removeRegOperandFromUseList(Src0);
          Src0->ChangeToImmediate(APF.bitcastToAPInt().getZExtValue());
          ConstantFolded = true;
        }
      }
      if (ConstantFolded) {
        if (MRI.use_empty(Reg))
          Def->eraseFromParent();
        ++NumLiteralConstantsFolded;
        return;
      }
    }
  }

  // We have failed to fold src0, so commute the instruction and try again.
  if (TryToCommute && MI.isCommutable() && TII->commuteInstruction(&MI))
    foldImmediates(MI, TII, MRI, false);

}

bool SIShrinkInstructions::runOnMachineFunction(MachineFunction &MF) {
  MachineRegisterInfo &MRI = MF.getRegInfo();
  const SIInstrInfo *TII = static_cast<const SIInstrInfo *>(
      MF.getTarget().getInstrInfo());
  const SIRegisterInfo &TRI = TII->getRegisterInfo();
  std::vector<unsigned> I1Defs;

  for (MachineFunction::iterator BI = MF.begin(), BE = MF.end();
                                                  BI != BE; ++BI) {

    MachineBasicBlock &MBB = *BI;
    MachineBasicBlock::iterator I, Next;
    for (I = MBB.begin(); I != MBB.end(); I = Next) {
      Next = std::next(I);
      MachineInstr &MI = *I;

      if (!TII->hasVALU32BitEncoding(MI.getOpcode()))
        continue;

      if (!canShrink(MI, TII, TRI, MRI)) {
        // Try commtuing the instruction and see if that enables us to shrink
        // it.
        if (!MI.isCommutable() || !TII->commuteInstruction(&MI) ||
            !canShrink(MI, TII, TRI, MRI))
          continue;
      }

      int Op32 = AMDGPU::getVOPe32(MI.getOpcode());

      // Op32 could be -1 here if we started with an instruction that had a
      // a 32-bit encoding and then commuted it to an instruction that did not.
      if (Op32 == -1)
        continue;

      if (TII->isVOPC(Op32)) {
        unsigned DstReg = MI.getOperand(0).getReg();
        if (TargetRegisterInfo::isVirtualRegister(DstReg)) {
          // VOPC instructions can only write to the VCC register.  We can't
          // force them to use VCC here, because the register allocator
          // has trouble with sequences like this, which cause the allocator
          // to run out of registes if vreg0 and vreg1 belong to the VCCReg
          // register class:
          // vreg0 = VOPC;
          // vreg1 = VOPC;
          // S_AND_B64 vreg0, vreg1
          //
          // So, instead of forcing the instruction to write to VCC, we provide a
          // hint to the register allocator to use VCC and then we
          // we will run this pass again after RA and shrink it if it outpus to
          // VCC.
          MRI.setRegAllocationHint(MI.getOperand(0).getReg(), 0, AMDGPU::VCC);
          continue;
        }
        if (DstReg != AMDGPU::VCC)
          continue;
      }

      // We can shrink this instruction
      DEBUG(dbgs() << "Shrinking "; MI.dump(); dbgs() << '\n';);

      MachineInstrBuilder Inst32 =
          BuildMI(MBB, I, MI.getDebugLoc(), TII->get(Op32));

      // dst
      Inst32.addOperand(MI.getOperand(0));

      Inst32.addOperand(*TII->getNamedOperand(MI, AMDGPU::OpName::src0));

      const MachineOperand *Src1 =
          TII->getNamedOperand(MI, AMDGPU::OpName::src1);
      if (Src1)
        Inst32.addOperand(*Src1);

      ++NumInstructionsShrunk;
      MI.eraseFromParent();

      foldImmediates(*Inst32, TII, MRI);
      DEBUG(dbgs() << "e32 MI = " << *Inst32 << '\n');

    }
  }
  return false;
}
<|endoftext|>


<commit_before>//===- LoopIndexSplit.cpp - Loop Index Splitting Pass ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Devang Patel and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements Loop Index Splitting Pass.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "loop-index-split"

#include "llvm/Function.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/ScalarEvolutionExpander.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/Statistic.h"

using namespace llvm;

STATISTIC(NumIndexSplit, "Number of loops index split");

namespace {

  class VISIBILITY_HIDDEN LoopIndexSplit : public LoopPass {

  public:
    static char ID; // Pass ID, replacement for typeid
    LoopIndexSplit() : LoopPass((intptr_t)&ID) {}

    // Index split Loop L. Return true if loop is split.
    bool runOnLoop(Loop *L, LPPassManager &LPM);

    void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequired<ScalarEvolution>();
      AU.addPreserved<ScalarEvolution>();
      AU.addRequiredID(LCSSAID);
      AU.addPreservedID(LCSSAID);
      AU.addPreserved<LoopInfo>();
      AU.addRequiredID(LoopSimplifyID);
      AU.addPreservedID(LoopSimplifyID);
    }

  private:
    /// Find condition inside a loop that is suitable candidate for index split.
    void findSplitCondition();

    /// processOneIterationLoop - Current loop L contains compare instruction
    /// that compares induction variable, IndVar, agains loop invariant. If
    /// entire (i.e. meaningful) loop body is dominated by this compare
    /// instruction then loop body is executed only for one iteration. In
    /// such case eliminate loop structure surrounding this loop body. For
    bool processOneIterationLoop(LPPassManager &LPM);

    // If loop header includes loop variant instruction operands then
    // this loop may not be eliminated.
    bool safeHeader(BasicBlock *BB);

    // If Exit block includes loop variant instructions then this
    // loop may not be eliminated.
    bool safeExitBlock(BasicBlock *BB);

    bool splitLoop();

  private:

    // Current Loop.
    Loop *L;
    ScalarEvolution *SE;

    // Induction variable whose range is being split by this transformation.
    PHINode *IndVar;

    // Induction variable's range is split at this value.
    Value *SplitValue;

    // Induction variable's final loop exit value.
    Value *ExitValue;

    // This compare instruction compares IndVar against SplitValue.
    ICmpInst *SplitCondition;
  };

  char LoopIndexSplit::ID = 0;
  RegisterPass<LoopIndexSplit> X ("loop-index-split", "Index Split Loops");
}

LoopPass *llvm::createLoopIndexSplitPass() {
  return new LoopIndexSplit();
}

// Index split Loop L. Return true if loop is split.
bool LoopIndexSplit::runOnLoop(Loop *IncomingLoop, LPPassManager &LPM) {
  bool Changed = false;
  L = IncomingLoop;
  SplitCondition = NULL;
  SE = &getAnalysis<ScalarEvolution>();

  findSplitCondition();

  if (!SplitCondition)
    return false;

  if (SplitCondition->getPredicate() == ICmpInst::ICMP_EQ)
    // If it is possible to eliminate loop then do so.
    Changed = processOneIterationLoop(LPM);
  else
    Changed = splitLoop();

  if (Changed)
    ++NumIndexSplit;

  return Changed;
}

/// Find condition inside a loop that is suitable candidate for index split.
void LoopIndexSplit::findSplitCondition() {

 BasicBlock *Header = L->getHeader();

  for (BasicBlock::iterator I = Header->begin(); isa<PHINode>(I); ++I) {
    PHINode *PN = cast<PHINode>(I);

    if (!PN->getType()->isInteger())
      continue;

    SCEVHandle SCEV = SE->getSCEV(PN);
    if (!isa<SCEVAddRecExpr>(SCEV))
      continue;

    // If this phi node is used in a compare instruction then it is a
    // split condition candidate.
    for (Value::use_iterator UI = PN->use_begin(), E = PN->use_end();
         UI != E; ++UI) {
      if (ICmpInst *CI = dyn_cast<ICmpInst>(*UI)) {
        SplitCondition = CI;
        break;
      }
    }

    // Valid SplitCondition's one operand is phi node and the other operand
    // is loop invariant.
    if (SplitCondition) {
      if (SplitCondition->getOperand(0) != PN)
        SplitValue = SplitCondition->getOperand(0);
      else
        SplitValue = SplitCondition->getOperand(1);
      SCEVHandle ValueSCEV = SE->getSCEV(SplitValue);

      // If SplitValue is not invariant then SplitCondition is not appropriate.
      if (!ValueSCEV->isLoopInvariant(L))
        SplitCondition = NULL;
    }

    // We are looking for only one split condition.
    if (SplitCondition) {
      IndVar = PN;
      break;
    }
  }
}

/// processOneIterationLoop - Current loop L contains compare instruction
/// that compares induction variable, IndVar, against loop invariant. If
/// entire (i.e. meaningful) loop body is dominated by this compare
/// instruction then loop body is executed only once. In such case eliminate
/// loop structure surrounding this loop body. For example,
///     for (int i = start; i < end; ++i) {
///         if ( i == somevalue) {
///           loop_body
///         }
///     }
/// can be transformed into
///     if (somevalue >= start && somevalue < end) {
///        i = somevalue;
///        loop_body
///     }
bool LoopIndexSplit::processOneIterationLoop(LPPassManager &LPM) {

  BasicBlock *Header = L->getHeader();

  // First of all, check if SplitCondition dominates entire loop body
  // or not.

  // If SplitCondition is not in loop header then this loop is not suitable
  // for this transformation.
  if (SplitCondition->getParent() != Header)
    return false;

  // If one of the Header block's successor is not an exit block then this
  // loop is not a suitable candidate.
  BasicBlock *ExitBlock = NULL;
  for (succ_iterator SI = succ_begin(Header), E = succ_end(Header); SI != E; ++SI) {
    if (L->isLoopExit(*SI)) {
      ExitBlock = *SI;
      break;
    }
  }

  if (!ExitBlock)
    return false;

  // If loop header includes loop variant instruction operands then
  // this loop may not be eliminated.
  if (!safeHeader(Header))
    return false;

  // If Exit block includes loop variant instructions then this
  // loop may not be eliminated.
  if (!safeExitBlock(ExitBlock))
    return false;

  BasicBlock *Latch = L->getLoopLatch();
  BasicBlock *Preheader = L->getLoopPreheader();
  Instruction *Terminator = Header->getTerminator();
  Value *StartValue = IndVar->getIncomingValueForBlock(Preheader);

  // Update CFG.

  // Replace split condition in header.
  // Transform
  //      SplitCondition : icmp eq i32 IndVar, SplitValue
  // into
  //      c1 = icmp uge i32 SplitValue, StartValue
  //      c2 = icmp ult i32 vSplitValue, ExitValue
  //      and i32 c1, c2
  bool SignedPredicate = SplitCondition->isSignedPredicate();
  Instruction *C1 = new ICmpInst(SignedPredicate ?
                                 ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE,
                                 SplitValue, StartValue, "lisplit", Terminator);
  Instruction *C2 = new ICmpInst(SignedPredicate ?
                                 ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT,
                                 SplitValue, ExitValue, "lisplit", Terminator);
  Instruction *NSplitCond = BinaryOperator::create(Instruction::And,
                                                   C1, C2, "lisplit", Terminator);
  SplitCondition->replaceAllUsesWith(NSplitCond);
  SplitCondition->removeFromParent();
  delete SplitCondition;

  // As a first step to break this loop, remove Latch to Header edge.
  BasicBlock *LatchSucc = NULL;
  Header->removePredecessor(Latch);
  for (succ_iterator SI = succ_begin(Latch), E = succ_end(Latch);
       SI != E; ++SI) {
    if (Header != *SI)
      LatchSucc = *SI;
  }
  BranchInst *BR = dyn_cast<BranchInst>(Latch->getTerminator());
  BR->setUnconditionalDest(LatchSucc);

  // Now, clear latch block. Remove instructions that are responsible
  // to increment induction variable.
  Instruction *LTerminator = Latch->getTerminator();
  for (BasicBlock::iterator LB = Latch->begin(), LE = Latch->end();
       LB != LE; ) {
    Instruction *I = LB;
    ++LB;
    if (isa<PHINode>(I) || I == LTerminator)
      continue;

    I->replaceAllUsesWith(UndefValue::get(I->getType()));
    I->removeFromParent();
    delete I;
  }

  LPM.deleteLoopFromQueue(L);
  return true;
}

// If loop header includes loop variant instruction operands then
// this loop can not be eliminated. This is used by processOneIterationLoop().
bool LoopIndexSplit::safeHeader(BasicBlock *Header) {

  Instruction *Terminator = Header->getTerminator();
  for(BasicBlock::iterator BI = Header->begin(), BE = Header->end();
      BI != BE; ++BI) {
    Instruction *I = BI;

    // PHI Nodes are OK.
    if (isa<PHINode>(I))
      continue;

    // SplitCondition itself is OK.
    if (ICmpInst *CI = dyn_cast<ICmpInst>(I)) {
      if (CI == SplitCondition)
        continue;
    }

    // Terminator is also harmless.
    if (I == Terminator)
      continue;

    // Otherwise we have a instruction that may not be safe.
    return false;
  }

  return true;
}

// If Exit block includes loop variant instructions then this
// loop may not be eliminated. This is used by processOneIterationLoop().
bool LoopIndexSplit::safeExitBlock(BasicBlock *ExitBlock) {

  Instruction *ExitCondition = NULL;
  Instruction *IndVarIncrement = NULL;

  for (BasicBlock::iterator BI = ExitBlock->begin(), BE = ExitBlock->end();
       BI != BE; ++BI) {
    Instruction *I = BI;

    // PHI Nodes are OK.
    if (isa<PHINode>(I))
      continue;

    // Check if I is induction variable increment instruction.
    if (BinaryOperator *BOp = dyn_cast<BinaryOperator>(I)) {
      if (BOp->getOpcode() != Instruction::Add)
        return false;

      Value *Op0 = BOp->getOperand(0);
      Value *Op1 = BOp->getOperand(1);
      PHINode *PN = NULL;
      ConstantInt *CI = NULL;

      if ((PN = dyn_cast<PHINode>(Op0))) {
        if ((CI = dyn_cast<ConstantInt>(Op1)))
          IndVarIncrement = I;
      } else
        if ((PN = dyn_cast<PHINode>(Op1))) {
          if ((CI = dyn_cast<ConstantInt>(Op0)))
            IndVarIncrement = I;
      }

      if (IndVarIncrement && PN == IndVar && CI->isOne())
        continue;
    }
    // I is an Exit condition if next instruction is block terminator.
    // Exit condition is OK if it compares loop invariant exit value,
    // which is checked below.
    else if (isa<ICmpInst>(I)) {
      ++BI;
      Instruction *N = BI;
      if (N == ExitBlock->getTerminator()) {
        ExitCondition = I;
        break;
      }
    }

    // Otherwise we have instruction that may not be safe.
    return false;
  }

  // Check if Exit condition is comparing induction variable against
  // loop invariant value. If one operand is induction variable and
  // the other operand is loop invaraint then Exit condition is safe.
  if (ExitCondition) {
    Value *Op0 = ExitCondition->getOperand(0);
    Value *Op1 = ExitCondition->getOperand(1);

    Instruction *Insn0 = dyn_cast<Instruction>(Op0);
    Instruction *Insn1 = dyn_cast<Instruction>(Op1);

    if (Insn0 && Insn0 == IndVarIncrement)
      ExitValue = Op1;
    else if (Insn1 && Insn1 == IndVarIncrement)
      ExitValue = Op0;

    SCEVHandle ValueSCEV = SE->getSCEV(ExitValue);
    if (!ValueSCEV->isLoopInvariant(L))
      return false;
  }

  // We could not find any reason to consider ExitBlock unsafe.
  return true;
}

bool LoopIndexSplit::splitLoop() {
  // FIXME :)
  return false;
}
<commit_msg>Use eraseFromParent().<commit_after>//===- LoopIndexSplit.cpp - Loop Index Splitting Pass ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Devang Patel and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements Loop Index Splitting Pass.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "loop-index-split"

#include "llvm/Function.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/ScalarEvolutionExpander.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/Statistic.h"

using namespace llvm;

STATISTIC(NumIndexSplit, "Number of loops index split");

namespace {

  class VISIBILITY_HIDDEN LoopIndexSplit : public LoopPass {

  public:
    static char ID; // Pass ID, replacement for typeid
    LoopIndexSplit() : LoopPass((intptr_t)&ID) {}

    // Index split Loop L. Return true if loop is split.
    bool runOnLoop(Loop *L, LPPassManager &LPM);

    void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequired<ScalarEvolution>();
      AU.addPreserved<ScalarEvolution>();
      AU.addRequiredID(LCSSAID);
      AU.addPreservedID(LCSSAID);
      AU.addPreserved<LoopInfo>();
      AU.addRequiredID(LoopSimplifyID);
      AU.addPreservedID(LoopSimplifyID);
    }

  private:
    /// Find condition inside a loop that is suitable candidate for index split.
    void findSplitCondition();

    /// processOneIterationLoop - Current loop L contains compare instruction
    /// that compares induction variable, IndVar, agains loop invariant. If
    /// entire (i.e. meaningful) loop body is dominated by this compare
    /// instruction then loop body is executed only for one iteration. In
    /// such case eliminate loop structure surrounding this loop body. For
    bool processOneIterationLoop(LPPassManager &LPM);

    // If loop header includes loop variant instruction operands then
    // this loop may not be eliminated.
    bool safeHeader(BasicBlock *BB);

    // If Exit block includes loop variant instructions then this
    // loop may not be eliminated.
    bool safeExitBlock(BasicBlock *BB);

    bool splitLoop();

  private:

    // Current Loop.
    Loop *L;
    ScalarEvolution *SE;

    // Induction variable whose range is being split by this transformation.
    PHINode *IndVar;

    // Induction variable's range is split at this value.
    Value *SplitValue;

    // Induction variable's final loop exit value.
    Value *ExitValue;

    // This compare instruction compares IndVar against SplitValue.
    ICmpInst *SplitCondition;
  };

  char LoopIndexSplit::ID = 0;
  RegisterPass<LoopIndexSplit> X ("loop-index-split", "Index Split Loops");
}

LoopPass *llvm::createLoopIndexSplitPass() {
  return new LoopIndexSplit();
}

// Index split Loop L. Return true if loop is split.
bool LoopIndexSplit::runOnLoop(Loop *IncomingLoop, LPPassManager &LPM) {
  bool Changed = false;
  L = IncomingLoop;
  SplitCondition = NULL;
  SE = &getAnalysis<ScalarEvolution>();

  findSplitCondition();

  if (!SplitCondition)
    return false;

  if (SplitCondition->getPredicate() == ICmpInst::ICMP_EQ)
    // If it is possible to eliminate loop then do so.
    Changed = processOneIterationLoop(LPM);
  else
    Changed = splitLoop();

  if (Changed)
    ++NumIndexSplit;

  return Changed;
}

/// Find condition inside a loop that is suitable candidate for index split.
void LoopIndexSplit::findSplitCondition() {

 BasicBlock *Header = L->getHeader();

  for (BasicBlock::iterator I = Header->begin(); isa<PHINode>(I); ++I) {
    PHINode *PN = cast<PHINode>(I);

    if (!PN->getType()->isInteger())
      continue;

    SCEVHandle SCEV = SE->getSCEV(PN);
    if (!isa<SCEVAddRecExpr>(SCEV))
      continue;

    // If this phi node is used in a compare instruction then it is a
    // split condition candidate.
    for (Value::use_iterator UI = PN->use_begin(), E = PN->use_end();
         UI != E; ++UI) {
      if (ICmpInst *CI = dyn_cast<ICmpInst>(*UI)) {
        SplitCondition = CI;
        break;
      }
    }

    // Valid SplitCondition's one operand is phi node and the other operand
    // is loop invariant.
    if (SplitCondition) {
      if (SplitCondition->getOperand(0) != PN)
        SplitValue = SplitCondition->getOperand(0);
      else
        SplitValue = SplitCondition->getOperand(1);
      SCEVHandle ValueSCEV = SE->getSCEV(SplitValue);

      // If SplitValue is not invariant then SplitCondition is not appropriate.
      if (!ValueSCEV->isLoopInvariant(L))
        SplitCondition = NULL;
    }

    // We are looking for only one split condition.
    if (SplitCondition) {
      IndVar = PN;
      break;
    }
  }
}

/// processOneIterationLoop - Current loop L contains compare instruction
/// that compares induction variable, IndVar, against loop invariant. If
/// entire (i.e. meaningful) loop body is dominated by this compare
/// instruction then loop body is executed only once. In such case eliminate
/// loop structure surrounding this loop body. For example,
///     for (int i = start; i < end; ++i) {
///         if ( i == somevalue) {
///           loop_body
///         }
///     }
/// can be transformed into
///     if (somevalue >= start && somevalue < end) {
///        i = somevalue;
///        loop_body
///     }
bool LoopIndexSplit::processOneIterationLoop(LPPassManager &LPM) {

  BasicBlock *Header = L->getHeader();

  // First of all, check if SplitCondition dominates entire loop body
  // or not.

  // If SplitCondition is not in loop header then this loop is not suitable
  // for this transformation.
  if (SplitCondition->getParent() != Header)
    return false;

  // If one of the Header block's successor is not an exit block then this
  // loop is not a suitable candidate.
  BasicBlock *ExitBlock = NULL;
  for (succ_iterator SI = succ_begin(Header), E = succ_end(Header); SI != E; ++SI) {
    if (L->isLoopExit(*SI)) {
      ExitBlock = *SI;
      break;
    }
  }

  if (!ExitBlock)
    return false;

  // If loop header includes loop variant instruction operands then
  // this loop may not be eliminated.
  if (!safeHeader(Header))
    return false;

  // If Exit block includes loop variant instructions then this
  // loop may not be eliminated.
  if (!safeExitBlock(ExitBlock))
    return false;

  BasicBlock *Latch = L->getLoopLatch();
  BasicBlock *Preheader = L->getLoopPreheader();
  Instruction *Terminator = Header->getTerminator();
  Value *StartValue = IndVar->getIncomingValueForBlock(Preheader);

  // Update CFG.

  // Replace split condition in header.
  // Transform
  //      SplitCondition : icmp eq i32 IndVar, SplitValue
  // into
  //      c1 = icmp uge i32 SplitValue, StartValue
  //      c2 = icmp ult i32 vSplitValue, ExitValue
  //      and i32 c1, c2
  bool SignedPredicate = SplitCondition->isSignedPredicate();
  Instruction *C1 = new ICmpInst(SignedPredicate ?
                                 ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE,
                                 SplitValue, StartValue, "lisplit", Terminator);
  Instruction *C2 = new ICmpInst(SignedPredicate ?
                                 ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT,
                                 SplitValue, ExitValue, "lisplit", Terminator);
  Instruction *NSplitCond = BinaryOperator::create(Instruction::And,
                                                   C1, C2, "lisplit", Terminator);
  SplitCondition->replaceAllUsesWith(NSplitCond);
  SplitCondition->eraseFromParent();

  // As a first step to break this loop, remove Latch to Header edge.
  BasicBlock *LatchSucc = NULL;
  Header->removePredecessor(Latch);
  for (succ_iterator SI = succ_begin(Latch), E = succ_end(Latch);
       SI != E; ++SI) {
    if (Header != *SI)
      LatchSucc = *SI;
  }
  BranchInst *BR = dyn_cast<BranchInst>(Latch->getTerminator());
  BR->setUnconditionalDest(LatchSucc);

  // Now, clear latch block. Remove instructions that are responsible
  // to increment induction variable.
  Instruction *LTerminator = Latch->getTerminator();
  for (BasicBlock::iterator LB = Latch->begin(), LE = Latch->end();
       LB != LE; ) {
    Instruction *I = LB;
    ++LB;
    if (isa<PHINode>(I) || I == LTerminator)
      continue;

    I->replaceAllUsesWith(UndefValue::get(I->getType()));
    I->eraseFromParent();
  }

  LPM.deleteLoopFromQueue(L);
  return true;
}

// If loop header includes loop variant instruction operands then
// this loop can not be eliminated. This is used by processOneIterationLoop().
bool LoopIndexSplit::safeHeader(BasicBlock *Header) {

  Instruction *Terminator = Header->getTerminator();
  for(BasicBlock::iterator BI = Header->begin(), BE = Header->end();
      BI != BE; ++BI) {
    Instruction *I = BI;

    // PHI Nodes are OK.
    if (isa<PHINode>(I))
      continue;

    // SplitCondition itself is OK.
    if (ICmpInst *CI = dyn_cast<ICmpInst>(I)) {
      if (CI == SplitCondition)
        continue;
    }

    // Terminator is also harmless.
    if (I == Terminator)
      continue;

    // Otherwise we have a instruction that may not be safe.
    return false;
  }

  return true;
}

// If Exit block includes loop variant instructions then this
// loop may not be eliminated. This is used by processOneIterationLoop().
bool LoopIndexSplit::safeExitBlock(BasicBlock *ExitBlock) {

  Instruction *ExitCondition = NULL;
  Instruction *IndVarIncrement = NULL;

  for (BasicBlock::iterator BI = ExitBlock->begin(), BE = ExitBlock->end();
       BI != BE; ++BI) {
    Instruction *I = BI;

    // PHI Nodes are OK.
    if (isa<PHINode>(I))
      continue;

    // Check if I is induction variable increment instruction.
    if (BinaryOperator *BOp = dyn_cast<BinaryOperator>(I)) {
      if (BOp->getOpcode() != Instruction::Add)
        return false;

      Value *Op0 = BOp->getOperand(0);
      Value *Op1 = BOp->getOperand(1);
      PHINode *PN = NULL;
      ConstantInt *CI = NULL;

      if ((PN = dyn_cast<PHINode>(Op0))) {
        if ((CI = dyn_cast<ConstantInt>(Op1)))
          IndVarIncrement = I;
      } else
        if ((PN = dyn_cast<PHINode>(Op1))) {
          if ((CI = dyn_cast<ConstantInt>(Op0)))
            IndVarIncrement = I;
      }

      if (IndVarIncrement && PN == IndVar && CI->isOne())
        continue;
    }
    // I is an Exit condition if next instruction is block terminator.
    // Exit condition is OK if it compares loop invariant exit value,
    // which is checked below.
    else if (isa<ICmpInst>(I)) {
      ++BI;
      Instruction *N = BI;
      if (N == ExitBlock->getTerminator()) {
        ExitCondition = I;
        break;
      }
    }

    // Otherwise we have instruction that may not be safe.
    return false;
  }

  // Check if Exit condition is comparing induction variable against
  // loop invariant value. If one operand is induction variable and
  // the other operand is loop invaraint then Exit condition is safe.
  if (ExitCondition) {
    Value *Op0 = ExitCondition->getOperand(0);
    Value *Op1 = ExitCondition->getOperand(1);

    Instruction *Insn0 = dyn_cast<Instruction>(Op0);
    Instruction *Insn1 = dyn_cast<Instruction>(Op1);

    if (Insn0 && Insn0 == IndVarIncrement)
      ExitValue = Op1;
    else if (Insn1 && Insn1 == IndVarIncrement)
      ExitValue = Op0;

    SCEVHandle ValueSCEV = SE->getSCEV(ExitValue);
    if (!ValueSCEV->isLoopInvariant(L))
      return false;
  }

  // We could not find any reason to consider ExitBlock unsafe.
  return true;
}

bool LoopIndexSplit::splitLoop() {
  // FIXME :)
  return false;
}
<|endoftext|>


<commit_before><commit_msg>twsgen cmd, add option [-w|--whatToShow=LIST]<commit_after><|endoftext|>


<commit_before><commit_msg>calculate view & proj mats<commit_after><|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS impress89 (1.113.6); FILE MERGED 2006/03/15 12:15:37 sj 1.113.6.1: #i63158# added patch: save thumbnails to MS format documents<commit_after><|endoftext|>


<commit_before>#include "Timestamp.h"

#include <sys/time.h>
#include <stdio.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#undef __STDC_FORMAT_MACROS

#include <boost/static_assert.hpp>

using namespace muduo;

BOOST_STATIC_ASSERT(sizeof(Timestamp) == sizeof(int64_t));

Timestamp::Timestamp()
  : microSecondsSinceEpoch_(0)
{
}

Timestamp::Timestamp(int64_t microseconds)
  : microSecondsSinceEpoch_(microseconds)
{
}

std::string Timestamp::toString() const
{
  char buf[32] = {0};
  int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond;
  int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond;
  snprintf(buf, sizeof(buf)-1, "%" PRId64 ".%06" PRId64 "", seconds, microseconds);
  return buf;
}

std::string Timestamp::toFormattedString() const
{
  char buf[32] = {0};
  time_t seconds = static_cast<time_t>(microSecondsSinceEpoch_ / kMicroSecondsPerSecond);
  int microseconds = static_cast<int>(microSecondsSinceEpoch_ % kMicroSecondsPerSecond);
  struct tm tm_time;
  gmtime_r(&seconds, &tm_time);

  snprintf(buf, sizeof(buf), "%4d-%02d-%02d %02d:%02d:%02d.%06d",
      tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
      tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec,
      microseconds);
  return buf;
}

Timestamp Timestamp::now()
{
  struct timeval tv;
  gettimeofday(&tv, NULL);
  int64_t seconds = tv.tv_sec;
  return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec);
}

Timestamp Timestamp::invalid()
{
  return Timestamp();
}

<commit_msg>change date format of Timestamp<commit_after>#include "Timestamp.h"

#include <sys/time.h>
#include <stdio.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#undef __STDC_FORMAT_MACROS

#include <boost/static_assert.hpp>

using namespace muduo;

BOOST_STATIC_ASSERT(sizeof(Timestamp) == sizeof(int64_t));

Timestamp::Timestamp()
  : microSecondsSinceEpoch_(0)
{
}

Timestamp::Timestamp(int64_t microseconds)
  : microSecondsSinceEpoch_(microseconds)
{
}

std::string Timestamp::toString() const
{
  char buf[32] = {0};
  int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond;
  int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond;
  snprintf(buf, sizeof(buf)-1, "%" PRId64 ".%06" PRId64 "", seconds, microseconds);
  return buf;
}

std::string Timestamp::toFormattedString() const
{
  char buf[32] = {0};
  time_t seconds = static_cast<time_t>(microSecondsSinceEpoch_ / kMicroSecondsPerSecond);
  int microseconds = static_cast<int>(microSecondsSinceEpoch_ % kMicroSecondsPerSecond);
  struct tm tm_time;
  gmtime_r(&seconds, &tm_time);

  snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d.%06d",
      tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
      tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec,
      microseconds);
  return buf;
}

Timestamp Timestamp::now()
{
  struct timeval tv;
  gettimeofday(&tv, NULL);
  int64_t seconds = tv.tv_sec;
  return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec);
}

Timestamp Timestamp::invalid()
{
  return Timestamp();
}

<|endoftext|>


<commit_before>/*
    Copyright (C) 2011 vlc-phonon AUTHORS

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "libvlc.h"

#include <QtCore/QByteArray>
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QLibrary>
#include <QtCore/QString>

#include <vlc/libvlc.h>

LibVLC *LibVLC::self;

LibVLC::LibVLC() :
    m_vlcInstance(0)
{
}

LibVLC::~LibVLC()
{
    libvlc_release(m_vlcInstance);
    vlcUnload();
    self = 0;
}

bool LibVLC::init(int debugLevel)
{
    Q_ASSERT_X(!self, "LibVLC", "there should be only one LibVLC object");
    LibVLC::self = new LibVLC;

    QString path = self->vlcPath();
    if (!path.isEmpty()) {
        QString pluginsPath = QString("--plugin-path=") + QDir::toNativeSeparators(QFileInfo(self->vlcPath()).dir().path());

#if defined(Q_OS_UNIX)
        pluginsPath.append("/vlc");
#elif defined(Q_OS_WIN)
        pluginsPath.append("\\plugins");
#endif
        QByteArray p = QFile::encodeName(path);
        QByteArray pp = QFile::encodeName(pluginsPath);

        QByteArray log;
        QByteArray logFile;
        QByteArray verboseLevl;
        if (debugLevel > 0) {
            verboseLevl = QString("--verbose=").append(QString::number(debugLevel)).toLatin1();
            log = "--extraintf=logger";
            logFile = "--logfile=";
#ifdef Q_WS_WIN
            QDir logFilePath(QString(qgetenv("APPDATA")).append("/vlc"));
#else
            QDir logFilePath(QDir::homePath().append("/.vlc"));
#endif //Q_WS_WIN
            logFilePath.mkdir("log");
            logFile.append(QFile::encodeName(QDir::toNativeSeparators(logFilePath.path().append("/log/vlc-log-").append(QString::number(qApp->applicationPid())).append(".txt"))));
        }
        // VLC command line options. See vlc --full-help
        const char *vlcArgs[] = {
            p.constData(),
            pp.constData(),
            log.constData(),
            logFile.constData(),
            verboseLevl.constData(),
            "--reset-plugins-cache",
            "--no-media-library",
#ifndef Q_OS_MAC
            "--no-one-instance",
#endif
            "--no-osd",
            "--no-stats",
            "--no-video-title-show",
            "--album-art=0"
        };

        // Create and initialize a libvlc instance (it should be done only once)
        self->m_vlcInstance = libvlc_new(sizeof(vlcArgs) / sizeof(*vlcArgs), vlcArgs);
        if (!self->m_vlcInstance) {
            qCritical() << "libvlc exception:" << libvlc_errmsg();
            return false;
        }
        return true;
    }
    return false;
}

#if defined(Q_OS_UNIX)
bool LibVLC::libGreaterThan(const QString &lhs, const QString &rhs)
{
    const QStringList lhsparts = lhs.split(QLatin1Char('.'));
    const QStringList rhsparts = rhs.split(QLatin1Char('.'));
    Q_ASSERT(lhsparts.count() > 1 && rhsparts.count() > 1);

    for (int i = 1; i < rhsparts.count(); ++i) {
        if (lhsparts.count() <= i) {
            // left hand side is shorter, so it's less than rhs
            return false;
        }

        bool ok = false;
        int b = 0;
        int a = lhsparts.at(i).toInt(&ok);
        if (ok) {
            b = rhsparts.at(i).toInt(&ok);
        }
        if (ok) {
            // both toInt succeeded
            if (a == b) {
                continue;
            }
            return a > b;
        } else {
            // compare as strings;
            if (lhsparts.at(i) == rhsparts.at(i)) {
                continue;
            }
            return lhsparts.at(i) > rhsparts.at(i);
        }
    }

    // they compared strictly equally so far
    // lhs cannot be less than rhs
    return true;
}
#endif

QStringList LibVLC::findAllLibVlcPaths()
{
    QStringList paths;

#ifdef Q_OS_UNIX
    paths = QString::fromLatin1(qgetenv("LD_LIBRARY_PATH"))
            .split(QLatin1Char(':'), QString::SkipEmptyParts);
    paths << QLatin1String(PHONON_LIB_INSTALL_DIR) << QLatin1String("/usr/lib") << QLatin1String("/usr/local/lib");

#if defined(Q_WS_MAC)
    paths
            << QCoreApplication::applicationDirPath()
            << QCoreApplication::applicationDirPath() + QLatin1String("/../Frameworks")
            << QCoreApplication::applicationDirPath() + QLatin1String("/../PlugIns")
            << QCoreApplication::applicationDirPath() + QLatin1String("/lib");
#endif

    QStringList foundVlcs;
    foreach (const QString & path, paths) {
        QDir dir = QDir(path);
        QStringList entryList = dir.entryList(QStringList() << QLatin1String("libvlc.*"), QDir::Files);

        qSort(entryList.begin(), entryList.end(), LibVLC::libGreaterThan);
        foreach(const QString & entry, entryList) {
            if (entry.contains(".debug")) {
                continue;
            }
            foundVlcs << path + QLatin1Char('/') + entry;
        }
    }

    return foundVlcs;
#elif defined(Q_OS_WIN)
    // Current application path has highest priority.
    // Application could be delivered with own copy of qt, phonon, LibVLC, vlc and vlc plugins.
    QString appDirVlc =
            QDir::toNativeSeparators(QCoreApplication::applicationDirPath()
                                     % QLatin1Char('\\')
                                     % QLatin1Literal("libvlc.dll"));
    if (QFile::exists(appDirVlc)) {
        paths << appDirVlc;
    }

    // Read VLC version and installation directory from Windows registry
    QSettings settings(QSettings::SystemScope, "VideoLAN", "VLC");
    QString vlcVersion = settings.value("Version").toString();
    QString vlcInstallDir = settings.value("InstallDir").toString();
    if (vlcVersion.startsWith("1.1") && !vlcInstallDir.isEmpty()) {
        paths << vlcInstallDir + QLatin1Char('\\') + "libvlc.dll";
        return paths;
    } else {
        //If nothing is found in the registry try %PATH%
        QStringList searchPaths = QString::fromLatin1(qgetenv("PATH"))
                                  .split(QLatin1Char(';'), QString::SkipEmptyParts);

        QStringList foundVlcs;
        foreach(const QString & sp, searchPaths) {
            QDir dir = QDir(sp);
            QStringList entryList = dir.entryList(QStringList() << QLatin1String("libvlc.dll"), QDir::Files);
            foreach(const QString & entry, entryList){
                foundVlcs << sp + QLatin1Char('\\') + entry;
            }
        }
        paths << foundVlcs;
        return paths;
    }
#endif
}

QString LibVLC::vlcPath()
{
    static QString path;
    if (!path.isEmpty()) {
        return path;
    }

    m_vlcLibrary = new QLibrary();
    QStringList paths = LibVLC::findAllLibVlcPaths();
    foreach(path, paths) {
        m_vlcLibrary->setFileName(path);

        if (!m_vlcLibrary->resolve("libvlc_exception_init")) { //"libvlc_exception_init" not contained in 1.1+
            return path;
        } else {
            qDebug("Cannot resolve the symbol or load VLC library");
        }
        qWarning() << m_vlcLibrary->errorString();
    }

    vlcUnload();

    return QString();
}

void LibVLC::vlcUnload()
{
    m_vlcLibrary->unload();
    delete m_vlcLibrary;
    m_vlcLibrary = 0;
}

<commit_msg>Fix includes for Windows and while I am at it, also convert all of libvlc to QStringBuilder<commit_after>/*
    Copyright (C) 2011 vlc-phonon AUTHORS

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "libvlc.h"

#include <QtCore/QByteArray>
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QLibrary>
#include <QtCore/QSettings>
#include <QtCore/QString>
#include <QtCore/QStringBuilder>

#include <vlc/libvlc.h>

LibVLC *LibVLC::self;

LibVLC::LibVLC() :
    m_vlcInstance(0)
{
}

LibVLC::~LibVLC()
{
    libvlc_release(m_vlcInstance);
    vlcUnload();
    self = 0;
}

bool LibVLC::init(int debugLevel)
{
    Q_ASSERT_X(!self, "LibVLC", "there should be only one LibVLC object");
    LibVLC::self = new LibVLC;

    QString path = self->vlcPath();
    if (!path.isEmpty()) {
        QString pluginsPath = QLatin1Literal("--plugin-path=") %
                QDir::toNativeSeparators(QFileInfo(self->vlcPath()).dir().path());

#if defined(Q_OS_UNIX)
        pluginsPath.append("/vlc");
#elif defined(Q_OS_WIN)
        pluginsPath.append("\\plugins");
#endif
        QByteArray p = QFile::encodeName(path);
        QByteArray pp = QFile::encodeName(pluginsPath);

        QByteArray log;
        QByteArray logFile;
        QByteArray verboseLevl;
        if (debugLevel > 0) {
            verboseLevl = QString("--verbose=").append(QString::number(debugLevel)).toLatin1();
            log = "--extraintf=logger";
            logFile = "--logfile=";
#ifdef Q_WS_WIN
            QDir logFilePath(QString(qgetenv("APPDATA")).append("/vlc"));
#else
            QDir logFilePath(QDir::homePath().append("/.vlc"));
#endif //Q_WS_WIN
            logFilePath.mkdir("log");
            logFile.append(QFile::encodeName(QDir::toNativeSeparators(logFilePath.path().append("/log/vlc-log-").append(QString::number(qApp->applicationPid())).append(".txt"))));
        }
        // VLC command line options. See vlc --full-help
        const char *vlcArgs[] = {
            p.constData(),
            pp.constData(),
            log.constData(),
            logFile.constData(),
            verboseLevl.constData(),
            "--reset-plugins-cache",
            "--no-media-library",
#ifndef Q_OS_MAC
            "--no-one-instance",
#endif
            "--no-osd",
            "--no-stats",
            "--no-video-title-show",
            "--album-art=0"
        };

        // Create and initialize a libvlc instance (it should be done only once)
        self->m_vlcInstance = libvlc_new(sizeof(vlcArgs) / sizeof(*vlcArgs), vlcArgs);
        if (!self->m_vlcInstance) {
            qCritical() << "libvlc exception:" << libvlc_errmsg();
            return false;
        }
        return true;
    }
    return false;
}

#if defined(Q_OS_UNIX)
bool LibVLC::libGreaterThan(const QString &lhs, const QString &rhs)
{
    const QStringList lhsparts = lhs.split(QLatin1Char('.'));
    const QStringList rhsparts = rhs.split(QLatin1Char('.'));
    Q_ASSERT(lhsparts.count() > 1 && rhsparts.count() > 1);

    for (int i = 1; i < rhsparts.count(); ++i) {
        if (lhsparts.count() <= i) {
            // left hand side is shorter, so it's less than rhs
            return false;
        }

        bool ok = false;
        int b = 0;
        int a = lhsparts.at(i).toInt(&ok);
        if (ok) {
            b = rhsparts.at(i).toInt(&ok);
        }
        if (ok) {
            // both toInt succeeded
            if (a == b) {
                continue;
            }
            return a > b;
        } else {
            // compare as strings;
            if (lhsparts.at(i) == rhsparts.at(i)) {
                continue;
            }
            return lhsparts.at(i) > rhsparts.at(i);
        }
    }

    // they compared strictly equally so far
    // lhs cannot be less than rhs
    return true;
}
#endif

QStringList LibVLC::findAllLibVlcPaths()
{
    QStringList paths;

#ifdef Q_OS_UNIX
    paths = QString::fromLatin1(qgetenv("LD_LIBRARY_PATH"))
            .split(QLatin1Char(':'), QString::SkipEmptyParts);
    paths << QLatin1String(PHONON_LIB_INSTALL_DIR) << QLatin1String("/usr/lib") << QLatin1String("/usr/local/lib");

#if defined(Q_WS_MAC)
    paths
            << QCoreApplication::applicationDirPath()
            << QCoreApplication::applicationDirPath() % QLatin1Literal("/../Frameworks")
            << QCoreApplication::applicationDirPath() % QLatin1Literal("/../PlugIns")
            << QCoreApplication::applicationDirPath() % QLatin1Literal("/lib");
#endif

    QStringList foundVlcs;
    foreach (const QString & path, paths) {
        QDir dir = QDir(path);
        QStringList entryList = dir.entryList(QStringList() << QLatin1String("libvlc.*"), QDir::Files);

        qSort(entryList.begin(), entryList.end(), LibVLC::libGreaterThan);
        foreach(const QString & entry, entryList) {
            if (entry.contains(".debug")) {
                continue;
            }
            foundVlcs << path % QLatin1Char('/') % entry;
        }
    }

    return foundVlcs;
#elif defined(Q_OS_WIN)
    // Current application path has highest priority.
    // Application could be delivered with own copy of qt, phonon, LibVLC, vlc and vlc plugins.
    QString appDirVlc =
            QDir::toNativeSeparators(QCoreApplication::applicationDirPath()
                                     % QLatin1Char('\\')
                                     % QLatin1Literal("libvlc.dll"));
    if (QFile::exists(appDirVlc)) {
        paths << appDirVlc;
    }

    // Read VLC version and installation directory from Windows registry
    QSettings settings(QSettings::SystemScope, "VideoLAN", "VLC");
    QString vlcVersion = settings.value("Version").toString();
    QString vlcInstallDir = settings.value("InstallDir").toString();
    if (vlcVersion.startsWith("1.1") && !vlcInstallDir.isEmpty()) {
        paths << vlcInstallDir % QLatin1Char('\\') % QLatin1Literal("libvlc.dll");
        return paths;
    } else {
        //If nothing is found in the registry try %PATH%
        QStringList searchPaths = QString::fromLatin1(qgetenv("PATH"))
                                  .split(QLatin1Char(';'), QString::SkipEmptyParts);

        QStringList foundVlcs;
        foreach(const QString & sp, searchPaths) {
            QDir dir = QDir(sp);
            QStringList entryList = dir.entryList(QStringList() << QLatin1String("libvlc.dll"), QDir::Files);
            foreach(const QString & entry, entryList){
                foundVlcs << sp % QLatin1Char('\\') % entry;
            }
        }
        paths << foundVlcs;
        return paths;
    }
#endif
}

QString LibVLC::vlcPath()
{
    static QString path;
    if (!path.isEmpty()) {
        return path;
    }

    m_vlcLibrary = new QLibrary();
    QStringList paths = LibVLC::findAllLibVlcPaths();
    foreach(path, paths) {
        m_vlcLibrary->setFileName(path);

        if (!m_vlcLibrary->resolve("libvlc_exception_init")) { //"libvlc_exception_init" not contained in 1.1+
            return path;
        } else {
            qDebug("Cannot resolve the symbol or load VLC library");
        }
        qWarning() << m_vlcLibrary->errorString();
    }

    vlcUnload();

    return QString();
}

void LibVLC::vlcUnload()
{
    m_vlcLibrary->unload();
    delete m_vlcLibrary;
    m_vlcLibrary = 0;
}

<|endoftext|>