Skip to content

Commit

Permalink
Issue 13010: use VRP for static asserts
Browse files Browse the repository at this point in the history
  • Loading branch information
lionello committed Mar 2, 2015
1 parent 004989b commit a2d1c32
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 65 deletions.
155 changes: 90 additions & 65 deletions src/constfold.c
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,40 @@ UnionExp Identity(TOK op, Type *type, Expression *e1, Expression *e2)
}


template<class T>
static bool _cmp(T n1, TOK op, T n2)
{
switch (op)
{
case TOKlt: return n1 < n2;
case TOKle: return n1 <= n2;
case TOKgt: return n1 > n2;
case TOKge: return n1 >= n2;

case TOKleg: return 1;
case TOKlg: return n1 != n2;
case TOKunord: return 0;
case TOKue: return n1 == n2;
case TOKug: return n1 > n2;
case TOKuge: return n1 >= n2;
case TOKul: return n1 < n2;
case TOKule: return n1 <= n2;

default:
assert(0);
}
}

static bool integerCmp(bool anyunsigned, sinteger_t n1, TOK op, sinteger_t n2)
{
/* Do an unsigned comparison if any of the integers is unsigned. */
if (anyunsigned)
return _cmp<d_uns64>(n1, op, n2);
else
return _cmp<sinteger_t>(n1, op, n2);
}


UnionExp Cmp(TOK op, Type *type, Expression *e1, Expression *e2)
{
UnionExp ue;
Expand All @@ -1010,31 +1044,66 @@ UnionExp Cmp(TOK op, Type *type, Expression *e1, Expression *e2)
if (cmp == 0)
cmp = (int)(es1->len - es2->len);

n = _cmp(cmp, op, 0);
}
else if (e1->isConst() != 1 || e2->isConst() != 1)
{
if (!e1->type->isintegral() || !e2->type->isintegral())
{
Lcantexp:
new(&ue) CTFEExp(TOKcantexp);
return ue;
}

/* Use VRP to determine whether the comparison is always true or false. */
bool anyunsigned = (e1->type->isunsigned() || e2->type->isunsigned());
IntRange r1 = getIntRange(e1);
IntRange r2 = getIntRange(e2);
// Make sure we don't loose bits during our cast to 64-bit
assert(!e1->type->isunsigned() || (!r1.imin.negative && !r1.imax.negative));
assert(!e2->type->isunsigned() || (!r2.imin.negative && !r2.imax.negative));
switch (op)
{
case TOKlt: n = cmp < 0; break;
case TOKle: n = cmp <= 0; break;
case TOKgt: n = cmp > 0; break;
case TOKge: n = cmp >= 0; break;
case TOKul:
case TOKule:
case TOKlt:
case TOKle:
if (integerCmp(anyunsigned, r1.imax.value, op, r2.imin.value))
n = 1;
else if (integerCmp(anyunsigned, r2.imax.value, op, r1.imin.value))
n = 0;
else
goto Lcantexp;
break;

case TOKleg: n = 1; break;
case TOKlg: n = cmp != 0; break;
case TOKunord: n = 0; break;
case TOKue: n = cmp == 0; break;
case TOKug: n = cmp > 0; break;
case TOKuge: n = cmp >= 0; break;
case TOKul: n = cmp < 0; break;
case TOKule: n = cmp <= 0; break;
case TOKug:
case TOKuge:
case TOKgt:
case TOKge:
if (integerCmp(anyunsigned, r1.imin.value, op, r2.imax.value))
n = 1;
else if (integerCmp(anyunsigned, r2.imin.value, op, r1.imax.value))
n = 0;
else
goto Lcantexp;
break;

case TOKleg:
n = 1;
break;

case TOKunord:
n = 0;
break;

case TOKue:
case TOKlg:
goto Lcantexp;

default:
assert(0);
}
}
else if (e1->isConst() != 1 || e2->isConst() != 1)
{
new(&ue) CTFEExp(TOKcantexp);
return ue;
}
else if (e1->type->isreal())
{
r1 = e1->toReal();
Expand Down Expand Up @@ -1099,55 +1168,11 @@ UnionExp Cmp(TOK op, Type *type, Expression *e1, Expression *e2)
}
else
{
sinteger_t n1;
sinteger_t n2;
sinteger_t n1 = e1->toInteger();
sinteger_t n2 = e2->toInteger();

n1 = e1->toInteger();
n2 = e2->toInteger();
if (e1->type->isunsigned() || e2->type->isunsigned())
{
switch (op)
{
case TOKlt: n = ((d_uns64) n1) < ((d_uns64) n2); break;
case TOKle: n = ((d_uns64) n1) <= ((d_uns64) n2); break;
case TOKgt: n = ((d_uns64) n1) > ((d_uns64) n2); break;
case TOKge: n = ((d_uns64) n1) >= ((d_uns64) n2); break;

case TOKleg: n = 1; break;
case TOKlg: n = ((d_uns64) n1) != ((d_uns64) n2); break;
case TOKunord: n = 0; break;
case TOKue: n = ((d_uns64) n1) == ((d_uns64) n2); break;
case TOKug: n = ((d_uns64) n1) > ((d_uns64) n2); break;
case TOKuge: n = ((d_uns64) n1) >= ((d_uns64) n2); break;
case TOKul: n = ((d_uns64) n1) < ((d_uns64) n2); break;
case TOKule: n = ((d_uns64) n1) <= ((d_uns64) n2); break;

default:
assert(0);
}
}
else
{
switch (op)
{
case TOKlt: n = n1 < n2; break;
case TOKle: n = n1 <= n2; break;
case TOKgt: n = n1 > n2; break;
case TOKge: n = n1 >= n2; break;

case TOKleg: n = 1; break;
case TOKlg: n = n1 != n2; break;
case TOKunord: n = 0; break;
case TOKue: n = n1 == n2; break;
case TOKug: n = n1 > n2; break;
case TOKuge: n = n1 >= n2; break;
case TOKul: n = n1 < n2; break;
case TOKule: n = n1 <= n2; break;

default:
assert(0);
}
}
bool anyunsigned = (e1->type->isunsigned() || e2->type->isunsigned());
n = integerCmp(anyunsigned, n1, op, n2);
}
new(&ue) IntegerExp(loc, n, type);
return ue;
Expand Down
29 changes: 29 additions & 0 deletions test/compilable/testVRP.d
Original file line number Diff line number Diff line change
Expand Up @@ -329,3 +329,32 @@ void test13001(bool unknown)
static assert(!__traits(compiles, b = i + 254));
}
}

void test13010(ubyte value)
{
immutable int i = value;
static assert(0 < i + 1);
static assert(0U < i + 1);
static assert(-1 < i);
static assert(0 <= i);
static assert(0U <= i);
static assert(256 > i);
static assert(256U > i);
static assert(255 >= i);
static assert(255U >= i);
//static assert(-1 != i);
//static assert(256 != i);
//static assert(256U != i);
static assert(i + 1 > 0);
static assert(i + 1 > 0U);
static assert(i > -1);
static assert(i >= 0);
static assert(i >= 0U);
static assert(i < 256);
static assert(i < 256U);
static assert(i <= 255);
static assert(i <= 255U);
//static assert(i != -1);
//static assert(i != 256);
//static assert(i != 256U);
}

0 comments on commit a2d1c32

Please sign in to comment.