Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 3 additions & 12 deletions llvm/include/llvm/Analysis/VectorUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "llvm/Analysis/LoopAccessAnalysis.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/VFABIDemangler.h"
#include "llvm/IR/VectorUtils.h"
#include "llvm/Support/CheckedArithmetic.h"

namespace llvm {
Expand Down Expand Up @@ -127,18 +128,8 @@ namespace Intrinsic {
typedef unsigned ID;
}

/// A helper function for converting Scalar types to vector types. If
/// the incoming type is void, we return void. If the EC represents a
/// scalar, we return the scalar type.
inline Type *ToVectorTy(Type *Scalar, ElementCount EC) {
if (Scalar->isVoidTy() || Scalar->isMetadataTy() || EC.isScalar())
return Scalar;
return VectorType::get(Scalar, EC);
}

inline Type *ToVectorTy(Type *Scalar, unsigned VF) {
return ToVectorTy(Scalar, ElementCount::getFixed(VF));
}
/// Returns true if `Ty` can be widened by the loop vectorizer.
bool canWidenType(Type *Ty);

/// Identify if the intrinsic is trivially vectorizable.
/// This method returns true if the intrinsic's argument types are all scalars
Expand Down
53 changes: 53 additions & 0 deletions llvm/include/llvm/IR/VectorUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//===----------- VectorUtils.h - Vector type utility functions -*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/DerivedTypes.h"

namespace llvm {

/// A helper function for converting Scalar types to vector types. If
/// the incoming type is void, we return void. If the EC represents a
/// scalar, we return the scalar type.
inline Type *ToVectorTy(Type *Scalar, ElementCount EC) {
if (Scalar->isVoidTy() || Scalar->isMetadataTy() || EC.isScalar())
return Scalar;
return VectorType::get(Scalar, EC);
}

inline Type *ToVectorTy(Type *Scalar, unsigned VF) {
return ToVectorTy(Scalar, ElementCount::getFixed(VF));
}

/// A helper for converting to wider (vector) types. For scalar types, this is
/// equivalent to calling `ToVectorTy`. For struct types, this returns a new
/// struct where each element type has been widened to a vector type. Note: Only
/// unpacked literal struct types are supported.
Type *ToWideTy(Type *Ty, ElementCount EC);

/// A helper for converting wide types to narrow (non-vector) types. For vector
/// types, this is equivalent to calling .getScalarType(). For struct types,
/// this returns a new struct where each element type has been converted to a
/// scalar type. Note: Only unpacked literal struct types are supported.
Type *ToNarrowTy(Type *Ty);

/// Returns the types contained in `Ty`. For struct types, it returns the
/// elements, all other types are returned directly.
SmallVector<Type *, 2> getContainedTypes(Type *Ty);

/// Returns true if `Ty` is a vector type or a struct of vector types where all
/// vector types share the same VF.
bool isWideTy(Type *Ty);

/// Returns the vectorization factor for a widened type.
inline ElementCount getWideTypeVF(Type *Ty) {
assert(isWideTy(Ty) && "expected widened type!");
return cast<VectorType>(getContainedTypes(Ty).front())->getElementCount();
}

} // namespace llvm
14 changes: 14 additions & 0 deletions llvm/lib/Analysis/VectorUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,20 @@ static cl::opt<unsigned> MaxInterleaveGroupFactor(
cl::desc("Maximum factor for an interleaved access group (default = 8)"),
cl::init(8));

/// Returns true if `Ty` can be widened by the loop vectorizer.
bool llvm::canWidenType(Type *Ty) {
Type *ElTy = Ty;
// For now, only allow widening non-packed literal structs where all
// element types are the same. This simplifies the cost model and
// conversion between scalar and wide types.
if (auto *StructTy = dyn_cast<StructType>(Ty);
StructTy && !StructTy->isPacked() && StructTy->isLiteral() &&
StructTy->containsHomogeneousTypes()) {
ElTy = StructTy->elements().front();
}
return VectorType::isValidElementType(ElTy);
}

/// Return true if all of the intrinsic's arguments and return type are scalars
/// for the scalar form of the intrinsic, and vectors for the vector form of the
/// intrinsic (except operands that are marked as always being scalar by
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/IR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ add_llvm_component_library(LLVMCore
Value.cpp
ValueSymbolTable.cpp
VectorBuilder.cpp
VectorUtils.cpp
Verifier.cpp
VFABIDemangler.cpp
RuntimeLibcalls.cpp
Expand Down
18 changes: 11 additions & 7 deletions llvm/lib/IR/VFABIDemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/VectorUtils.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <limits>
Expand Down Expand Up @@ -346,12 +347,15 @@ getScalableECFromSignature(const FunctionType *Signature, const VFISAKind ISA,
// Also check the return type if not void.
Type *RetTy = Signature->getReturnType();
if (!RetTy->isVoidTy()) {
std::optional<ElementCount> ReturnEC = getElementCountForTy(ISA, RetTy);
// If we have an unknown scalar element type we can't find a reasonable VF.
if (!ReturnEC)
return std::nullopt;
if (ElementCount::isKnownLT(*ReturnEC, MinEC))
MinEC = *ReturnEC;
for (Type *RetTy : getContainedTypes(RetTy)) {
std::optional<ElementCount> ReturnEC = getElementCountForTy(ISA, RetTy);
// If we have an unknown scalar element type we can't find a reasonable
// VF.
if (!ReturnEC)
return std::nullopt;
if (ElementCount::isKnownLT(*ReturnEC, MinEC))
MinEC = *ReturnEC;
}
}

// The SVE Vector function call ABI bases the VF on the widest element types
Expand Down Expand Up @@ -566,7 +570,7 @@ FunctionType *VFABI::createFunctionType(const VFInfo &Info,

auto *RetTy = ScalarFTy->getReturnType();
if (!RetTy->isVoidTy())
RetTy = VectorType::get(RetTy, VF);
RetTy = ToWideTy(RetTy, VF);
return FunctionType::get(RetTy, VecTypes, false);
}

Expand Down
69 changes: 69 additions & 0 deletions llvm/lib/IR/VectorUtils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//===----------- VectorUtils.cpp - Vector type utility functions ----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/IR/VectorUtils.h"
#include "llvm/ADT/SmallVectorExtras.h"

using namespace llvm;

/// A helper for converting to wider (vector) types. For scalar types, this is
/// equivalent to calling `ToVectorTy`. For struct types, this returns a new
/// struct where each element type has been widened to a vector type. Note: Only
/// unpacked literal struct types are supported.
Type *llvm::ToWideTy(Type *Ty, ElementCount EC) {
if (EC.isScalar())
return Ty;
auto *StructTy = dyn_cast<StructType>(Ty);
if (!StructTy)
return ToVectorTy(Ty, EC);
assert(StructTy->isLiteral() && !StructTy->isPacked() &&
"expected unpacked struct literal");
return StructType::get(
Ty->getContext(),
map_to_vector(StructTy->elements(), [&](Type *ElTy) -> Type * {
return VectorType::get(ElTy, EC);
}));
}

/// A helper for converting wide types to narrow (non-vector) types. For vector
/// types, this is equivalent to calling .getScalarType(). For struct types,
/// this returns a new struct where each element type has been converted to a
/// scalar type. Note: Only unpacked literal struct types are supported.
Type *llvm::ToNarrowTy(Type *Ty) {
auto *StructTy = dyn_cast<StructType>(Ty);
if (!StructTy)
return Ty->getScalarType();
assert(StructTy->isLiteral() && !StructTy->isPacked() &&
"expected unpacked struct literal");
return StructType::get(
Ty->getContext(),
map_to_vector(StructTy->elements(), [](Type *ElTy) -> Type * {
return ElTy->getScalarType();
}));
}

/// Returns the types contained in `Ty`. For struct types, it returns the
/// elements, all other types are returned directly.
SmallVector<Type *, 2> llvm::getContainedTypes(Type *Ty) {
auto *StructTy = dyn_cast<StructType>(Ty);
if (StructTy)
return to_vector<2>(StructTy->elements());
return {Ty};
}

/// Returns true if `Ty` is a vector type or a struct of vector types where all
/// vector types share the same VF.
bool llvm::isWideTy(Type *Ty) {
auto ContainedTys = getContainedTypes(Ty);
if (ContainedTys.empty() || !ContainedTys.front()->isVectorTy())
return false;
ElementCount VF = cast<VectorType>(ContainedTys.front())->getElementCount();
return all_of(ContainedTys, [&](Type *Ty) {
return Ty->isVectorTy() && cast<VectorType>(Ty)->getElementCount() == VF;
});
}
19 changes: 17 additions & 2 deletions llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -946,11 +946,26 @@ bool LoopVectorizationLegality::canVectorizeInstrs() {
if (CI && !VFDatabase::getMappings(*CI).empty())
VecCallVariantsFound = true;

// TODO: Tidy up these checks.
auto canWidenInst = [](Instruction &I) {
Type *InstTy = I.getType();
if (isa<CallInst>(I) && isa<StructType>(InstTy) &&
canWidenType(InstTy)) {
// We can only widen struct calls where the users are extractvalues.
for (auto &U : I.uses()) {
if (!isa<ExtractValueInst>(U.getUser()))
return false;
}
return true;
}
return VectorType::isValidElementType(InstTy) || InstTy->isVoidTy();
};

// Check that the instruction return type is vectorizable.
// We can't vectorize casts from vector type to scalar type.
// Also, we can't vectorize extractelement instructions.
if ((!VectorType::isValidElementType(I.getType()) &&
!I.getType()->isVoidTy()) ||
// TODO: Tidy up these checks.
if (!canWidenInst(I) ||
(isa<CastInst>(I) &&
!VectorType::isValidElementType(I.getOperand(0)->getType())) ||
isa<ExtractElementInst>(I)) {
Expand Down
12 changes: 6 additions & 6 deletions llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ class VPBuilder {

VPInstruction *createOverflowingOp(unsigned Opcode,
std::initializer_list<VPValue *> Operands,
VPRecipeWithIRFlags::WrapFlagsTy WrapFlags,
VPRecipeIRFlags::WrapFlagsTy WrapFlags,
DebugLoc DL = {}, const Twine &Name = "") {
return tryInsertInstruction(
new VPInstruction(Opcode, Operands, WrapFlags, DL, Name));
Expand All @@ -187,9 +187,9 @@ class VPBuilder {
VPValue *createOr(VPValue *LHS, VPValue *RHS, DebugLoc DL = {},
const Twine &Name = "") {

return tryInsertInstruction(new VPInstruction(
Instruction::BinaryOps::Or, {LHS, RHS},
VPRecipeWithIRFlags::DisjointFlagsTy(false), DL, Name));
return tryInsertInstruction(
new VPInstruction(Instruction::BinaryOps::Or, {LHS, RHS},
VPRecipeIRFlags::DisjointFlagsTy(false), DL, Name));
}

VPValue *createLogicalAnd(VPValue *LHS, VPValue *RHS, DebugLoc DL = {},
Expand Down Expand Up @@ -223,12 +223,12 @@ class VPBuilder {
VPInstruction *createPtrAdd(VPValue *Ptr, VPValue *Offset, DebugLoc DL = {},
const Twine &Name = "") {
return tryInsertInstruction(new VPInstruction(
Ptr, Offset, VPRecipeWithIRFlags::GEPFlagsTy(false), DL, Name));
Ptr, Offset, VPRecipeIRFlags::GEPFlagsTy(false), DL, Name));
}
VPValue *createInBoundsPtrAdd(VPValue *Ptr, VPValue *Offset, DebugLoc DL = {},
const Twine &Name = "") {
return tryInsertInstruction(new VPInstruction(
Ptr, Offset, VPRecipeWithIRFlags::GEPFlagsTy(true), DL, Name));
Ptr, Offset, VPRecipeIRFlags::GEPFlagsTy(true), DL, Name));
}

VPDerivedIVRecipe *createDerivedIV(InductionDescriptor::InductionKind Kind,
Expand Down
Loading