Skip to content

Commit

Permalink
Merge pull request #1383 from donc/ctfe9170reinterpret_float_int
Browse files Browse the repository at this point in the history
9170 CTFE: Allow reinterpret casts float <-> int
  • Loading branch information
WalterBright committed Dec 18, 2012
2 parents a739c13 + 234fa18 commit ab21c35
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/ctfe.h
Expand Up @@ -182,6 +182,12 @@ int comparePointers(Loc loc, enum TOK op, Type *type, Expression *agg1, dinteger
Expression *pointerArithmetic(Loc loc, enum TOK op, Type *type,
Expression *eptr, Expression *e2);

// True if conversion from type 'from' to 'to' involves a reinterpret_cast
// floating point -> integer or integer -> floating point
bool isFloatIntPaint(Type *to, Type *from);

// Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
Expression *paintFloatInt(Expression *fromVal, Type *to);

/// Return true if t is an AA, or AssociativeArray!(key, value)
bool isAssocArray(Type *t);
Expand Down
60 changes: 60 additions & 0 deletions src/ctfeexpr.c
Expand Up @@ -760,6 +760,66 @@ int comparePointers(Loc loc, enum TOK op, Type *type, Expression *agg1, dinteger
return cmp;
}

union UnionFloatInt
{
float f;
d_int32 x;
};

union UnionDoubleLong
{
double f;
d_int64 x;
};

// True if conversion from type 'from' to 'to' involves a reinterpret_cast
// floating point -> integer or integer -> floating point
bool isFloatIntPaint(Type *to, Type *from)
{
return (from->size() == to->size()) &&
( (from->isintegral() && to->isfloating())
|| (from->isfloating() && to->isintegral()) );
}

// Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
Expression *paintFloatInt(Expression *fromVal, Type *to)
{
if (exceptionOrCantInterpret(fromVal))
return fromVal;

if (to->size() == 4)
{
UnionFloatInt u;
if (to->isintegral())
{
u.f = fromVal->toReal();
return new IntegerExp(fromVal->loc, u.x, to);
}
else
{
u.x = fromVal->toInteger();
return new RealExp(fromVal->loc, u.f, to);
}
}
else if (to->size() == 8)
{
UnionDoubleLong v;
if (to->isintegral())
{
v.f = fromVal->toReal();
return new IntegerExp(fromVal->loc, v.x, to);
}
else
{
v.x = fromVal->toInteger();
return new RealExp(fromVal->loc, v.f, to);
}
}
else
assert(0);
}


/***********************************************
Primitive integer operations
***********************************************/
Expand Down
16 changes: 16 additions & 0 deletions src/interpret.c
Expand Up @@ -4806,6 +4806,22 @@ Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal)
#if LOG
printf("%s PtrExp::interpret() %s\n", loc.toChars(), toChars());
#endif

// Check for int<->float and long<->double casts.

if ( e1->op == TOKsymoff && ((SymOffExp *)e1)->offset == 0
&& isFloatIntPaint(type, ((SymOffExp *)e1)->var->type) )
{ // *(cast(int*)&v, where v is a float variable
return paintFloatInt(getVarExp(loc, istate, ((SymOffExp *)e1)->var, ctfeNeedRvalue),
type);
}
else if (e1->op == TOKcast && ((CastExp *)e1)->e1->op == TOKaddress)
{ // *(cast(int *))&x where x is a float expression
Expression *x = ((AddrExp *)(((CastExp *)e1)->e1))->e1;
if ( isFloatIntPaint(type, x->type) )
return paintFloatInt(x->interpret(istate), type);
}

// Constant fold *(&structliteral + offset)
if (e1->op == TOKadd)
{ AddExp *ae = (AddExp *)e1;
Expand Down
50 changes: 50 additions & 0 deletions test/compilable/interpret3.d
Expand Up @@ -3329,6 +3329,56 @@ static assert(!is(typeof(compiles!(badpointer(6)))));
static assert(!is(typeof(compiles!(badpointer(7)))));
static assert(!is(typeof(compiles!(badpointer(8)))));

/**************************************************
9170 Allow reinterpret casts float<->int
**************************************************/
int f9170(float x) {
return *(cast(int*)&x);
}

float i9170(int x) {
return *(cast(float*)&x);
}

float u9170(uint x) {
return *(cast(float*)&x);
}

int f9170arr(float[] x) {
return *(cast(int*)&(x[1]));
}

long d9170(double x) {
return *(cast(long*)&x);
}

int fref9170(ref float x) {
return *(cast(int*)&x);
}

long dref9170(ref double x) {
return *(cast(long*)&x);
}

bool bug9170()
{
float f = 1.25;
double d = 1.25;
assert(f9170(f) == 0x3FA0_0000);
assert(fref9170(f) == 0x3FA0_0000);
assert(d9170(d)==0x3FF4_0000_0000_0000L);
assert(dref9170(d)==0x3FF4_0000_0000_0000L);
float [3] farr = [0, 1.25, 0];
assert(f9170arr(farr) == 0x3FA0_0000);
int i = 0x3FA0_0000;
assert(i9170(i) == 1.25);
uint u = 0x3FA0_0000;
assert(u9170(u) == 1.25);
return true;
}

static assert(bug9170());

/**************************************************
6792 ICE with pointer cast of indexed array
**************************************************/
Expand Down

0 comments on commit ab21c35

Please sign in to comment.