[ARM,MVE] Add intrinsics for vector comparisons.

This adds the `vcmp` family of ACLE MVE intrinsics: vector/vector,
vector/scalar, and the predicated forms of both. All are represented
using standard existing IR: vector/scalar comparisons are represented
by making a vector out of the scalar first, and predicated forms are
represented by taking the bitwise AND of the input predicate and the
output of the comparison. Existing LLVM-side tests demonstrate that
ISel will pattern-match all of that back down to single MVE VCMPs.

The idiom of handling a vector/scalar operation by generating IR to
expand the scalar into a second vector is going to be needed for a lot
of MVE intrinsics, so to make that easy, I've provided a helper
function that automatically works out the element count.

The comparison intrinsics are the first ones that have to //return// a
predicate, in the user-facing `mve_pred16_t` format. This means we
have to use the `arm_mve_pred_v2i` low-level intrinsic to convert it
back from the logical `<n x i1>` form used in IR. I've done that
explicitly in the code gen specification for the builtins, because it
happens much more rarely in the ACLE API than passing a Predicate as
input, so it didn't seem worth automating in MveEmitter.

Reviewers: ostannard, MarkMurrayARM, dmgreen

Reviewed By: dmgreen

Subscribers: kristof.beyls, hiraditya, cfe-commits, llvm-commits

Tags: #clang, #llvm

Differential Revision: https://reviews.llvm.org/D70297
This commit is contained in:
Simon Tatham 2019-11-18 10:38:48 +00:00
parent 23a766dcad
commit 4a4dd85e5a
4 changed files with 3220 additions and 0 deletions

View File

@ -72,6 +72,51 @@ def vcvt#half#q_m_f16: Intrinsic<
} // loop over half = "b", "t"
multiclass compare_with_pred<string condname, dag arguments,
dag cmp, string suffix> {
// Make the predicated and unpredicated versions of a single comparison.
def: Intrinsic<Predicate, arguments,
(u16 (IRInt<"pred_v2i", [Predicate]> cmp))>,
NameOverride<"vcmp" # condname # "q" # suffix>;
def: Intrinsic<Predicate, !con(arguments, (args Predicate:$inpred)),
(u16 (IRInt<"pred_v2i", [Predicate]> (and $inpred, cmp)))>,
NameOverride<"vcmp" # condname # "q_m" # suffix>;
}
multiclass compare<string condname, IRBuilder cmpop> {
// Make all four variants of a comparison: the vector/vector and
// vector/scalar forms, each using compare_with_pred to make a
// predicated and unpredicated version.
defm: compare_with_pred<condname, (args Vector:$va, Vector:$vb),
(cmpop $va, $vb), "">;
let pnt = PNT_NType in {
defm: compare_with_pred<condname, (args Vector:$va, unpromoted<Scalar>:$sb),
(cmpop $va, (splat $sb)), "_n">;
}
}
let params = T.Int in {
defm: compare<"eq", icmp_eq>;
defm: compare<"ne", icmp_ne>;
}
let params = T.Signed in {
defm: compare<"gt", icmp_sgt>;
defm: compare<"ge", icmp_sge>;
defm: compare<"lt", icmp_slt>;
defm: compare<"le", icmp_sle>;
}
let params = T.Unsigned in {
defm: compare<"hi", icmp_ugt>;
defm: compare<"cs", icmp_uge>;
}
let params = T.Float in {
defm: compare<"eq", fcmp_eq>;
defm: compare<"ne", fcmp_ne>;
defm: compare<"gt", fcmp_gt>;
defm: compare<"ge", fcmp_ge>;
defm: compare<"lt", fcmp_lt>;
defm: compare<"le", fcmp_le>;
}
multiclass contiguous_load<string mnemonic, PrimitiveType memtype,
list<Type> same_size, list<Type> wider> {
// Intrinsics named with explicit memory and element sizes that match:

View File

@ -86,6 +86,23 @@ def extend: CGHelperFn<"SignOrZeroExtend"> {
}
def zeroinit: IRFunction<"llvm::Constant::getNullValue">;
def undef: IRFunction<"UndefValue::get">;
def icmp_eq: IRBuilder<"CreateICmpEQ">;
def icmp_ne: IRBuilder<"CreateICmpNE">;
def icmp_ugt: IRBuilder<"CreateICmpUGT">;
def icmp_uge: IRBuilder<"CreateICmpUGE">;
def icmp_ult: IRBuilder<"CreateICmpULT">;
def icmp_ule: IRBuilder<"CreateICmpULE">;
def icmp_sgt: IRBuilder<"CreateICmpSGT">;
def icmp_sge: IRBuilder<"CreateICmpSGE">;
def icmp_slt: IRBuilder<"CreateICmpSLT">;
def icmp_sle: IRBuilder<"CreateICmpSLE">;
def fcmp_eq: IRBuilder<"CreateFCmpOEQ">;
def fcmp_ne: IRBuilder<"CreateFCmpUNE">; // not O: it must return true on NaNs
def fcmp_gt: IRBuilder<"CreateFCmpOGT">;
def fcmp_ge: IRBuilder<"CreateFCmpOGE">;
def fcmp_lt: IRBuilder<"CreateFCmpOLT">;
def fcmp_le: IRBuilder<"CreateFCmpOLE">;
def splat: CGHelperFn<"ARMMVEVectorSplat">;
// A node that makes an Address out of a pointer-typed Value, by
// providing an alignment as the second argument.

View File

@ -6795,6 +6795,14 @@ static llvm::Value *SignOrZeroExtend(CGBuilderTy &Builder, llvm::Value *V,
return Unsigned ? Builder.CreateZExt(V, T) : Builder.CreateSExt(V, T);
}
static llvm::Value *ARMMVEVectorSplat(CGBuilderTy &Builder, llvm::Value *V) {
// MVE-specific helper function for a vector splat, which infers the element
// count of the output vector by knowing that MVE vectors are all 128 bits
// wide.
unsigned Elements = 128 / V->getType()->getPrimitiveSizeInBits();
return Builder.CreateVectorSplat(Elements, V);
}
Value *CodeGenFunction::EmitARMMVEBuiltinExpr(unsigned BuiltinID,
const CallExpr *E,
ReturnValueSlot ReturnValue,

File diff suppressed because it is too large Load Diff