Skip to content

Commit

Permalink
[SveEmitter] Add IsOverloadNone flag and builtins for svpfalse and sv…
Browse files Browse the repository at this point in the history
…cnt[bhwd]_pat

Add the IsOverloadNone flag to tell CGBuiltin that it does not have
an overloaded type. This is used for e.g. svpfalse which does
not take any arguments and always returns a svbool_t.

This patch also adds builtins for svcntb_pat, svcnth_pat, svcntw_pat
and svcntd_pat, as those don't require custom codegen.

Reviewers: SjoerdMeijer, efriedma, rovka

Reviewed By: efriedma

Tags: #clang

Differential Revision: https://reviews.llvm.org/D77596
  • Loading branch information
sdesmalen-arm committed Apr 22, 2020
1 parent 1b6b05a commit 662cbaf
Show file tree
Hide file tree
Showing 10 changed files with 665 additions and 10 deletions.
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/TargetBuiltins.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ namespace clang {
bool isStructStore() const { return Flags & IsStructStore; }
bool isZExtReturn() const { return Flags & IsZExtReturn; }
bool isByteIndexed() const { return Flags & IsByteIndexed; }
bool isOverloadNone() const { return Flags & IsOverloadNone; }
bool isOverloadDefault() const { return !(Flags & OverloadKindMask); }

uint64_t getBits() const { return Flags; }
bool isFlagSet(uint64_t Flag) const { return Flags & Flag; }
Expand Down
20 changes: 20 additions & 0 deletions clang/include/clang/Basic/arm_sve.td
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@
// o: 4x width elements, 1/4 element count
//
// i: constant uint64_t
// k: int32_t
// l: int64_t
// m: uint32_t
// n: uint64_t
//
// I: Predicate Pattern (sv_pattern)

Expand Down Expand Up @@ -163,6 +167,8 @@ def IsScatterStore : FlagType<0x00010000>;
def IsStructLoad : FlagType<0x00020000>;
def IsStructStore : FlagType<0x00040000>;
def IsZExtReturn : FlagType<0x00080000>; // Return value is sign-extend by default
def IsOverloadNone : FlagType<0x00100000>; // Intrinsic does not take any overloaded types.
def OverloadKindMask : FlagType<0x00E00000>; // When the masked values are all '0', the default type is used as overload type.
// : :
// : :
def IsByteIndexed : FlagType<0x02000000>;
Expand Down Expand Up @@ -542,6 +548,20 @@ def SVCMLA_M : SInst<"svcmla[_{d}]", "dPdddi", "hfd", MergeOp1, "aarch64_sve_fc
def SVQDECH_S : SInst<"svqdech_pat[_{d}]", "ddIi", "s", MergeNone, "aarch64_sve_sqdech", [], [ImmCheck<2, ImmCheck1_16>]>;
def SVQDECH_U : SInst<"svqdech_pat[_{d}]", "ddIi", "Us", MergeNone, "aarch64_sve_uqdech", [], [ImmCheck<2, ImmCheck1_16>]>;


////////////////////////////////////////////////////////////////////////////////
// Predicate creation

def SVPFALSE : SInst<"svpfalse[_b]", "P", "", MergeNone, "", [IsOverloadNone]>;


////////////////////////////////////////////////////////////////////////////////
// Counting elements

def SVCNTB_PAT : SInst<"svcntb_pat", "nI", "", MergeNone, "aarch64_sve_cntb", [IsOverloadNone]>;
def SVCNTH_PAT : SInst<"svcnth_pat", "nI", "", MergeNone, "aarch64_sve_cnth", [IsOverloadNone]>;
def SVCNTW_PAT : SInst<"svcntw_pat", "nI", "", MergeNone, "aarch64_sve_cntw", [IsOverloadNone]>;
def SVCNTD_PAT : SInst<"svcntd_pat", "nI", "", MergeNone, "aarch64_sve_cntd", [IsOverloadNone]>;
////////////////////////////////////////////////////////////////////////////////
// Integer arithmetic
def SVDOT_LANE_S : SInst<"svdot_lane[_{d}]", "ddqqi", "il", MergeNone, "aarch64_sve_sdot_lane", [], [ImmCheck<3, ImmCheckLaneIndexDot, 2>]>;
Expand Down
41 changes: 31 additions & 10 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7773,6 +7773,18 @@ static void InsertExplicitUndefOperand(CGBuilderTy &Builder, llvm::Type *Ty,
Ops.insert(Ops.begin(), SplatUndef);
}

SmallVector<llvm::Type *, 2>
CodeGenFunction::getSVEOverloadTypes(SVETypeFlags TypeFlags,
ArrayRef<Value *> Ops) {
if (TypeFlags.isOverloadNone())
return {};

llvm::Type *DefaultType = getSVEType(TypeFlags);

assert(TypeFlags.isOverloadDefault() && "Unexpected value for overloads");
return {DefaultType};
}

Value *CodeGenFunction::EmitAArch64SVEBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
// Find out if any arguments are required to be integer constant expressions.
Expand Down Expand Up @@ -7814,22 +7826,17 @@ Value *CodeGenFunction::EmitAArch64SVEBuiltinExpr(unsigned BuiltinID,
else if (TypeFlags.isScatterStore())
return EmitSVEScatterStore(TypeFlags, Ops, Builtin->LLVMIntrinsic);
else if (Builtin->LLVMIntrinsic != 0) {
llvm::VectorType *OverloadedTy = getSVEType(TypeFlags);

if (TypeFlags.getMergeType() == SVETypeFlags::MergeZeroExp)
InsertExplicitZeroOperand(Builder, Ty, Ops);

if (TypeFlags.getMergeType() == SVETypeFlags::MergeAnyExp)
InsertExplicitUndefOperand(Builder, Ty, Ops);

// Predicates must match the main datatype.
for (unsigned i = 0, e = Ops.size(); i != e; ++i) {
for (unsigned i = 0, e = Ops.size(); i != e; ++i)
if (auto PredTy = dyn_cast<llvm::VectorType>(Ops[i]->getType()))
if (PredTy->getScalarType()->isIntegerTy(1)) {
auto NewPredTy = cast<llvm::VectorType>(OverloadedTy);
Ops[i] = EmitSVEPredicateCast(Ops[i], NewPredTy);
}
}
if (PredTy->getElementType()->isIntegerTy(1))
Ops[i] = EmitSVEPredicateCast(Ops[i], getSVEType(TypeFlags));

// Splat scalar operand to vector (intrinsics with _n infix)
if (TypeFlags.hasSplatOperand()) {
Expand All @@ -7845,9 +7852,23 @@ Value *CodeGenFunction::EmitAArch64SVEBuiltinExpr(unsigned BuiltinID,
Ops[1] = Builder.CreateCall(Sel, {Ops[0], Ops[1], SplatZero});
}

Function *F = CGM.getIntrinsic(Builtin->LLVMIntrinsic, OverloadedTy);
Function *F = CGM.getIntrinsic(Builtin->LLVMIntrinsic,
getSVEOverloadTypes(TypeFlags, Ops));
Value *Call = Builder.CreateCall(F, Ops);
return Call;

// Predicate results must be converted to svbool_t.
if (auto PredTy = dyn_cast<llvm::VectorType>(Call->getType()))
if (PredTy->getScalarType()->isIntegerTy(1))
Call = EmitSVEPredicateCast(Call, cast<llvm::VectorType>(Ty));

return Call;
}

switch (BuiltinID) {
default:
return nullptr;
case SVE::BI__builtin_sve_svpfalse_b:
return ConstantInt::getFalse(Ty);
}

/// Should not happen
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -3908,6 +3908,8 @@ class CodeGenFunction : public CodeGenTypeCache {
/// pointer operand.
llvm::Type *SVEBuiltinMemEltTy(SVETypeFlags TypeFlags);

SmallVector<llvm::Type *, 2> getSVEOverloadTypes(SVETypeFlags TypeFlags,
ArrayRef<llvm::Value *> Ops);
llvm::Type *getEltType(SVETypeFlags TypeFlags);
llvm::VectorType *getSVEType(const SVETypeFlags &TypeFlags);
llvm::Value *EmitSVEDupX(llvm::Value *Scalar);
Expand Down
139 changes: 139 additions & 0 deletions clang/test/CodeGen/aarch64-sve-intrinsics/acle_sve_cntb.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s

#include <arm_sve.h>

uint64_t test_svcntb_pat()
{
// CHECK-LABEL: test_svcntb_pat
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.cntb(i32 0)
// CHECK: ret i64 %[[INTRINSIC]]
return svcntb_pat(SV_POW2);
}

uint64_t test_svcntb_pat_1()
{
// CHECK-LABEL: test_svcntb_pat_1
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.cntb(i32 1)
// CHECK: ret i64 %[[INTRINSIC]]
return svcntb_pat(SV_VL1);
}

uint64_t test_svcntb_pat_2()
{
// CHECK-LABEL: test_svcntb_pat_2
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.cntb(i32 2)
// CHECK: ret i64 %[[INTRINSIC]]
return svcntb_pat(SV_VL2);
}

uint64_t test_svcntb_pat_3()
{
// CHECK-LABEL: test_svcntb_pat_3
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.cntb(i32 3)
// CHECK: ret i64 %[[INTRINSIC]]
return svcntb_pat(SV_VL3);
}

uint64_t test_svcntb_pat_4()
{
// CHECK-LABEL: test_svcntb_pat_4
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.cntb(i32 4)
// CHECK: ret i64 %[[INTRINSIC]]
return svcntb_pat(SV_VL4);
}

uint64_t test_svcntb_pat_5()
{
// CHECK-LABEL: test_svcntb_pat_5
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.cntb(i32 5)
// CHECK: ret i64 %[[INTRINSIC]]
return svcntb_pat(SV_VL5);
}

uint64_t test_svcntb_pat_6()
{
// CHECK-LABEL: test_svcntb_pat_6
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.cntb(i32 6)
// CHECK: ret i64 %[[INTRINSIC]]
return svcntb_pat(SV_VL6);
}

uint64_t test_svcntb_pat_7()
{
// CHECK-LABEL: test_svcntb_pat_7
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.cntb(i32 7)
// CHECK: ret i64 %[[INTRINSIC]]
return svcntb_pat(SV_VL7);
}

uint64_t test_svcntb_pat_8()
{
// CHECK-LABEL: test_svcntb_pat_8
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.cntb(i32 8)
// CHECK: ret i64 %[[INTRINSIC]]
return svcntb_pat(SV_VL8);
}

uint64_t test_svcntb_pat_9()
{
// CHECK-LABEL: test_svcntb_pat_9
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.cntb(i32 9)
// CHECK: ret i64 %[[INTRINSIC]]
return svcntb_pat(SV_VL16);
}

uint64_t test_svcntb_pat_10()
{
// CHECK-LABEL: test_svcntb_pat_10
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.cntb(i32 10)
// CHECK: ret i64 %[[INTRINSIC]]
return svcntb_pat(SV_VL32);
}

uint64_t test_svcntb_pat_11()
{
// CHECK-LABEL: test_svcntb_pat_11
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.cntb(i32 11)
// CHECK: ret i64 %[[INTRINSIC]]
return svcntb_pat(SV_VL64);
}

uint64_t test_svcntb_pat_12()
{
// CHECK-LABEL: test_svcntb_pat_12
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.cntb(i32 12)
// CHECK: ret i64 %[[INTRINSIC]]
return svcntb_pat(SV_VL128);
}

uint64_t test_svcntb_pat_13()
{
// CHECK-LABEL: test_svcntb_pat_13
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.cntb(i32 13)
// CHECK: ret i64 %[[INTRINSIC]]
return svcntb_pat(SV_VL256);
}

uint64_t test_svcntb_pat_14()
{
// CHECK-LABEL: test_svcntb_pat_14
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.cntb(i32 29)
// CHECK: ret i64 %[[INTRINSIC]]
return svcntb_pat(SV_MUL4);
}

uint64_t test_svcntb_pat_15()
{
// CHECK-LABEL: test_svcntb_pat_15
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.cntb(i32 30)
// CHECK: ret i64 %[[INTRINSIC]]
return svcntb_pat(SV_MUL3);
}

uint64_t test_svcntb_pat_16()
{
// CHECK-LABEL: test_svcntb_pat_16
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.cntb(i32 31)
// CHECK: ret i64 %[[INTRINSIC]]
return svcntb_pat(SV_ALL);
}
Loading

0 comments on commit 662cbaf

Please sign in to comment.