Skip to content

Commit

Permalink
[Clang][SVE] Parse builtin type string for scalable vectors
Browse files Browse the repository at this point in the history
This patch adds 'q' to mean 'scalable vector' in the builtin
type string, and for SVE will return the matching builtin
type as defined in the C/C++ language extensions for SVE.

This patch also adds some scaffolding to generate the arm_sve.h
header file, and some builtin definitions (+CodeGen) to be able
to implement some simple masked load intrinsics that use the
ACLE types, such as:

 svint8_t test_svld1_s8(svbool_t pg, const int8_t *base) {
   return svld1_s8(pg, base);
 }

Reviewers: efriedma, rjmccall, rovka, rsandifo-arm, rengolin

Reviewed By: efriedma

Tags: #clang

Differential Revision: https://reviews.llvm.org/D75298
  • Loading branch information
sdesmalen-arm committed Mar 15, 2020
1 parent 8105935 commit 5087ace
Show file tree
Hide file tree
Showing 16 changed files with 405 additions and 28 deletions.
6 changes: 6 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Expand Up @@ -1275,6 +1275,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// Returns a vla type where known sizes are replaced with [*].
QualType getVariableArrayDecayedType(QualType Ty) const;

/// Return the unique reference to a scalable vector type of the specified
/// element type and scalable number of elements.
///
/// \pre \p EltTy must be a built-in type.
QualType getScalableVectorType(QualType EltTy, unsigned NumElts) const;

/// Return the unique reference to a vector type of the specified
/// element type and size.
///
Expand Down
28 changes: 14 additions & 14 deletions clang/include/clang/Basic/AArch64SVEACLETypes.def
Expand Up @@ -38,32 +38,32 @@
//===----------------------------------------------------------------------===//

#ifndef SVE_VECTOR_TYPE
#define SVE_VECTOR_TYPE(Name, Id, SingletonId, ElKind, ElBits, IsSigned, IsFP)\
#define SVE_VECTOR_TYPE(Name, Id, SingletonId, NumEls, ElBits, IsSigned, IsFP) \
SVE_TYPE(Name, Id, SingletonId)
#endif

#ifndef SVE_PREDICATE_TYPE
#define SVE_PREDICATE_TYPE(Name, Id, SingletonId, ElKind)\
#define SVE_PREDICATE_TYPE(Name, Id, SingletonId, NumEls)\
SVE_TYPE(Name, Id, SingletonId)
#endif

//===- Vector point types -----------------------------------------------===//

SVE_VECTOR_TYPE("__SVInt8_t", SveInt8, SveInt8Ty, SveElSInt8, 8, true, false)
SVE_VECTOR_TYPE("__SVInt16_t", SveInt16, SveInt16Ty, SveElSInt16, 16, true, false)
SVE_VECTOR_TYPE("__SVInt32_t", SveInt32, SveInt32Ty, SveElSInt32, 32, true, false)
SVE_VECTOR_TYPE("__SVInt64_t", SveInt64, SveInt64Ty, SveElSInt64, 64, true, false)
SVE_VECTOR_TYPE("__SVInt8_t", SveInt8, SveInt8Ty, 16, 8, true, false)
SVE_VECTOR_TYPE("__SVInt16_t", SveInt16, SveInt16Ty, 8, 16, true, false)
SVE_VECTOR_TYPE("__SVInt32_t", SveInt32, SveInt32Ty, 4, 32, true, false)
SVE_VECTOR_TYPE("__SVInt64_t", SveInt64, SveInt64Ty, 2, 64, true, false)

SVE_VECTOR_TYPE("__SVUint8_t", SveUint8, SveUint8Ty, SveElUInt8, 8, false, false)
SVE_VECTOR_TYPE("__SVUint16_t", SveUint16, SveUint16Ty, SveElUInt16, 16, false, false)
SVE_VECTOR_TYPE("__SVUint32_t", SveUint32, SveUint32Ty, SveElUInt32, 32, false, false)
SVE_VECTOR_TYPE("__SVUint64_t", SveUint64, SveUint64Ty, SveElUInt64, 64, false, false)
SVE_VECTOR_TYPE("__SVUint8_t", SveUint8, SveUint8Ty, 16, 8, false, false)
SVE_VECTOR_TYPE("__SVUint16_t", SveUint16, SveUint16Ty, 8, 16, false, false)
SVE_VECTOR_TYPE("__SVUint32_t", SveUint32, SveUint32Ty, 4, 32, false, false)
SVE_VECTOR_TYPE("__SVUint64_t", SveUint64, SveUint64Ty, 2, 64, false, false)

SVE_VECTOR_TYPE("__SVFloat16_t", SveFloat16, SveFloat16Ty, SveElHalf, 16, true, true)
SVE_VECTOR_TYPE("__SVFloat32_t", SveFloat32, SveFloat32Ty, SveElFloat, 32, true, true)
SVE_VECTOR_TYPE("__SVFloat64_t", SveFloat64, SveFloat64Ty, SveElDouble, 64, true, true)
SVE_VECTOR_TYPE("__SVFloat16_t", SveFloat16, SveFloat16Ty, 8, 16, true, true)
SVE_VECTOR_TYPE("__SVFloat32_t", SveFloat32, SveFloat32Ty, 4, 32, true, true)
SVE_VECTOR_TYPE("__SVFloat64_t", SveFloat64, SveFloat64Ty, 2, 64, true, true)

SVE_PREDICATE_TYPE("__SVBool_t", SveBool, SveBoolTy, SveElBool)
SVE_PREDICATE_TYPE("__SVBool_t", SveBool, SveBoolTy, 16)

#undef SVE_VECTOR_TYPE
#undef SVE_PREDICATE_TYPE
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/Builtins.def
Expand Up @@ -36,6 +36,7 @@
// a -> __builtin_va_list
// A -> "reference" to __builtin_va_list
// V -> Vector, followed by the number of elements and the base type.
// q -> Scalable vector, followed by the number of elements and the base type.
// E -> ext_vector, followed by the number of elements and the base type.
// X -> _Complex, followed by the base type.
// Y -> ptrdiff_t
Expand Down
13 changes: 13 additions & 0 deletions clang/include/clang/Basic/BuiltinsAArch64.def
Expand Up @@ -99,6 +99,19 @@ BUILTIN(__builtin_arm_tcommit, "v", "n")
BUILTIN(__builtin_arm_tcancel, "vWUIi", "n")
BUILTIN(__builtin_arm_ttest, "WUi", "nc")

// SVE
BUILTIN(__builtin_sve_svld1_s16, "q8sq16bSsC*", "n")
BUILTIN(__builtin_sve_svld1_s32, "q4iq16bSiC*", "n")
BUILTIN(__builtin_sve_svld1_s64, "q2Wiq16bSWiC*", "n")
BUILTIN(__builtin_sve_svld1_s8, "q16Scq16bScC*", "n")
BUILTIN(__builtin_sve_svld1_u16, "q8Usq16bUsC*", "n")
BUILTIN(__builtin_sve_svld1_u32, "q4Uiq16bUiC*", "n")
BUILTIN(__builtin_sve_svld1_u64, "q2UWiq16bUWiC*", "n")
BUILTIN(__builtin_sve_svld1_u8, "q16Ucq16bUcC*", "n")
BUILTIN(__builtin_sve_svld1_f64, "q2dq16bdC*", "n")
BUILTIN(__builtin_sve_svld1_f32, "q4fq16bfC*", "n")
BUILTIN(__builtin_sve_svld1_f16, "q8hq16bhC*", "n")

TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
Expand Down
14 changes: 14 additions & 0 deletions clang/include/clang/Basic/arm_sve.td
@@ -0,0 +1,14 @@
//===--- arm_sve.td - ARM SVE compiler interface ------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file defines the TableGen definitions from which the ARM SVE header
// file will be generated. See:
//
// https://developer.arm.com/architectures/system-architectures/software-standards/acle
//
//===----------------------------------------------------------------------===//
55 changes: 45 additions & 10 deletions clang/lib/AST/ASTContext.cpp
Expand Up @@ -2100,16 +2100,16 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
// Because the length is only known at runtime, we use a dummy value
// of 0 for the static length. The alignment values are those defined
// by the Procedure Call Standard for the Arm Architecture.
#define SVE_VECTOR_TYPE(Name, Id, SingletonId, ElKind, ElBits, IsSigned, IsFP)\
case BuiltinType::Id: \
Width = 0; \
Align = 128; \
break;
#define SVE_PREDICATE_TYPE(Name, Id, SingletonId, ElKind) \
case BuiltinType::Id: \
Width = 0; \
Align = 16; \
break;
#define SVE_VECTOR_TYPE(Name, Id, SingletonId, NumEls, ElBits, IsSigned, IsFP) \
case BuiltinType::Id: \
Width = 0; \
Align = 128; \
break;
#define SVE_PREDICATE_TYPE(Name, Id, SingletonId, NumEls) \
case BuiltinType::Id: \
Width = 0; \
Align = 16; \
break;
#include "clang/Basic/AArch64SVEACLETypes.def"
}
break;
Expand Down Expand Up @@ -3584,6 +3584,28 @@ QualType ASTContext::getIncompleteArrayType(QualType elementType,
return QualType(newType, 0);
}

/// getScalableVectorType - Return the unique reference to a scalable vector
/// type of the specified element type and size. VectorType must be a built-in
/// type.
QualType ASTContext::getScalableVectorType(QualType EltTy,
unsigned NumElts) const {
if (Target->hasAArch64SVETypes()) {
uint64_t EltTySize = getTypeSize(EltTy);
#define SVE_VECTOR_TYPE(Name, Id, SingletonId, NumEls, ElBits, IsSigned, IsFP) \
if (!EltTy->isBooleanType() && \
((EltTy->hasIntegerRepresentation() && \
EltTy->hasSignedIntegerRepresentation() == IsSigned) || \
(EltTy->hasFloatingRepresentation() && IsFP)) && \
EltTySize == ElBits && NumElts == NumEls) \
return SingletonId;
#define SVE_PREDICATE_TYPE(Name, Id, SingletonId, NumEls) \
if (EltTy->isBooleanType() && NumElts == NumEls) \
return SingletonId;
#include "clang/Basic/AArch64SVEACLETypes.def"
}
return QualType();
}

/// getVectorType - Return the unique reference to a vector type of
/// the specified element type and size. VectorType must be a built-in type.
QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts,
Expand Down Expand Up @@ -9699,6 +9721,19 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
else
Type = Context.getLValueReferenceType(Type);
break;
case 'q': {
char *End;
unsigned NumElements = strtoul(Str, &End, 10);
assert(End != Str && "Missing vector size");
Str = End;

QualType ElementType = DecodeTypeFromStr(Str, Context, Error,
RequiresICE, false);
assert(!RequiresICE && "Can't require vector ICE");

Type = Context.getScalableVectorType(ElementType, NumElements);
break;
}
case 'V': {
char *End;
unsigned NumElements = strtoul(Str, &End, 10);
Expand Down
73 changes: 73 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Expand Up @@ -7384,6 +7384,58 @@ Value *CodeGenFunction::vectorWrapScalar16(Value *Op) {
return Op;
}

// Reinterpret the input predicate so that it can be used to correctly isolate
// the elements of the specified datatype.
Value *CodeGenFunction::EmitSVEPredicateCast(Value *Pred,
llvm::VectorType *VTy) {
llvm::VectorType *RTy = llvm::VectorType::get(
IntegerType::get(getLLVMContext(), 1), VTy->getElementCount());
if (Pred->getType() == RTy)
return Pred;

unsigned IntID;
llvm::Type *IntrinsicTy;
switch (VTy->getNumElements()) {
default:
llvm_unreachable("unsupported element count!");
case 2:
case 4:
case 8:
IntID = Intrinsic::aarch64_sve_convert_from_svbool;
IntrinsicTy = RTy;
break;
case 16:
IntID = Intrinsic::aarch64_sve_convert_to_svbool;
IntrinsicTy = Pred->getType();
break;
}

Function *F = CGM.getIntrinsic(IntID, IntrinsicTy);
Value *C = Builder.CreateCall(F, Pred);
assert(C->getType() == RTy && "Unexpected return type!");
return C;
}

Value *CodeGenFunction::EmitSVEMaskedLoad(llvm::Type *ReturnTy,
SmallVectorImpl<Value *> &Ops) {
llvm::PointerType *PTy = cast<llvm::PointerType>(Ops[1]->getType());
llvm::Type *MemEltTy = PTy->getPointerElementType();

// The vector type that is returned may be different from the
// eventual type loaded from memory.
auto VectorTy = cast<llvm::VectorType>(ReturnTy);
auto MemoryTy =
llvm::VectorType::get(MemEltTy, VectorTy->getVectorElementCount());

Value *Offset = Builder.getInt32(0);
Value *Predicate = EmitSVEPredicateCast(Ops[0], MemoryTy);
Value *BasePtr = Builder.CreateBitCast(Ops[1], MemoryTy->getPointerTo());
BasePtr = Builder.CreateGEP(MemoryTy, BasePtr, Offset);

Value *Splat0 = Constant::getNullValue(MemoryTy);
return Builder.CreateMaskedLoad(BasePtr, Align(1), Predicate, Splat0);
}

Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
const CallExpr *E,
llvm::Triple::ArchType Arch) {
Expand Down Expand Up @@ -7420,6 +7472,27 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall(F, llvm::ConstantInt::get(Int32Ty, HintID));
}

switch (BuiltinID) {
case AArch64::BI__builtin_sve_svld1_u8:
case AArch64::BI__builtin_sve_svld1_u16:
case AArch64::BI__builtin_sve_svld1_u32:
case AArch64::BI__builtin_sve_svld1_u64:
case AArch64::BI__builtin_sve_svld1_s8:
case AArch64::BI__builtin_sve_svld1_s16:
case AArch64::BI__builtin_sve_svld1_s32:
case AArch64::BI__builtin_sve_svld1_s64:
case AArch64::BI__builtin_sve_svld1_f16:
case AArch64::BI__builtin_sve_svld1_f32:
case AArch64::BI__builtin_sve_svld1_f64: {
llvm::SmallVector<Value *, 4> Ops = {EmitScalarExpr(E->getArg(0)),
EmitScalarExpr(E->getArg(1))};
llvm::Type *Ty = ConvertType(E->getType());
return EmitSVEMaskedLoad(Ty, Ops);
}
default:
break;
}

if (BuiltinID == AArch64::BI__builtin_arm_prefetch) {
Value *Address = EmitScalarExpr(E->getArg(0));
Value *RW = EmitScalarExpr(E->getArg(1));
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Expand Up @@ -495,13 +495,15 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
// Scan function arguments for vector width.
for (llvm::Argument &A : CurFn->args())
if (auto *VT = dyn_cast<llvm::VectorType>(A.getType()))
LargestVectorWidth = std::max((uint64_t)LargestVectorWidth,
VT->getPrimitiveSizeInBits().getFixedSize());
LargestVectorWidth =
std::max((uint64_t)LargestVectorWidth,
VT->getPrimitiveSizeInBits().getKnownMinSize());

// Update vector width based on return type.
if (auto *VT = dyn_cast<llvm::VectorType>(CurFn->getReturnType()))
LargestVectorWidth = std::max((uint64_t)LargestVectorWidth,
VT->getPrimitiveSizeInBits().getFixedSize());
LargestVectorWidth =
std::max((uint64_t)LargestVectorWidth,
VT->getPrimitiveSizeInBits().getKnownMinSize());

// Add the required-vector-width attribute. This contains the max width from:
// 1. min-vector-width attribute used in the source program.
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.h
Expand Up @@ -3900,6 +3900,11 @@ class CodeGenFunction : public CodeGenTypeCache {
llvm::Value *EmitNeonRShiftImm(llvm::Value *Vec, llvm::Value *Amt,
llvm::Type *Ty, bool usgn, const char *name);
llvm::Value *vectorWrapScalar16(llvm::Value *Op);

llvm::Value *EmitSVEPredicateCast(llvm::Value *Pred, llvm::VectorType *VTy);
llvm::Value *EmitSVEMaskedLoad(llvm::Type *ReturnTy,
SmallVectorImpl<llvm::Value *> &Ops);

llvm::Value *EmitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E,
llvm::Triple::ArchType Arch);
llvm::Value *EmitBPFBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Headers/CMakeLists.txt
Expand Up @@ -184,6 +184,8 @@ endforeach( f )
clang_generate_header(-gen-arm-neon arm_neon.td arm_neon.h)
# Generate arm_fp16.h
clang_generate_header(-gen-arm-fp16 arm_fp16.td arm_fp16.h)
# Generate arm_sve.h
clang_generate_header(-gen-arm-sve-header arm_sve.td arm_sve.h)
# Generate arm_mve.h
clang_generate_header(-gen-arm-mve-header arm_mve.td arm_mve.h)
# Generate arm_cde.h
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Headers/module.modulemap
Expand Up @@ -27,6 +27,12 @@ module _Builtin_intrinsics [system] [extern_c] {
header "arm_fp16.h"
export *
}

explicit module sve {
requires sve
header "arm_sve.h"
export *
}
}

explicit module intel {
Expand Down

0 comments on commit 5087ace

Please sign in to comment.