forked from OSchip/llvm-project
[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:
parent
23a766dcad
commit
4a4dd85e5a
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue