Skip to content

Commit

Permalink
[PATCH] ARM: 2837/2: Re: ARM: Make NWFPE preempt safe
Browse files Browse the repository at this point in the history
Patch from Richard Purdie

NWFPE used global variables which meant it wasn't safe for use with
preemptive kernels. This patch removes them and communicates the
information between functions in a preempt safe manner. Generation
of some exceptions was broken and this has also been corrected.
Tests with glibc's maths test suite show no change in the results
before/after this patch.

Signed-off-by: Richard Purdie <rpurdie@rpsys.net>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Richard Purdie authored and Russell King committed Aug 3, 2005
1 parent 1fcf844 commit f148af2
Show file tree
Hide file tree
Showing 11 changed files with 304 additions and 304 deletions.
24 changes: 12 additions & 12 deletions arch/arm/nwfpe/double_cpdo.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,17 @@ float64 float64_arccos(float64 rFm);
float64 float64_pow(float64 rFn, float64 rFm);
float64 float64_pol(float64 rFn, float64 rFm);

static float64 float64_rsf(float64 rFn, float64 rFm)
static float64 float64_rsf(struct roundingData *roundData, float64 rFn, float64 rFm)
{
return float64_sub(rFm, rFn);
return float64_sub(roundData, rFm, rFn);
}

static float64 float64_rdv(float64 rFn, float64 rFm)
static float64 float64_rdv(struct roundingData *roundData, float64 rFn, float64 rFm)
{
return float64_div(rFm, rFn);
return float64_div(roundData, rFm, rFn);
}

static float64 (*const dyadic_double[16])(float64 rFn, float64 rFm) = {
static float64 (*const dyadic_double[16])(struct roundingData*, float64 rFn, float64 rFm) = {
[ADF_CODE >> 20] = float64_add,
[MUF_CODE >> 20] = float64_mul,
[SUF_CODE >> 20] = float64_sub,
Expand All @@ -65,12 +65,12 @@ static float64 (*const dyadic_double[16])(float64 rFn, float64 rFm) = {
[FRD_CODE >> 20] = float64_rdv,
};

static float64 float64_mvf(float64 rFm)
static float64 float64_mvf(struct roundingData *roundData,float64 rFm)
{
return rFm;
}

static float64 float64_mnf(float64 rFm)
static float64 float64_mnf(struct roundingData *roundData,float64 rFm)
{
union float64_components u;

Expand All @@ -84,7 +84,7 @@ static float64 float64_mnf(float64 rFm)
return u.f64;
}

static float64 float64_abs(float64 rFm)
static float64 float64_abs(struct roundingData *roundData,float64 rFm)
{
union float64_components u;

Expand All @@ -98,7 +98,7 @@ static float64 float64_abs(float64 rFm)
return u.f64;
}

static float64 (*const monadic_double[16])(float64 rFm) = {
static float64 (*const monadic_double[16])(struct roundingData *, float64 rFm) = {
[MVF_CODE >> 20] = float64_mvf,
[MNF_CODE >> 20] = float64_mnf,
[ABS_CODE >> 20] = float64_abs,
Expand All @@ -108,7 +108,7 @@ static float64 (*const monadic_double[16])(float64 rFm) = {
[NRM_CODE >> 20] = float64_mvf,
};

unsigned int DoubleCPDO(const unsigned int opcode, FPREG * rFd)
unsigned int DoubleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd)
{
FPA11 *fpa11 = GET_FPA11();
float64 rFm;
Expand Down Expand Up @@ -151,13 +151,13 @@ unsigned int DoubleCPDO(const unsigned int opcode, FPREG * rFd)
}

if (dyadic_double[opc_mask_shift]) {
rFd->fDouble = dyadic_double[opc_mask_shift](rFn, rFm);
rFd->fDouble = dyadic_double[opc_mask_shift](roundData, rFn, rFm);
} else {
return 0;
}
} else {
if (monadic_double[opc_mask_shift]) {
rFd->fDouble = monadic_double[opc_mask_shift](rFm);
rFd->fDouble = monadic_double[opc_mask_shift](roundData, rFm);
} else {
return 0;
}
Expand Down
24 changes: 12 additions & 12 deletions arch/arm/nwfpe/extended_cpdo.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,17 @@ floatx80 floatx80_arccos(floatx80 rFm);
floatx80 floatx80_pow(floatx80 rFn, floatx80 rFm);
floatx80 floatx80_pol(floatx80 rFn, floatx80 rFm);

static floatx80 floatx80_rsf(floatx80 rFn, floatx80 rFm)
static floatx80 floatx80_rsf(struct roundingData *roundData, floatx80 rFn, floatx80 rFm)
{
return floatx80_sub(rFm, rFn);
return floatx80_sub(roundData, rFm, rFn);
}

static floatx80 floatx80_rdv(floatx80 rFn, floatx80 rFm)
static floatx80 floatx80_rdv(struct roundingData *roundData, floatx80 rFn, floatx80 rFm)
{
return floatx80_div(rFm, rFn);
return floatx80_div(roundData, rFm, rFn);
}

static floatx80 (*const dyadic_extended[16])(floatx80 rFn, floatx80 rFm) = {
static floatx80 (*const dyadic_extended[16])(struct roundingData*, floatx80 rFn, floatx80 rFm) = {
[ADF_CODE >> 20] = floatx80_add,
[MUF_CODE >> 20] = floatx80_mul,
[SUF_CODE >> 20] = floatx80_sub,
Expand All @@ -60,24 +60,24 @@ static floatx80 (*const dyadic_extended[16])(floatx80 rFn, floatx80 rFm) = {
[FRD_CODE >> 20] = floatx80_rdv,
};

static floatx80 floatx80_mvf(floatx80 rFm)
static floatx80 floatx80_mvf(struct roundingData *roundData, floatx80 rFm)
{
return rFm;
}

static floatx80 floatx80_mnf(floatx80 rFm)
static floatx80 floatx80_mnf(struct roundingData *roundData, floatx80 rFm)
{
rFm.high ^= 0x8000;
return rFm;
}

static floatx80 floatx80_abs(floatx80 rFm)
static floatx80 floatx80_abs(struct roundingData *roundData, floatx80 rFm)
{
rFm.high &= 0x7fff;
return rFm;
}

static floatx80 (*const monadic_extended[16])(floatx80 rFm) = {
static floatx80 (*const monadic_extended[16])(struct roundingData*, floatx80 rFm) = {
[MVF_CODE >> 20] = floatx80_mvf,
[MNF_CODE >> 20] = floatx80_mnf,
[ABS_CODE >> 20] = floatx80_abs,
Expand All @@ -87,7 +87,7 @@ static floatx80 (*const monadic_extended[16])(floatx80 rFm) = {
[NRM_CODE >> 20] = floatx80_mvf,
};

unsigned int ExtendedCPDO(const unsigned int opcode, FPREG * rFd)
unsigned int ExtendedCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd)
{
FPA11 *fpa11 = GET_FPA11();
floatx80 rFm;
Expand Down Expand Up @@ -138,13 +138,13 @@ unsigned int ExtendedCPDO(const unsigned int opcode, FPREG * rFd)
}

if (dyadic_extended[opc_mask_shift]) {
rFd->fExtended = dyadic_extended[opc_mask_shift](rFn, rFm);
rFd->fExtended = dyadic_extended[opc_mask_shift](roundData, rFn, rFm);
} else {
return 0;
}
} else {
if (monadic_extended[opc_mask_shift]) {
rFd->fExtended = monadic_extended[opc_mask_shift](rFm);
rFd->fExtended = monadic_extended[opc_mask_shift](roundData, rFm);
} else {
return 0;
}
Expand Down
30 changes: 11 additions & 19 deletions arch/arm/nwfpe/fpa11.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,48 +51,42 @@ static void resetFPA11(void)
fpa11->fpsr = FP_EMULATOR | BIT_AC;
}

void SetRoundingMode(const unsigned int opcode)
int8 SetRoundingMode(const unsigned int opcode)
{
switch (opcode & MASK_ROUNDING_MODE) {
default:
case ROUND_TO_NEAREST:
float_rounding_mode = float_round_nearest_even;
break;
return float_round_nearest_even;

case ROUND_TO_PLUS_INFINITY:
float_rounding_mode = float_round_up;
break;
return float_round_up;

case ROUND_TO_MINUS_INFINITY:
float_rounding_mode = float_round_down;
break;
return float_round_down;

case ROUND_TO_ZERO:
float_rounding_mode = float_round_to_zero;
break;
return float_round_to_zero;
}
}

void SetRoundingPrecision(const unsigned int opcode)
int8 SetRoundingPrecision(const unsigned int opcode)
{
#ifdef CONFIG_FPE_NWFPE_XP
switch (opcode & MASK_ROUNDING_PRECISION) {
case ROUND_SINGLE:
floatx80_rounding_precision = 32;
break;
return 32;

case ROUND_DOUBLE:
floatx80_rounding_precision = 64;
break;
return 64;

case ROUND_EXTENDED:
floatx80_rounding_precision = 80;
break;
return 80;

default:
floatx80_rounding_precision = 80;
return 80;
}
#endif
return 80;
}

void nwfpe_init_fpa(union fp_state *fp)
Expand All @@ -103,8 +97,6 @@ void nwfpe_init_fpa(union fp_state *fp)
#endif
memset(fpa11, 0, sizeof(FPA11));
resetFPA11();
SetRoundingMode(ROUND_TO_NEAREST);
SetRoundingPrecision(ROUND_EXTENDED);
fpa11->initflag = 1;
}

Expand Down
11 changes: 9 additions & 2 deletions arch/arm/nwfpe/fpa11.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@
/* includes */
#include "fpsr.h" /* FP control and status register definitions */
#include "milieu.h"

struct roundingData {
int8 mode;
int8 precision;
signed char exception;
};

#include "softfloat.h"

#define typeNone 0x00
Expand Down Expand Up @@ -84,8 +91,8 @@ typedef struct tagFPA11 {
initialised. */
} FPA11;

extern void SetRoundingMode(const unsigned int);
extern void SetRoundingPrecision(const unsigned int);
extern int8 SetRoundingMode(const unsigned int);
extern int8 SetRoundingPrecision(const unsigned int);
extern void nwfpe_init_fpa(union fp_state *fp);

#endif
28 changes: 17 additions & 11 deletions arch/arm/nwfpe/fpa11_cpdo.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,26 @@
#include "fpa11.h"
#include "fpopcode.h"

unsigned int SingleCPDO(const unsigned int opcode, FPREG * rFd);
unsigned int DoubleCPDO(const unsigned int opcode, FPREG * rFd);
unsigned int ExtendedCPDO(const unsigned int opcode, FPREG * rFd);
unsigned int SingleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
unsigned int DoubleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
unsigned int ExtendedCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);

unsigned int EmulateCPDO(const unsigned int opcode)
{
FPA11 *fpa11 = GET_FPA11();
FPREG *rFd;
unsigned int nType, nDest, nRc;
struct roundingData roundData;

/* Get the destination size. If not valid let Linux perform
an invalid instruction trap. */
nDest = getDestinationSize(opcode);
if (typeNone == nDest)
return 0;

SetRoundingMode(opcode);
roundData.mode = SetRoundingMode(opcode);
roundData.precision = SetRoundingPrecision(opcode);
roundData.exception = 0;

/* Compare the size of the operands in Fn and Fm.
Choose the largest size and perform operations in that size,
Expand All @@ -63,14 +66,14 @@ unsigned int EmulateCPDO(const unsigned int opcode)

switch (nType) {
case typeSingle:
nRc = SingleCPDO(opcode, rFd);
nRc = SingleCPDO(&roundData, opcode, rFd);
break;
case typeDouble:
nRc = DoubleCPDO(opcode, rFd);
nRc = DoubleCPDO(&roundData, opcode, rFd);
break;
#ifdef CONFIG_FPE_NWFPE_XP
case typeExtended:
nRc = ExtendedCPDO(opcode, rFd);
nRc = ExtendedCPDO(&roundData, opcode, rFd);
break;
#endif
default:
Expand All @@ -93,9 +96,9 @@ unsigned int EmulateCPDO(const unsigned int opcode)
case typeSingle:
{
if (typeDouble == nType)
rFd->fSingle = float64_to_float32(rFd->fDouble);
rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);
else
rFd->fSingle = floatx80_to_float32(rFd->fExtended);
rFd->fSingle = floatx80_to_float32(&roundData, rFd->fExtended);
}
break;

Expand All @@ -104,7 +107,7 @@ unsigned int EmulateCPDO(const unsigned int opcode)
if (typeSingle == nType)
rFd->fDouble = float32_to_float64(rFd->fSingle);
else
rFd->fDouble = floatx80_to_float64(rFd->fExtended);
rFd->fDouble = floatx80_to_float64(&roundData, rFd->fExtended);
}
break;

Expand All @@ -121,12 +124,15 @@ unsigned int EmulateCPDO(const unsigned int opcode)
#else
if (nDest != nType) {
if (nDest == typeSingle)
rFd->fSingle = float64_to_float32(rFd->fDouble);
rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);
else
rFd->fDouble = float32_to_float64(rFd->fSingle);
}
#endif
}

if (roundData.exception)
float_raise(roundData.exception);

return nRc;
}
Loading

0 comments on commit f148af2

Please sign in to comment.