Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More ^^ related improvements. #344

Merged
merged 3 commits into from
Sep 26, 2011
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions src/constfold.c
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,83 @@ Expression *Mod(Type *type, Expression *e1, Expression *e2)
return e;
}

Expression *Pow(Type *type, Expression *e1, Expression *e2)
{ Expression *e;
Loc loc = e1->loc;

// Handle integer power operations.
if (e2->type->isintegral())
{
Expression * r;
Expression * v;
dinteger_t n = e2->toInteger();
bool neg;

if (!e2->type->isunsigned() && (sinteger_t)n < 0)
{
if (e1->type->isintegral())
return EXP_CANT_INTERPRET;

// Don't worry about overflow, from now on n is unsigned.
neg = true;
n = -n;
}
else
neg = false;

if (e1->type->isfloating())
{
r = new RealExp(loc, e1->toReal(), e1->type);
v = new RealExp(loc, 1.0, e1->type);
}
else
{
r = new RealExp(loc, e1->toReal(), Type::tfloat64);
v = new RealExp(loc, 1.0, Type::tfloat64);
}

while (n != 0)
{
if (n & 1)
v = Mul(v->type, v, r);
n >>= 1;
r = Mul(r->type, r, r);
}

if (neg)
v = Div(v->type, new RealExp(loc, 1.0, v->type), v);

if (type->isintegral())
e = new IntegerExp(loc, v->toInteger(), type);
else
e = new RealExp(loc, v->toReal(), type);
}
else if (e2->type->isfloating())
{
// x ^ y for x < 0 and y not an integer is not defined
if (e1->toReal() < 0.0)
{
e = new RealExp(loc, Port::nan, type);
}
else if (e2->toReal() == 0.5)
{
// Special case: call sqrt directly.
Expressions args;
args.setDim(1);
args.tdata()[0] = e1;
e = eval_builtin(BUILTINsqrt, &args);
if (!e)
e = EXP_CANT_INTERPRET;
}
else
e = EXP_CANT_INTERPRET;
}
else
e = EXP_CANT_INTERPRET;

return e;
}

Expression *Shl(Type *type, Expression *e1, Expression *e2)
{ Expression *e;
Loc loc = e1->loc;
Expand Down
32 changes: 32 additions & 0 deletions src/e2ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -3219,6 +3219,22 @@ elem *XorAssignExp::toElem(IRState *irs)
}


/***************************************
*/

elem *PowAssignExp::toElem(IRState *irs)
{
Type *tb1 = e1->type->toBasetype();
if (tb1->ty == Tarray || tb1->ty == Tsarray)
{
error("Array operation %s not implemented", toChars());
return el_long(type->totym(), 0); // error recovery
}
else
assert(0);
}


/***************************************
*/

Expand Down Expand Up @@ -3266,6 +3282,22 @@ elem *XorExp::toElem(IRState *irs)
}


/***************************************
*/

elem *PowExp::toElem(IRState *irs)
{
Type *tb1 = e1->type->toBasetype();
if (tb1->ty == Tarray || tb1->ty == Tsarray)
{
error("Array operation %s not implemented", toChars());
return el_long(type->totym(), 0); // error recovery
}
else
assert(0);
}


/***************************************
*/

Expand Down
72 changes: 5 additions & 67 deletions src/expression.c
Original file line number Diff line number Diff line change
Expand Up @@ -10934,6 +10934,8 @@ Expression *PowExp::semantic(Scope *sc)
return e;

assert(e1->type && e2->type);
typeCombine(sc);

if (e1->op == TOKslice)
{
// Check element types are arithmetic
Expand All @@ -10957,64 +10959,14 @@ Expression *PowExp::semantic(Scope *sc)
// TODO: backend support, especially for e1 ^^ 2.

bool wantSqrt = false;
e1 = e1->optimize(0);
e2 = e2->optimize(0);

// Replace 1 ^^ x or 1.0^^x by (x, 1)
if ((e1->op == TOKint64 && e1->toInteger() == 1) ||
(e1->op == TOKfloat64 && e1->toReal() == 1.0))
{
typeCombine(sc);
e = new CommaExp(loc, e2, e1);
e = e->semantic(sc);
return e;
}
// Replace -1 ^^ x by (x&1) ? -1 : 1, where x is integral
if (e2->type->isintegral() && e1->op == TOKint64 && (sinteger_t)e1->toInteger() == -1L)
{
typeCombine(sc);
Type* resultType = type;
e = new AndExp(loc, e2, new IntegerExp(loc, 1, e2->type));
e = new CondExp(loc, e, new IntegerExp(loc, -1L, resultType), new IntegerExp(loc, 1L, resultType));
e = e->semantic(sc);
return e;
}
// Replace x ^^ 0 or x^^0.0 by (x, 1)
if ((e2->op == TOKint64 && e2->toInteger() == 0) ||
(e2->op == TOKfloat64 && e2->toReal() == 0.0))
{
if (e1->type->isintegral())
e = new IntegerExp(loc, 1, e1->type);
else
e = new RealExp(loc, 1.0, e1->type);

typeCombine(sc);
e = new CommaExp(loc, e1, e);
e = e->semantic(sc);
return e;
}
// Replace x ^^ 1 or x^^1.0 by (x)
if ((e2->op == TOKint64 && e2->toInteger() == 1) ||
(e2->op == TOKfloat64 && e2->toReal() == 1.0))
{
typeCombine(sc);
return e1;
}
// Replace x ^^ -1.0 by (1.0 / x)
if ((e2->op == TOKfloat64 && e2->toReal() == -1.0))
// First, attempt to fold the expression.
e = optimize(WANTvalue);
if (e->op != TOKpow)
{
typeCombine(sc);
e = new DivExp(loc, new RealExp(loc, 1.0, e2->type), e1);
e = e->semantic(sc);
return e;
}
// All other negative integral powers are illegal
if ((e1->type->isintegral()) && (e2->op == TOKint64) && (sinteger_t)e2->toInteger() < 0)
{
error("cannot raise %s to a negative integer power. Did you mean (cast(real)%s)^^%s ?",
e1->type->toBasetype()->toChars(), e1->toChars(), e2->toChars());
return new ErrorExp();
}

// Determine if we're raising to an integer power.
sinteger_t intpow = 0;
Expand All @@ -11026,7 +10978,6 @@ Expression *PowExp::semantic(Scope *sc)
// Deal with x^^2, x^^3 immediately, since they are of practical importance.
if (intpow == 2 || intpow == 3)
{
typeCombine(sc);
// Replace x^^2 with (tmp = x, tmp*tmp)
// Replace x^^3 with (tmp = x, tmp*tmp*tmp)
Identifier *idtmp = Lexer::uniqueId("__powtmp");
Expand Down Expand Up @@ -11067,27 +11018,14 @@ Expression *PowExp::semantic(Scope *sc)
e = new DotIdExp(loc, e, Id::math);
if (e2->op == TOKfloat64 && e2->toReal() == 0.5)
{ // Replace e1 ^^ 0.5 with .std.math.sqrt(x)
typeCombine(sc);
e = new CallExp(loc, new DotIdExp(loc, e, Id::_sqrt), e1);
}
else
{
// Replace e1 ^^ e2 with .std.math.pow(e1, e2)
// We don't combine the types if raising to an integer power (because
// integer powers are treated specially by std.math.pow).
if (!e2->type->isintegral())
typeCombine(sc);
// In fact, if it *could* have been an integer, make it one.
if (e2->op == TOKfloat64 && intpow != 0)
e2 = new IntegerExp(loc, intpow, Type::tint64);
e = new CallExp(loc, new DotIdExp(loc, e, Id::_pow), e1, e2);
}
e = e->semantic(sc);
// Always constant fold integer powers of literals. This will run the interpreter
// on .std.math.pow
if ((e1->op == TOKfloat64 || e1->op == TOKint64) && (e2->op == TOKint64))
e = e->optimize(WANTvalue | WANTinterpret);

return e;
}
incompatibleTypes();
Expand Down
20 changes: 8 additions & 12 deletions src/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -1267,6 +1267,9 @@ ASSIGNEXP(Mod)
ASSIGNEXP(And)
ASSIGNEXP(Or)
ASSIGNEXP(Xor)
#if DMDV2
ASSIGNEXP(Pow)
#endif
#undef X

#define X(a)
Expand All @@ -1279,18 +1282,6 @@ ASSIGNEXP(Cat)
#undef X
#undef ASSIGNEXP

// Only a reduced subset of operations for now.
struct PowAssignExp : BinAssignExp
{
PowAssignExp(Loc loc, Expression *e1, Expression *e2);
Expression *semantic(Scope *sc);
void buildArrayIdent(OutBuffer *buf, Expressions *arguments);
Expression *buildArrayLoop(Parameters *fparams);

// For operator overloading
Identifier *opId();
};

struct AddExp : BinExp
{
AddExp(Loc loc, Expression *e1, Expression *e2);
Expand Down Expand Up @@ -1397,12 +1388,16 @@ struct PowExp : BinExp
{
PowExp(Loc loc, Expression *e1, Expression *e2);
Expression *semantic(Scope *sc);
Expression *optimize(int result);
Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
void buildArrayIdent(OutBuffer *buf, Expressions *arguments);
Expression *buildArrayLoop(Parameters *fparams);

// For operator overloading
Identifier *opId();
Identifier *opId_r();

elem *toElem(IRState *irs);
};
#endif

Expand Down Expand Up @@ -1680,6 +1675,7 @@ Expression *Min(Type *type, Expression *e1, Expression *e2);
Expression *Mul(Type *type, Expression *e1, Expression *e2);
Expression *Div(Type *type, Expression *e1, Expression *e2);
Expression *Mod(Type *type, Expression *e1, Expression *e2);
Expression *Pow(Type *type, Expression *e1, Expression *e2);
Expression *Shl(Type *type, Expression *e1, Expression *e2);
Expression *Shr(Type *type, Expression *e1, Expression *e2);
Expression *Ushr(Type *type, Expression *e1, Expression *e2);
Expand Down
6 changes: 6 additions & 0 deletions src/interpret.c
Original file line number Diff line number Diff line change
Expand Up @@ -2356,6 +2356,9 @@ BIN_INTERPRET(Ushr)
BIN_INTERPRET(And)
BIN_INTERPRET(Or)
BIN_INTERPRET(Xor)
#if DMDV2
BIN_INTERPRET(Pow)
#endif


typedef Expression *(*fp2_t)(enum TOK, Type *, Expression *, Expression *);
Expand Down Expand Up @@ -3914,6 +3917,9 @@ BIN_ASSIGN_INTERPRET(Ushr)
BIN_ASSIGN_INTERPRET(And)
BIN_ASSIGN_INTERPRET(Or)
BIN_ASSIGN_INTERPRET(Xor)
#if DMDV2
BIN_ASSIGN_INTERPRET(Pow)
#endif

Expression *PostExp::interpret(InterState *istate, CtfeGoal goal)
{
Expand Down
65 changes: 65 additions & 0 deletions src/optimize.c
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,71 @@ Expression *XorExp::optimize(int result)
return e;
}

Expression *PowExp::optimize(int result)
{ Expression *e;

e1 = e1->optimize(result);
e2 = e2->optimize(result);

// Replace 1 ^^ x or 1.0^^x by (x, 1)
if ((e1->op == TOKint64 && e1->toInteger() == 1) ||
(e1->op == TOKfloat64 && e1->toReal() == 1.0))
{
e = new CommaExp(loc, e2, e1);
}
// Replace -1 ^^ x by (x&1) ? -1 : 1, where x is integral
else if (e2->type->isintegral() && e1->op == TOKint64 && (sinteger_t)e1->toInteger() == -1L)
{
Type* resultType = type;
e = new AndExp(loc, e2, new IntegerExp(loc, 1, e2->type));
e = new CondExp(loc, e, new IntegerExp(loc, -1L, resultType), new IntegerExp(loc, 1L, resultType));
}
// Replace x ^^ 0 or x^^0.0 by (x, 1)
else if ((e2->op == TOKint64 && e2->toInteger() == 0) ||
(e2->op == TOKfloat64 && e2->toReal() == 0.0))
{
if (e1->type->isintegral())
e = new IntegerExp(loc, 1, e1->type);
else
e = new RealExp(loc, 1.0, e1->type);

e = new CommaExp(loc, e1, e);
}
// Replace x ^^ 1 or x^^1.0 by (x)
else if ((e2->op == TOKint64 && e2->toInteger() == 1) ||
(e2->op == TOKfloat64 && e2->toReal() == 1.0))
{
e = e1;
}
// Replace x ^^ -1.0 by (1.0 / x)
else if ((e2->op == TOKfloat64 && e2->toReal() == -1.0))
{
e = new DivExp(loc, new RealExp(loc, 1.0, e2->type), e1);
}
// All other negative integral powers are illegal
else if ((e1->type->isintegral()) && (e2->op == TOKint64) && (sinteger_t)e2->toInteger() < 0)
{
error("cannot raise %s to a negative integer power. Did you mean (cast(real)%s)^^%s ?",
e1->type->toBasetype()->toChars(), e1->toChars(), e2->toChars());
e = new ErrorExp();
}
else
{
// If e2 *could* have been an integer, make it one.
if (e2->op == TOKfloat64 && (e2->toReal() == (sinteger_t)(e2->toReal())))
e2 = new IntegerExp(loc, e2->toInteger(), Type::tint64);

if (e1->isConst() == 1 && e2->isConst() == 1)
{
e = Pow(type, e1, e2);
if (e != EXP_CANT_INTERPRET)
return e;
}
e = this;
}
return e;
}

Expression *CommaExp::optimize(int result)
{ Expression *e;

Expand Down
Loading