mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-28 16:01:00 +08:00
d: Add support for vector comparison operators
The front-end added semantic support to permit comparing two vector expressions. This removes the restriction in the code generator, as well as the intrisics that previously exposed the same operation. gcc/d/ChangeLog: * d-target.cc (Target::isVectorOpSupported): Remove cases for comparison operators. * intrinsics.cc (maybe_set_intrinsic): Remove cases for vector comparison intrinsics. (maybe_warn_intrinsic_mismatch): Likewise. (expand_intrinsic_vec_cond): Remove. (maybe_expand_intrinsic): Remove cases for vector comparison intrinsics. * intrinsics.def (INTRINSIC_EQUALMASK): Remove. (INTRINSIC_NOTEQUALMASK): Remove. (INTRINSIC_GREATERMASK): Remove. (INTRINSIC_GREATEREQUALMASK): Remove. libphobos/ChangeLog: * libdruntime/gcc/simd.d (equalMask): Implement using generics. (notEqualMask): Likewise. (greaterMask): Likewise. (greaterOrEqualMask): Likewise. (notMask): Likewise. (andAndMask): Likewise. (orOrMask): Likewise. gcc/testsuite/ChangeLog: * gdc.dg/Wbuiltin_declaration_mismatch2.d: Remove comparision tests. * gdc.dg/simd2a.d: Update comparison tests. * gdc.dg/simd2b.d: Likewise. * gdc.dg/simd2c.d: Likewise. * gdc.dg/simd2d.d: Likewise. * gdc.dg/simd2e.d: Likewise. * gdc.dg/simd2f.d: Likewise. * gdc.dg/simd2g.d: Likewise. * gdc.dg/simd2h.d: Likewise. * gdc.dg/simd2i.d: Likewise. * gdc.dg/simd2j.d: Likewise.
This commit is contained in:
parent
3ad2167bba
commit
3c28d6a3a0
@ -323,12 +323,6 @@ Target::isVectorOpSupported (Type *type, EXP op, Type *)
|
||||
/* Logical operators must have a result type of bool. */
|
||||
return false;
|
||||
|
||||
case EXP::lessOrEqual:
|
||||
case EXP::lessThan:
|
||||
case EXP::greaterOrEqual:
|
||||
case EXP::greaterThan:
|
||||
case EXP::equal:
|
||||
case EXP::notEqual:
|
||||
case EXP::identity:
|
||||
case EXP::notIdentity:
|
||||
/* Comparison operators must have a result type of bool. */
|
||||
|
@ -170,10 +170,6 @@ maybe_set_intrinsic (FuncDeclaration *decl)
|
||||
case INTRINSIC_SHUFFLEVECTOR:
|
||||
case INTRINSIC_CONVERTVECTOR:
|
||||
case INTRINSIC_BLENDVECTOR:
|
||||
case INTRINSIC_EQUALMASK:
|
||||
case INTRINSIC_NOTEQUALMASK:
|
||||
case INTRINSIC_GREATERMASK:
|
||||
case INTRINSIC_GREATEREQUALMASK:
|
||||
case INTRINSIC_VLOAD8:
|
||||
case INTRINSIC_VLOAD16:
|
||||
case INTRINSIC_VLOAD32:
|
||||
@ -487,29 +483,6 @@ maybe_warn_intrinsic_mismatch (tree function, tree callexp)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case INTRINSIC_EQUALMASK:
|
||||
case INTRINSIC_NOTEQUALMASK:
|
||||
case INTRINSIC_GREATERMASK:
|
||||
case INTRINSIC_GREATEREQUALMASK:
|
||||
{
|
||||
/* Expects the signature:
|
||||
vector(T) equalMask(vector(T), vector(T));
|
||||
vector(T) notEqualMask(vector(T), vector(T));
|
||||
vector(T) greaterMask(vector(T), vector(T));
|
||||
vector(T) greateOrEqualMask(vector(T), vector(T)); */
|
||||
gcc_assert (call_expr_nargs (callexp) == 2);
|
||||
|
||||
tree vec0 = TREE_TYPE (CALL_EXPR_ARG (callexp, 0));
|
||||
tree vec1 = TREE_TYPE (CALL_EXPR_ARG (callexp, 1));
|
||||
if (!VECTOR_TYPE_P (TREE_TYPE (callexp))
|
||||
|| !VECTOR_TYPE_P (vec0)
|
||||
|| !VECTOR_TYPE_P (vec1)
|
||||
|| TYPE_MAIN_VARIANT (vec0) != TYPE_MAIN_VARIANT (vec1))
|
||||
return warn_mismatched_return_type (callexp, "__vector(T)");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generic mismatch warning if it hasn't already been handled. */
|
||||
@ -1072,32 +1045,6 @@ expand_volatile_store (tree callexp)
|
||||
return modify_expr (result, value);
|
||||
}
|
||||
|
||||
/* Expand a front-end intrinsic call to a vector comparison intrinsic, which is
|
||||
either a call to equalMask(), notEqualMask(), greaterMask(), or
|
||||
greaterOrEqualMask(). These intrinsics take two arguments, the signature to
|
||||
which can be either:
|
||||
|
||||
vector(T) equalMask(vector(T) vec0, vector(T) vec1);
|
||||
vector(T) notEqualMask(vector(T) vec0, vector(T) vec1);
|
||||
vector(T) greaterMask(vector(T) vec0, vector(T) vec1);
|
||||
vector(T) greaterOrEqualMask(vector(T) vec0, vector(T) vec1);
|
||||
|
||||
This performs an element-wise comparison between two vectors VEC0 and VEC1,
|
||||
returning a vector with signed integral elements. */
|
||||
|
||||
static tree
|
||||
expand_intrinsic_vec_cond (tree_code code, tree callexp)
|
||||
{
|
||||
tree vec0 = CALL_EXPR_ARG (callexp, 0);
|
||||
tree vec1 = CALL_EXPR_ARG (callexp, 1);
|
||||
tree type = TREE_TYPE (callexp);
|
||||
|
||||
tree cmp = fold_build2_loc (EXPR_LOCATION (callexp), code,
|
||||
truth_type_for (type), vec0, vec1);
|
||||
return fold_build3_loc (EXPR_LOCATION (callexp), VEC_COND_EXPR, type, cmp,
|
||||
build_minus_one_cst (type), build_zero_cst (type));
|
||||
}
|
||||
|
||||
/* Expand a front-end instrinsic call to convertvector(). This takes one
|
||||
argument, the signature to which is:
|
||||
|
||||
@ -1488,18 +1435,6 @@ maybe_expand_intrinsic (tree callexp)
|
||||
case INTRINSIC_BLENDVECTOR:
|
||||
return expand_intrinsic_vec_blend (callexp);
|
||||
|
||||
case INTRINSIC_EQUALMASK:
|
||||
return expand_intrinsic_vec_cond (EQ_EXPR, callexp);
|
||||
|
||||
case INTRINSIC_NOTEQUALMASK:
|
||||
return expand_intrinsic_vec_cond (NE_EXPR, callexp);
|
||||
|
||||
case INTRINSIC_GREATERMASK:
|
||||
return expand_intrinsic_vec_cond (GT_EXPR, callexp);
|
||||
|
||||
case INTRINSIC_GREATEREQUALMASK:
|
||||
return expand_intrinsic_vec_cond (GE_EXPR, callexp);
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
@ -266,14 +266,6 @@ DEF_D_BUILTIN (INTRINSIC_CONVERTVECTOR, BUILT_IN_NONE, "convertvector",
|
||||
"gcc.simd", "F@1TZ@1V")
|
||||
DEF_D_BUILTIN (INTRINSIC_BLENDVECTOR, BUILT_IN_NONE, "blendvector", "gcc.simd",
|
||||
"F@2V0@2V1@1MZ@2V0")
|
||||
DEF_D_BUILTIN (INTRINSIC_EQUALMASK, BUILT_IN_NONE, "equalMask", "gcc.simd",
|
||||
"F@1V@1VZ@1V")
|
||||
DEF_D_BUILTIN (INTRINSIC_NOTEQUALMASK, BUILT_IN_NONE, "notEqualMask",
|
||||
"gcc.simd", "F@1V@1VZ@1V")
|
||||
DEF_D_BUILTIN (INTRINSIC_GREATERMASK, BUILT_IN_NONE, "greaterMask", "gcc.simd",
|
||||
"F@1V@1VZ@1V")
|
||||
DEF_D_BUILTIN (INTRINSIC_GREATEREQUALMASK, BUILT_IN_NONE,
|
||||
"greaterOrEqualMask", "gcc.simd", "F@1V@1VZ@1V")
|
||||
|
||||
#undef DEF_D_BUILTIN
|
||||
#undef DEF_CTFE_BUILTIN
|
||||
|
@ -191,41 +191,6 @@ void test_blendvector()
|
||||
blendvector!(byte16, byte16, byte16)(0, 0, 0);
|
||||
}
|
||||
|
||||
void test_comparison()
|
||||
{
|
||||
equalMask!int(0, 0); // { dg-warning "mismatch in return type" }
|
||||
equalMask!double(0, 0); // { dg-warning "mismatch in return type" }
|
||||
equalMask!int4(0, 0);
|
||||
equalMask!short8(0, 0);
|
||||
equalMask!float4(0, 0);
|
||||
equalMask!byte16(0, 0);
|
||||
equalMask!fake4(f, f); // { dg-warning "mismatch in return type" }
|
||||
|
||||
notEqualMask!int(0, 0); // { dg-warning "mismatch in return type" }
|
||||
notEqualMask!double(0, 0); // { dg-warning "mismatch in return type" }
|
||||
notEqualMask!int4(0, 0);
|
||||
notEqualMask!short8(0, 0);
|
||||
notEqualMask!float4(0, 0);
|
||||
notEqualMask!byte16(0, 0);
|
||||
notEqualMask!fake4(f, f); // { dg-warning "mismatch in return type" }
|
||||
|
||||
greaterMask!int(0, 0); // { dg-warning "mismatch in return type" }
|
||||
greaterMask!double(0, 0); // { dg-warning "mismatch in return type" }
|
||||
greaterMask!int4(0, 0);
|
||||
greaterMask!short8(0, 0);
|
||||
greaterMask!float4(0, 0);
|
||||
greaterMask!byte16(0, 0);
|
||||
greaterMask!fake4(f, f); // { dg-warning "mismatch in return type" }
|
||||
|
||||
greaterOrEqualMask!int(0, 0); // { dg-warning "mismatch in return type" }
|
||||
greaterOrEqualMask!double(0, 0); // { dg-warning "mismatch in return type" }
|
||||
greaterOrEqualMask!int4(0, 0);
|
||||
greaterOrEqualMask!short8(0, 0);
|
||||
greaterOrEqualMask!float4(0, 0);
|
||||
greaterOrEqualMask!byte16(0, 0);
|
||||
greaterOrEqualMask!fake4(f, f); // { dg-warning "mismatch in return type" }
|
||||
}
|
||||
|
||||
// The following declarations of the simd intrinsics are without any guards
|
||||
// to verify `d/intrinsics.cc` is doing checks to prevent invalid lowerings.
|
||||
V loadUnaligned(V)(const V*);
|
||||
@ -243,8 +208,3 @@ __vector(E!V1[M.length]) shufflevector(V1, V2, M...)(V1, V2, M) if (isV!V1 && is
|
||||
|
||||
V convertvector(V, T)(T);
|
||||
V0 blendvector(V0, V1, M)(V0, V1, M);
|
||||
|
||||
V equalMask(V)(V, V);
|
||||
V notEqualMask(V)(V, V);
|
||||
V greaterMask(V)(V, V);
|
||||
V greaterOrEqualMask(V)(V, V);
|
||||
|
@ -18,12 +18,12 @@ void test2a()
|
||||
static assert(!__traits(compiles, v1 ^^ v2));
|
||||
static assert(!__traits(compiles, v1 is v2));
|
||||
static assert(!__traits(compiles, v1 !is v2));
|
||||
static assert(!__traits(compiles, v1 == v2));
|
||||
static assert(!__traits(compiles, v1 != v2));
|
||||
static assert(!__traits(compiles, v1 < v2));
|
||||
static assert(!__traits(compiles, v1 > v2));
|
||||
static assert(!__traits(compiles, v1 <= v2));
|
||||
static assert(!__traits(compiles, v1 >= v2));
|
||||
v1 = v1 == v2;
|
||||
v1 = v1 != v2;
|
||||
v1 = v1 < v2;
|
||||
v1 = v1 > v2;
|
||||
v1 = v1 <= v2;
|
||||
v1 = v1 >= v2;
|
||||
v1 = v2 << 1;
|
||||
v1 = v2 >> 1;
|
||||
v1 = v2 >>> 1;
|
||||
|
@ -18,12 +18,12 @@ void test2b()
|
||||
static assert(!__traits(compiles, v1 ^^ v2));
|
||||
static assert(!__traits(compiles, v1 is v2));
|
||||
static assert(!__traits(compiles, v1 !is v2));
|
||||
static assert(!__traits(compiles, v1 == v2));
|
||||
static assert(!__traits(compiles, v1 != v2));
|
||||
static assert(!__traits(compiles, v1 < v2));
|
||||
static assert(!__traits(compiles, v1 > v2));
|
||||
static assert(!__traits(compiles, v1 <= v2));
|
||||
static assert(!__traits(compiles, v1 >= v2));
|
||||
v1 = v1 == v2;
|
||||
v1 = v1 != v2;
|
||||
v1 = v1 < v2;
|
||||
v1 = v1 > v2;
|
||||
v1 = v1 <= v2;
|
||||
v1 = v1 >= v2;
|
||||
v1 = v2 << 1;
|
||||
v1 = v2 >> 1;
|
||||
v1 = v2 >>> 1;
|
||||
|
@ -18,12 +18,12 @@ void test2c()
|
||||
static assert(!__traits(compiles, v1 ^^ v2));
|
||||
static assert(!__traits(compiles, v1 is v2));
|
||||
static assert(!__traits(compiles, v1 !is v2));
|
||||
static assert(!__traits(compiles, v1 == v2));
|
||||
static assert(!__traits(compiles, v1 != v2));
|
||||
static assert(!__traits(compiles, v1 < v2));
|
||||
static assert(!__traits(compiles, v1 > v2));
|
||||
static assert(!__traits(compiles, v1 <= v2));
|
||||
static assert(!__traits(compiles, v1 >= v2));
|
||||
v1 = v1 == v2;
|
||||
v1 = v1 != v2;
|
||||
v1 = v1 < v2;
|
||||
v1 = v1 > v2;
|
||||
v1 = v1 <= v2;
|
||||
v1 = v1 >= v2;
|
||||
v1 = v2 << 1;
|
||||
v1 = v2 >> 1;
|
||||
v1 = v2 >>> 1;
|
||||
|
@ -18,12 +18,12 @@ void test2d()
|
||||
static assert(!__traits(compiles, v1 ^^ v2));
|
||||
static assert(!__traits(compiles, v1 is v2));
|
||||
static assert(!__traits(compiles, v1 !is v2));
|
||||
static assert(!__traits(compiles, v1 == v2));
|
||||
static assert(!__traits(compiles, v1 != v2));
|
||||
static assert(!__traits(compiles, v1 < v2));
|
||||
static assert(!__traits(compiles, v1 > v2));
|
||||
static assert(!__traits(compiles, v1 <= v2));
|
||||
static assert(!__traits(compiles, v1 >= v2));
|
||||
v1 = v1 == v2;
|
||||
v1 = v1 != v2;
|
||||
v1 = v1 < v2;
|
||||
v1 = v1 > v2;
|
||||
v1 = v1 <= v2;
|
||||
v1 = v1 >= v2;
|
||||
v1 = v2 << 1;
|
||||
v1 = v2 >> 1;
|
||||
v1 = v2 >>> 1;
|
||||
|
@ -18,12 +18,12 @@ void test2e()
|
||||
static assert(!__traits(compiles, v1 ^^ v2));
|
||||
static assert(!__traits(compiles, v1 is v2));
|
||||
static assert(!__traits(compiles, v1 !is v2));
|
||||
static assert(!__traits(compiles, v1 == v2));
|
||||
static assert(!__traits(compiles, v1 != v2));
|
||||
static assert(!__traits(compiles, v1 < v2));
|
||||
static assert(!__traits(compiles, v1 > v2));
|
||||
static assert(!__traits(compiles, v1 <= v2));
|
||||
static assert(!__traits(compiles, v1 >= v2));
|
||||
v1 = v1 == v2;
|
||||
v1 = v1 != v2;
|
||||
v1 = v1 < v2;
|
||||
v1 = v1 > v2;
|
||||
v1 = v1 <= v2;
|
||||
v1 = v1 >= v2;
|
||||
v1 = v2 << 1;
|
||||
v1 = v2 >> 1;
|
||||
v1 = v2 >>> 1;
|
||||
|
@ -18,12 +18,12 @@ void test2f()
|
||||
static assert(!__traits(compiles, v1 ^^ v2));
|
||||
static assert(!__traits(compiles, v1 is v2));
|
||||
static assert(!__traits(compiles, v1 !is v2));
|
||||
static assert(!__traits(compiles, v1 == v2));
|
||||
static assert(!__traits(compiles, v1 != v2));
|
||||
static assert(!__traits(compiles, v1 < v2));
|
||||
static assert(!__traits(compiles, v1 > v2));
|
||||
static assert(!__traits(compiles, v1 <= v2));
|
||||
static assert(!__traits(compiles, v1 >= v2));
|
||||
v1 = v1 == v2;
|
||||
v1 = v1 != v2;
|
||||
v1 = v1 < v2;
|
||||
v1 = v1 > v2;
|
||||
v1 = v1 <= v2;
|
||||
v1 = v1 >= v2;
|
||||
v1 = v2 << 1;
|
||||
v1 = v2 >> 1;
|
||||
v1 = v2 >>> 1;
|
||||
|
@ -18,12 +18,12 @@ void test2g()
|
||||
static assert(!__traits(compiles, v1 ^^ v2));
|
||||
static assert(!__traits(compiles, v1 is v2));
|
||||
static assert(!__traits(compiles, v1 !is v2));
|
||||
static assert(!__traits(compiles, v1 == v2));
|
||||
static assert(!__traits(compiles, v1 != v2));
|
||||
static assert(!__traits(compiles, v1 < v2));
|
||||
static assert(!__traits(compiles, v1 > v2));
|
||||
static assert(!__traits(compiles, v1 <= v2));
|
||||
static assert(!__traits(compiles, v1 >= v2));
|
||||
v1 = v1 == v2;
|
||||
v1 = v1 != v2;
|
||||
v1 = v1 < v2;
|
||||
v1 = v1 > v2;
|
||||
v1 = v1 <= v2;
|
||||
v1 = v1 >= v2;
|
||||
v1 = v2 << 1;
|
||||
v1 = v2 >> 1;
|
||||
v1 = v2 >>> 1;
|
||||
|
@ -18,12 +18,12 @@ void test2h()
|
||||
static assert(!__traits(compiles, v1 ^^ v2));
|
||||
static assert(!__traits(compiles, v1 is v2));
|
||||
static assert(!__traits(compiles, v1 !is v2));
|
||||
static assert(!__traits(compiles, v1 == v2));
|
||||
static assert(!__traits(compiles, v1 != v2));
|
||||
static assert(!__traits(compiles, v1 < v2));
|
||||
static assert(!__traits(compiles, v1 > v2));
|
||||
static assert(!__traits(compiles, v1 <= v2));
|
||||
static assert(!__traits(compiles, v1 >= v2));
|
||||
v1 = v1 == v2;
|
||||
v1 = v1 != v2;
|
||||
v1 = v1 < v2;
|
||||
v1 = v1 > v2;
|
||||
v1 = v1 <= v2;
|
||||
v1 = v1 >= v2;
|
||||
v1 = v2 << 1;
|
||||
v1 = v2 >> 1;
|
||||
v1 = v2 >>> 1;
|
||||
|
@ -18,12 +18,12 @@ void test2i()
|
||||
static assert(!__traits(compiles, v1 ^^ v2));
|
||||
static assert(!__traits(compiles, v1 is v2));
|
||||
static assert(!__traits(compiles, v1 !is v2));
|
||||
static assert(!__traits(compiles, v1 == v2));
|
||||
static assert(!__traits(compiles, v1 != v2));
|
||||
static assert(!__traits(compiles, v1 < v2));
|
||||
static assert(!__traits(compiles, v1 > v2));
|
||||
static assert(!__traits(compiles, v1 <= v2));
|
||||
static assert(!__traits(compiles, v1 >= v2));
|
||||
v1 = v1 == v2;
|
||||
v1 = v1 != v2;
|
||||
v1 = v1 < v2;
|
||||
v1 = v1 > v2;
|
||||
v1 = v1 <= v2;
|
||||
v1 = v1 >= v2;
|
||||
static assert(!__traits(compiles, v1 << 1));
|
||||
static assert(!__traits(compiles, v1 >> 1));
|
||||
static assert(!__traits(compiles, v1 >>> 1));
|
||||
|
@ -18,12 +18,12 @@ void test2j()
|
||||
static assert(!__traits(compiles, v1 ^^ v2));
|
||||
static assert(!__traits(compiles, v1 is v2));
|
||||
static assert(!__traits(compiles, v1 !is v2));
|
||||
static assert(!__traits(compiles, v1 == v2));
|
||||
static assert(!__traits(compiles, v1 != v2));
|
||||
static assert(!__traits(compiles, v1 < v2));
|
||||
static assert(!__traits(compiles, v1 > v2));
|
||||
static assert(!__traits(compiles, v1 <= v2));
|
||||
static assert(!__traits(compiles, v1 >= v2));
|
||||
v1 = v1 == v2;
|
||||
v1 = v1 != v2;
|
||||
v1 = v1 < v2;
|
||||
v1 = v1 > v2;
|
||||
v1 = v1 <= v2;
|
||||
v1 = v1 >= v2;
|
||||
static assert(!__traits(compiles, v1 << 1));
|
||||
static assert(!__traits(compiles, v1 >> 1));
|
||||
static assert(!__traits(compiles, v1 >>> 1));
|
||||
|
@ -306,13 +306,25 @@ template blendvector(V0, V1, M)
|
||||
* assert(c.array == [0, 0, -1, -1]);
|
||||
* ---
|
||||
*/
|
||||
V equalMask(V)(V op1, V op2) if (isVectorType!V);
|
||||
V equalMask(V)(V op1, V op2) if (isVectorType!V)
|
||||
{
|
||||
return op1 == op2;
|
||||
}
|
||||
/// Ditto
|
||||
V notEqualMask(V)(V op1, V op2) if (isVectorType!V);
|
||||
V notEqualMask(V)(V op1, V op2) if (isVectorType!V)
|
||||
{
|
||||
return op1 != op2;
|
||||
}
|
||||
/// Ditto
|
||||
V greaterMask(V)(V op1, V op2) if (isVectorType!V);
|
||||
V greaterMask(V)(V op1, V op2) if (isVectorType!V)
|
||||
{
|
||||
return op1 > op2;
|
||||
}
|
||||
/// Ditto
|
||||
V greaterOrEqualMask(V)(V op1, V op2) if (isVectorType!V);
|
||||
V greaterOrEqualMask(V)(V op1, V op2) if (isVectorType!V)
|
||||
{
|
||||
return op1 >= op2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an element-wise logical comparison between two vectors, producing
|
||||
@ -326,19 +338,19 @@ V greaterOrEqualMask(V)(V op1, V op2) if (isVectorType!V);
|
||||
*/
|
||||
V notMask(V)(V op1) if (isVectorType!V)
|
||||
{
|
||||
return equalMask(op1, 0);
|
||||
return op1 == 0;
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
V andAndMask(V)(V op1, V op2) if (isVectorType!V)
|
||||
{
|
||||
return notEqualMask(op1, 0) & notEqualMask(op2, 0);
|
||||
return (op1 != 0) & (op2 != 0);
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
V orOrMask(V)(V op1, V op2) if (isVectorType!V)
|
||||
{
|
||||
return notEqualMask(op1, 0) | notEqualMask(op2, 0);
|
||||
return (op1 != 0) | (op2 != 0);
|
||||
}
|
||||
|
||||
// Private helper templates.
|
||||
|
Loading…
x
Reference in New Issue
Block a user