Skip to content

Commit

Permalink
Adapt to vector comparisons now yielding a vector mask
Browse files Browse the repository at this point in the history
Except for identity comparisons, which still yield a scalar bool.
(DMD doesn't support vector identity comparisons for some reason.)
  • Loading branch information
kinke committed Feb 19, 2023
1 parent c428bbc commit 3a59ee8
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 55 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# LDC master

#### Big news
- Frontend, druntime and Phobos are at version [2.102.1](https://dlang.org/changelog/2.102.0.html). (#4323)
- Vector comparisons (==, !=, <, <=, >, >=) now yield a vector mask. Identity comparisons (`is`, `!is`) still yield a scalar `bool`. (#4323)

#### Platform support

Expand Down
21 changes: 8 additions & 13 deletions dmd/target.d
Original file line number Diff line number Diff line change
Expand Up @@ -634,24 +634,19 @@ else
} // !IN_LLVM
break;

version (IN_LLVM)
{
case EXP.lessThan, EXP.greaterThan, EXP.lessOrEqual, EXP.greaterOrEqual:
supported = false;
break;
case EXP.equal, EXP.notEqual, EXP.identity, EXP.notIdentity:
supported = true;
break;
}
else
{
case EXP.identity, EXP.notIdentity:
supported = false;
supported = IN_LLVM;
break;

case EXP.lessThan, EXP.greaterThan, EXP.lessOrEqual, EXP.greaterOrEqual:
case EXP.equal:
case EXP.notEqual:
version (IN_LLVM)
{
supported = tvec.isscalar();
}
else
{
if (vecsize == 16)
{
// float[4] comparison needs SSE support (CMP{EQ,NEQ,LT,LE}PS)
Expand Down Expand Up @@ -685,8 +680,8 @@ else
else if (tvec.isintegral() && cpu >= CPU.avx2)
supported = true;
}
break;
} // !IN_LLVM
break;

case EXP.leftShift, EXP.leftShiftAssign, EXP.rightShift, EXP.rightShiftAssign, EXP.unsignedRightShift, EXP.unsignedRightShiftAssign:
supported = IN_LLVM && tvec.isintegral();
Expand Down
3 changes: 0 additions & 3 deletions gen/binops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,6 @@ LLValue *DtoBinFloatsEquals(const Loc &loc, DValue *lhs, DValue *rhs, EXP op) {
LLValue *r = DtoRVal(rhs);
res = (op == EXP::equal ? gIR->ir->CreateFCmpOEQ(l, r)
: gIR->ir->CreateFCmpUNE(l, r));
if (lhs->type->toBasetype()->ty == TY::Tvector) {
res = mergeVectorEquals(res, op);
}
} else {
const auto cmpop =
op == EXP::identity ? llvm::ICmpInst::ICMP_EQ : llvm::ICmpInst::ICMP_NE;
Expand Down
38 changes: 20 additions & 18 deletions gen/toir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,19 @@ void pushVarDtorCleanup(IRState *p, VarDeclaration *vd) {
p->funcGen().scopes.pushCleanup(beginBB, p->scopebb());
}

DImValue *zextInteger(LLValue *val, Type *to) {
assert(val->getType()->isIntegerTy(1));
// Zero-extends a scalar i1 to an integer type, or creates a vector mask from an
// i1 vector.
DImValue *zextBool(LLValue *val, Type *to) {
assert(val->getType()->isIntOrIntVectorTy(1));
LLType *llTy = DtoType(to);
if (val->getType() != llTy) {
assert(llTy->isIntegerTy());
val = gIR->ir->CreateZExt(val, llTy);
if (llTy->isVectorTy()) {
assert(val->getType()->isVectorTy());
val = gIR->ir->CreateSExt(val, llTy);
} else {
assert(llTy->isIntegerTy());
val = gIR->ir->CreateZExt(val, llTy);
}
}
return new DImValue(to, val);
}
Expand Down Expand Up @@ -1360,7 +1367,7 @@ class ToElemVisitor : public Visitor {
llvm_unreachable("Unsupported CmpExp type");
}

result = zextInteger(eval, e->type);
result = zextBool(eval, e->type);
}

//////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -1406,11 +1413,7 @@ class ToElemVisitor : public Visitor {
Logger::cout() << "rv: " << *rv << '\n';
}
eval = p->ir->CreateICmp(cmpop, lv, rv);
if (t->ty == TY::Tvector) {
eval = mergeVectorEquals(eval, e->op);
}
} else if (t->isfloating()) // includes iscomplex
{
} else if (t->isfloating()) { // includes iscomplex
eval = DtoBinNumericEquals(e->loc, l, r, e->op);
} else if (t->ty == TY::Tsarray || t->ty == TY::Tarray) {
Logger::println("static or dynamic array");
Expand All @@ -1429,7 +1432,7 @@ class ToElemVisitor : public Visitor {
llvm_unreachable("Unsupported EqualExp type.");
}

result = zextInteger(eval, e->type);
result = zextBool(eval, e->type);
}

//////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -1814,7 +1817,7 @@ class ToElemVisitor : public Visitor {
LLConstant *zero = DtoConstBool(false);
b = p->ir->CreateICmpEQ(b, zero);

result = zextInteger(b, e->type);
result = zextBool(b, e->type);
}

//////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -1890,7 +1893,7 @@ class ToElemVisitor : public Visitor {
resval = phi;
}

result = zextInteger(resval, e->type);
result = zextBool(resval, e->type);
}

//////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -1990,12 +1993,12 @@ class ToElemVisitor : public Visitor {

// handle dynarray specially
if (t1->ty == TY::Tarray) {
result = zextInteger(DtoDynArrayIs(e->op, l, r), e->type);
result = zextBool(DtoDynArrayIs(e->op, l, r), e->type);
return;
}
// also structs
if (t1->ty == TY::Tstruct) {
result = zextInteger(DtoStructEquals(e->op, l, r), e->type);
result = zextBool(DtoStructEquals(e->op, l, r), e->type);
return;
}

Expand All @@ -2010,8 +2013,7 @@ class ToElemVisitor : public Visitor {
assert(lv->getType() == rv->getType());
}
eval = DtoDelegateEquals(e->op, lv, rv);
} else if (t1->isfloating()) // includes iscomplex
{
} else if (t1->isfloating()) { // includes iscomplex
eval = DtoBinNumericEquals(e->loc, l, r, e->op);
} else if (t1->ty == TY::Tpointer || t1->ty == TY::Tclass) {
LLValue *lv = DtoRVal(l);
Expand Down Expand Up @@ -2042,7 +2044,7 @@ class ToElemVisitor : public Visitor {
: EXP::notEqual);
}
}
result = zextInteger(eval, e->type);
result = zextBool(eval, e->type);
}

//////////////////////////////////////////////////////////////////////////////
Expand Down
18 changes: 15 additions & 3 deletions tests/codegen/gh3208.d
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,24 @@

void test(int length)()
{
__vector(byte[length]) a = 123, b = a;
assert(a == b && !(a != b));
alias V = __vector(byte[length]);

V a = 123, b = a;

V eqMask = -1;
V neqMask = 0;

assert(a is b && !(a !is b));
assert((a == b) is eqMask);
assert((a != b) is neqMask);

b[0] = 0;
assert(a != b && !(a == b));
eqMask[0] = 0;
neqMask[0] = -1;

assert(a !is b && !(a is b));
assert((a == b) is eqMask);
assert((a != b) is neqMask);
}

void main()
Expand Down
4 changes: 2 additions & 2 deletions tests/codegen/vector_intrinsics_gh2962.d
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ void main()
{
const float4 f = [ 1, -2, 3, -4 ];
const abs = llvm_fabs(f);
assert(abs == [ 1, 2, 3, 4 ]);
assert(abs is [ 1, 2, 3, 4 ]);

const int4 i = [ 0b0, 0b10, 0b101, 0b100011 ];
const numOnes = llvm_ctpop(i);
assert(numOnes == [ 0, 1, 2, 3 ]);
assert(numOnes is [ 0, 1, 2, 3 ]);
}
42 changes: 26 additions & 16 deletions tests/codegen/vector_ops.d
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,47 @@ void main()
{
const T v = [ 1, -2, 3, -4 ];

assert(-v == [ -1, 2, -3, 4 ]);
assert(+v == v);
assert(-v is [ -1, 2, -3, 4 ]);
assert(+v is v);

T v2 = v;
assert(v2 == v && !(v2 != v));
assert(v2 is v && !(v2 !is v));
assert((v2 == v) is [ -1, -1, -1, -1 ]);
assert((v2 != v) is [ 0, 0, 0, 0 ]);

v2[0] = 0;
assert(v2 != v && !(v2 == v));
assert(v2 !is v && !(v2 is v));

assert(v + v == [ 2, -4, 6, -8 ]);
assert(v - v == T(0));
assert(v * v == [ 1, 4, 9, 16 ]);
assert(v / v == T(1));
assert(v % T(3) == [ 1, -2, 0, -1 ]);
assert((v2 == v) is [ 0, -1, -1, -1 ]);
assert((v2 != v) is [ -1, 0, 0, 0 ]);

const T comparand = [ 2, -3, 3, -4 ];
assert((v > comparand) is [ 0, -1, 0, 0 ]);
assert((v >= comparand) is [ 0, -1, -1, -1 ]);
assert((v < comparand) is [ -1, 0, 0, 0 ]);
assert((v <= comparand) is [ -1, 0, -1, -1 ]);

assert(v + v is [ 2, -4, 6, -8 ]);
assert(v - v is T(0));
assert(v * v is [ 1, 4, 9, 16 ]);
assert(v / v is T(1));
assert(v % T(3) is [ 1, -2, 0, -1 ]);
}

testGenericOps!float4();
testGenericOps!int4();

const float4 nan = float.nan;
assert(nan != nan && !(nan == nan));
assert(nan is nan && !(nan !is nan));
assert((nan == nan) is [ 0, 0, 0, 0 ]);
assert((nan != nan) is [ -1, -1, -1, -1 ]);

const int4 i = [ 1, 2, 3, 4 ];
assert(i << i == [ 2, 8, 24, 64 ]);
assert(i << i is [ 2, 8, 24, 64 ]);

const int4 a = [ 0b1, 0b10, 0b101, 0b100011 ];
const int4 b = 0b110;
assert((a & b) == [ 0, 0b10, 0b100, 0b10 ]);
assert((a | b) == [ 0b111, 0b110, 0b111, 0b100111 ]);
assert((a ^ b) == [ 0b111, 0b100, 0b11, 0b100101 ]);
assert(~a == [ ~0b1, ~0b10, ~0b101, ~0b100011 ]);
assert((a & b) is [ 0, 0b10, 0b100, 0b10 ]);
assert((a | b) is [ 0b111, 0b110, 0b111, 0b100111 ]);
assert((a ^ b) is [ 0b111, 0b100, 0b11, 0b100101 ]);
assert(~a is [ ~0b1, ~0b10, ~0b101, ~0b100011 ]);
}

0 comments on commit 3a59ee8

Please sign in to comment.