Merge pull request #1393 from kinke/nullArray

Optimize array comparisons against null
This commit is contained in:
David Nadlinger 2016-04-09 23:22:53 +01:00
commit 209b6fc2b0
6 changed files with 67 additions and 42 deletions

View file

@ -207,9 +207,9 @@ LLValue *DtoAAEquals(Loc &loc, TOK op, DValue *l, DValue *r) {
LLValue *res =
gIR->CreateCallOrInvoke(func, aaTypeInfo, aaval, abval, "aaEqRes")
.getInstruction();
res = gIR->ir->CreateICmpNE(res, DtoConstInt(0));
if (op == TOKnotequal) {
res = gIR->ir->CreateNot(res);
}
const auto predicate = eqTokToICmpPred(op, /* invert = */ true);
res = gIR->ir->CreateICmp(predicate, res, DtoConstInt(0));
return res;
}

View file

@ -943,10 +943,16 @@ static LLValue *DtoArrayEqCmp_impl(Loc &loc, const char *func, DValue *l,
////////////////////////////////////////////////////////////////////////////////
LLValue *DtoArrayEquals(Loc &loc, TOK op, DValue *l, DValue *r) {
LLValue *res = DtoArrayEqCmp_impl(loc, "_adEq2", l, r, true);
res = gIR->ir->CreateICmpNE(res, DtoConstInt(0));
if (op == TOKnotequal) {
res = gIR->ir->CreateNot(res);
LLValue *res = nullptr;
// optimize comparisons against null by rewriting to `l.length op 0`
if (r->isNull()) {
const auto predicate = eqTokToICmpPred(op);
res = gIR->ir->CreateICmp(predicate, DtoArrayLen(l), DtoConstSize_t(0));
} else {
res = DtoArrayEqCmp_impl(loc, "_adEq2", l, r, true);
const auto predicate = eqTokToICmpPred(op, /* invert = */ true);
res = gIR->ir->CreateICmp(predicate, res, DtoConstInt(0));
}
return res;
@ -956,7 +962,7 @@ LLValue *DtoArrayEquals(Loc &loc, TOK op, DValue *l, DValue *r) {
LLValue *DtoArrayCompare(Loc &loc, TOK op, DValue *l, DValue *r) {
LLValue *res = nullptr;
llvm::ICmpInst::Predicate cmpop;
tokToIcmpPred(op, false, &cmpop, &res);
tokToICmpPred(op, false, &cmpop, &res);
if (!res) {
Type *t = l->getType()->toBasetype()->nextOf()->toBasetype();
@ -997,26 +1003,16 @@ LLValue *DtoArrayCastLength(Loc &loc, LLValue *len, LLType *elemty,
////////////////////////////////////////////////////////////////////////////////
LLValue *DtoDynArrayIs(TOK op, DValue *l, DValue *r) {
LLValue *len1, *ptr1, *len2, *ptr2;
assert(l);
assert(r);
// compare lengths
len1 = DtoArrayLen(l);
len2 = DtoArrayLen(r);
LLValue *b1 = gIR->ir->CreateICmpEQ(len1, len2);
LLValue *len1 = DtoArrayLen(l);
LLValue *ptr1 = DtoArrayPtr(l);
// compare pointers
ptr1 = DtoArrayPtr(l);
ptr2 = DtoArrayPtr(r);
LLValue *b2 = gIR->ir->CreateICmpEQ(ptr1, ptr2);
LLValue *len2 = DtoArrayLen(r);
LLValue *ptr2 = DtoArrayPtr(r);
// combine
LLValue *res = gIR->ir->CreateAnd(b1, b2);
// return result
return (op == TOKnotidentity) ? gIR->ir->CreateNot(res) : res;
return createIPairCmp(op, len1, ptr1, len2, ptr2);
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -1451,7 +1451,7 @@ void AppendFunctionToLLVMGlobalCtorsDtors(llvm::Function *func,
////////////////////////////////////////////////////////////////////////////////
void tokToIcmpPred(TOK op, bool isUnsigned, llvm::ICmpInst::Predicate *outPred,
void tokToICmpPred(TOK op, bool isUnsigned, llvm::ICmpInst::Predicate *outPred,
llvm::Value **outConst) {
switch (op) {
case TOKlt:
@ -1487,6 +1487,35 @@ void tokToIcmpPred(TOK op, bool isUnsigned, llvm::ICmpInst::Predicate *outPred,
}
}
////////////////////////////////////////////////////////////////////////////////
llvm::ICmpInst::Predicate eqTokToICmpPred(TOK op, bool invert) {
assert(op == TOKequal || op == TOKnotequal || op == TOKidentity ||
op == TOKnotidentity);
bool isEquality = (op == TOKequal || op == TOKidentity);
if (invert)
isEquality = !isEquality;
return (isEquality ? llvm::ICmpInst::ICMP_EQ : llvm::ICmpInst::ICMP_NE);
}
////////////////////////////////////////////////////////////////////////////////
LLValue *createIPairCmp(TOK op, LLValue *lhs1, LLValue *lhs2, LLValue *rhs1,
LLValue *rhs2) {
const auto predicate = eqTokToICmpPred(op);
LLValue *r1 = gIR->ir->CreateICmp(predicate, lhs1, rhs1);
LLValue *r2 = gIR->ir->CreateICmp(predicate, lhs2, rhs2);
LLValue *r =
(predicate == llvm::ICmpInst::ICMP_EQ ? gIR->ir->CreateAnd(r1, r2)
: gIR->ir->CreateOr(r1, r2));
return r;
}
///////////////////////////////////////////////////////////////////////////////
DValue *DtoSymbolAddress(Loc &loc, Type *type, Declaration *decl) {
IF_LOG Logger::println("DtoSymbolAddress ('%s' of type '%s')",

View file

@ -180,9 +180,18 @@ bool isLLVMUnsigned(Type *t);
///
/// For some operations, the result can be a constant. In this case outConst is
/// set to it, otherwise outPred is set to the predicate to use.
void tokToIcmpPred(TOK op, bool isUnsigned, llvm::ICmpInst::Predicate *outPred,
void tokToICmpPred(TOK op, bool isUnsigned, llvm::ICmpInst::Predicate *outPred,
llvm::Value **outConst);
/// Converts a DMD equality/identity operation token into the corresponding LLVM
/// icmp predicate.
llvm::ICmpInst::Predicate eqTokToICmpPred(TOK op, bool invert = false);
/// For equality/identity operations, returns `(lhs1 == rhs1) & (lhs2 == rhs2)`.
/// `(lhs1 != rhs1) | (lhs2 != rhs2)` for inequality/not-identity.
LLValue *createIPairCmp(TOK op, LLValue *lhs1, LLValue *lhs2, LLValue *rhs1,
LLValue *rhs2);
////////////////////////////////////////////
// gen/tocall.cpp stuff below
////////////////////////////////////////////

View file

@ -1416,7 +1416,7 @@ public:
if (t->isintegral() || t->ty == Tpointer || t->ty == Tnull) {
llvm::ICmpInst::Predicate icmpPred;
tokToIcmpPred(e->op, isLLVMUnsigned(t), &icmpPred, &eval);
tokToICmpPred(e->op, isLLVMUnsigned(t), &icmpPred, &eval);
if (!eval) {
LLValue *a = l->getRVal();
@ -1481,7 +1481,7 @@ public:
eval = LLConstantInt::getFalse(gIR->context());
} else if (t->ty == Tdelegate) {
llvm::ICmpInst::Predicate icmpPred;
tokToIcmpPred(e->op, isLLVMUnsigned(t), &icmpPred, &eval);
tokToICmpPred(e->op, isLLVMUnsigned(t), &icmpPred, &eval);
if (!eval) {
// First compare the function pointers, then the context ones. This is

View file

@ -221,26 +221,17 @@ LLType *i1ToI8(LLType *t) {
LLValue *DtoDelegateEquals(TOK op, LLValue *lhs, LLValue *rhs) {
Logger::println("Doing delegate equality");
llvm::Value *b1, *b2;
if (rhs == nullptr) {
rhs = LLConstant::getNullValue(lhs->getType());
}
LLValue *l = gIR->ir->CreateExtractValue(lhs, 0);
LLValue *r = gIR->ir->CreateExtractValue(rhs, 0);
b1 = gIR->ir->CreateICmp(llvm::ICmpInst::ICMP_EQ, l, r);
LLValue *l1 = gIR->ir->CreateExtractValue(lhs, 0);
LLValue *l2 = gIR->ir->CreateExtractValue(lhs, 1);
l = gIR->ir->CreateExtractValue(lhs, 1);
r = gIR->ir->CreateExtractValue(rhs, 1);
b2 = gIR->ir->CreateICmp(llvm::ICmpInst::ICMP_EQ, l, r);
LLValue *r1 = gIR->ir->CreateExtractValue(rhs, 0);
LLValue *r2 = gIR->ir->CreateExtractValue(rhs, 1);
LLValue *b = gIR->ir->CreateAnd(b1, b2);
if (op == TOKnotequal || op == TOKnotidentity) {
return gIR->ir->CreateNot(b);
}
return b;
return createIPairCmp(op, l1, l2, r1, r2);
}
////////////////////////////////////////////////////////////////////////////////