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

9170 CTFE: Allow reinterpret casts float <-> int #1383

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
6 changes: 6 additions & 0 deletions src/ctfe.h
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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