Skip to content

Commit

Permalink
[ARM] Implement math-related stuff in phobos
Browse files Browse the repository at this point in the history
  • Loading branch information
jpf91 committed Jan 14, 2014
1 parent a5f9ea1 commit f7bafdd
Showing 1 changed file with 164 additions and 53 deletions.
217 changes: 164 additions & 53 deletions libphobos/src/std/math.d
Original file line number Diff line number Diff line change
Expand Up @@ -2076,7 +2076,7 @@ real frexp(real value, out int exp) @trusted pure nothrow
else
{
exp = (ex - F.EXPBIAS) >> 4;
vu[F.EXPPOS_SHORT] = cast(ushort)((0x8000 & vu[F.EXPPOS_SHORT]) | 0x3FE0);
vu[F.EXPPOS_SHORT] = cast(ushort)((0x800F & vu[F.EXPPOS_SHORT]) | 0x3FE0);
}
}
else if (!(*vl & 0x7FFF_FFFF_FFFF_FFFF))
Expand Down Expand Up @@ -3580,6 +3580,14 @@ private:
{
"fstsw %%ax; andq $0x03D, %%rax;" : "=a" result;
}
else version (ARM_SoftFloat)
{
return 0;
}
else version (ARM) asm
{
"vmrs %0, FPSCR; and %0, %0, #0x1F;" : "=r" result;
}
else
assert(0, "Not yet supported");
return result;
Expand Down Expand Up @@ -3620,6 +3628,15 @@ private:
{
"fnclex;";
}
else version (ARM_SoftFloat)
{
}
else version (ARM)
{
uint old = getIeeeFlags();
old &= ~0b11111; // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0408i/Chdfifdc.html
asm {"vmsr FPSCR, %0;" : : "r" (old);}
}
else
assert(0, "Not yet supported");
}
Expand All @@ -3635,7 +3652,7 @@ private:
}
}
public:
version (X86_Any) { // TODO: Lift this version condition when we support !x86.
version (IeeeFlagsSupport) {

/// The result cannot be represented exactly, so rounding occured.
/// (example: x = sin(0.1); )
Expand All @@ -3655,7 +3672,14 @@ public:

}
}

version(X86_Any)
{
version = IeeeFlagsSupport;
}
else version(ARM)
{
version = IeeeFlagsSupport;
}

/// Set all of the floating-point status flags to false.
void resetIeeeFlags() { IeeeFlags.resetIeeeFlags(); }
Expand Down Expand Up @@ -3722,49 +3746,103 @@ struct FloatingPointControl
/** IEEE rounding modes.
* The default mode is roundToNearest.
*/
enum : RoundingMode
version(ARM)
{
enum : RoundingMode
{
roundToNearest = 0x000000,
roundDown = 0x400000,
roundUp = 0x800000,
roundToZero = 0xC00000
}
}
else
{
roundToNearest = 0x0000,
roundDown = 0x0400,
roundUp = 0x0800,
roundToZero = 0x0C00
enum : RoundingMode
{
roundToNearest = 0x0000,
roundDown = 0x0400,
roundUp = 0x0800,
roundToZero = 0x0C00
}
}

/** IEEE hardware exceptions.
* By default, all exceptions are masked (disabled).
*/
enum : uint
version(ARM)
{
inexactException = 0x20,
underflowException = 0x10,
overflowException = 0x08,
divByZeroException = 0x04,
subnormalException = 0x02,
invalidException = 0x01,
/// Severe = The overflow, division by zero, and invalid exceptions.
severeExceptions = overflowException | divByZeroException
| invalidException,
allExceptions = severeExceptions | underflowException
| inexactException | subnormalException,
enum : uint
{
subnormalException = 0x8000,
inexactException = 0x1000,
underflowException = 0x0800,
overflowException = 0x0400,
divByZeroException = 0x0200,
invalidException = 0x0100,
/// Severe = The overflow, division by zero, and invalid exceptions.
severeExceptions = overflowException | divByZeroException
| invalidException,
allExceptions = severeExceptions | underflowException
| inexactException | subnormalException,
}
}
else
{
enum : uint
{
inexactException = 0x20,
underflowException = 0x10,
overflowException = 0x08,
divByZeroException = 0x04,
subnormalException = 0x02,
invalidException = 0x01,
/// Severe = The overflow, division by zero, and invalid exceptions.
severeExceptions = overflowException | divByZeroException
| invalidException,
allExceptions = severeExceptions | underflowException
| inexactException | subnormalException,
}
}

private:
enum ushort EXCEPTION_MASK = 0x3F;
enum ushort ROUNDING_MASK = 0xC00;
version(ARM)
{
enum uint EXCEPTION_MASK = 0x9F00;
enum uint ROUNDING_MASK = 0xC00000;
}
else version(X86)
{
enum ushort EXCEPTION_MASK = 0x3F;
enum ushort ROUNDING_MASK = 0xC00;
}
else version(X86_64)
{
enum ushort EXCEPTION_MASK = 0x3F;
enum ushort ROUNDING_MASK = 0xC00;
}
else
static assert(false, "Architecture not supported");

public:
/// Enable (unmask) specific hardware exceptions. Multiple exceptions may be ORed together.
void enableExceptions(uint exceptions)
{
initialize();
setControlState(getControlState() & ~(exceptions & EXCEPTION_MASK));
version(ARM)
setControlState(getControlState() | (exceptions & EXCEPTION_MASK));
else
setControlState(getControlState() & ~(exceptions & EXCEPTION_MASK));
}

/// Disable (mask) specific hardware exceptions. Multiple exceptions may be ORed together.
void disableExceptions(uint exceptions)
{
initialize();
setControlState(getControlState() | (exceptions & EXCEPTION_MASK));
version(ARM)
setControlState(getControlState() & ~(exceptions & EXCEPTION_MASK));
else
setControlState(getControlState() | (exceptions & EXCEPTION_MASK));
}

//// Change the floating-point hardware rounding mode
Expand All @@ -3777,7 +3855,10 @@ public:
/// Return the exceptions which are currently enabled (unmasked)
@property static uint enabledExceptions()
{
return (getControlState() & EXCEPTION_MASK) ^ EXCEPTION_MASK;
version(ARM)
return (getControlState() & EXCEPTION_MASK);
else
return (getControlState() & EXCEPTION_MASK) ^ EXCEPTION_MASK;
}

/// Return the currently active rounding mode
Expand All @@ -3795,10 +3876,19 @@ public:
}

private:
ushort savedState;
ControlState savedState;

bool initialized = false;

version(ARM)
{
alias ControlState = uint;
}
else
{
alias ControlState = ushort;
}

void initialize()
{
// BUG: This works around the absence of this() constructors.
Expand Down Expand Up @@ -3828,6 +3918,15 @@ private:
{
"fclex;";
}
else version (ARM_SoftFloat)
{
}
else version (ARM)
{
uint old = getControlState();
old &= ~0b11111; // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0408i/Chdfifdc.html
asm {"vmsr FPSCR, %0;" : : "r" (old);}
}
else
assert(0, "Not yet supported");
}
Expand All @@ -3836,7 +3935,7 @@ private:
}

// Read from the control register
static ushort getControlState() @trusted nothrow
static ControlState getControlState() @trusted nothrow
{
version (D_InlineAsm_X86)
{
Expand All @@ -3862,7 +3961,7 @@ private:
else
version (GNU)
{
short cont;
ControlState cont;
version (X86) asm
{
"xor %%eax, %%eax; fstcw %[cw];" : [cw] "=m" cont :: "eax";
Expand All @@ -3871,12 +3970,14 @@ private:
{
"xor %%rax, %%rax; fstcw %[cw];" : [cw] "=m" cont :: "rax";
}
else version (ARM) asm
else version (ARM)
{
"mrc p10, 7, %[cw], cr1, cr0, 0"
:
[cw] "=r" cont
;
version (ARM_SoftFloat)
return 0;
else asm
{
"vmrs %0, FPSCR;" : "=r" cont;
}
}
else
assert(0, "Not yet supported");
Expand All @@ -3887,7 +3988,7 @@ private:
}

// Set the control register
static void setControlState(ushort newState) @trusted nothrow
static void setControlState(ControlState newState) @trusted nothrow
{
version (InlineAsm_X86_Any)
{
Expand Down Expand Up @@ -3915,27 +4016,20 @@ private:
{
version (X86) asm
{
"fclex; fldcw %[cw]"
:
:
[cw] "m" newState
;
"fclex; fldcw %[cw]" : : [cw] "m" newState;
}
else version (X86_64) asm
{
"fclex; fldcw %[cw]"
:
:
[cw] "m" newState
;
"fclex; fldcw %[cw]" : : [cw] "m" newState;
}
else version (ARM) asm
else version (ARM)
{
"mcr p10, 7, %[cw], cr1, cr0, 0"
:
:
[cw] "r" newState
;
version (ARM_SoftFloat)
return;
else asm
{
"vmsr FPSCR, %0;" : : "r" (newState);
}
}
else
assert(0, "Not yet supported");
Expand All @@ -3947,6 +4041,11 @@ private:

unittest
{
//GCC floating point emulation doesn't allow changing
//rounding modes, getting error bits etc
version(GNU) version(D_SoftFloat)
return;

void ensureDefaults()
{
assert(FloatingPointControl.rounding
Expand Down Expand Up @@ -4180,7 +4279,7 @@ bool isInfinity(real x) @trusted pure nothrow
{
// double
return ((*cast(ulong *)&x) & 0x7FFF_FFFF_FFFF_FFFF)
== 0x7FF8_0000_0000_0000;
== 0x7FF0000000000000;
}
else static if(real.mant_dig == 106)
{
Expand Down Expand Up @@ -4341,12 +4440,13 @@ real NaN(ulong payload) @trusted pure nothrow
{
static if (real.mant_dig == 64)
{
//real80
//real80 (in x86 real format, the implied bit is actually
//not implied but a real bit which is stored in the real)
ulong v = 3; // implied bit = 1, quiet bit = 1
}
else
{
ulong v = 2; // no implied bit. quiet bit = 1
ulong v = 1; // no implied bit. quiet bit = 1
}

ulong a = payload;
Expand Down Expand Up @@ -4409,6 +4509,17 @@ real NaN(ulong payload) @trusted pure nothrow
}
}

unittest
{
static if (real.mant_dig == 53)
{
auto x = NaN(1);
auto xl = *cast(ulong*)&x;
assert(xl & 0x8_0000_0000_0000UL); //non-signaling bit, bit 52
assert((xl & 0x7FF0_0000_0000_0000UL) == 0x7FF0_0000_0000_0000UL); //all exp bits set
}
}

/**
* Extract an integral payload from a $(NAN).
*
Expand Down

0 comments on commit f7bafdd

Please sign in to comment.