Skip to content

Commit

Permalink
ARM: The Simulator will now handle different VFP rounding modes. RZ a…
Browse files Browse the repository at this point in the history
…nd RM are implemented. This is a commit of

http://codereview.chromium.org/4295003/show for Alexander Rames of ARM.

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@5790 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
  • Loading branch information
erik.corry@gmail.com committed Nov 9, 2010
1 parent cfcad56 commit 30c5dc9
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 26 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Expand Up @@ -9,6 +9,7 @@ ARM Ltd.
Hewlett-Packard Development Company, LP

Alexander Botero-Lowry <alexbl@FreeBSD.org>
Alexandre Rames <alexandre.rames@arm.com>
Alexandre Vassalotti <avassalotti@gmail.com>
Andreas Anyuru <andreas.anyuru@gmail.com>
Burcu Dogan <burcujdogan@gmail.com>
Expand Down
35 changes: 26 additions & 9 deletions src/arm/assembler-arm.cc
Expand Up @@ -2144,6 +2144,7 @@ static Instr EncodeVCVT(const VFPType dst_type,
const int dst_code,
const VFPType src_type,
const int src_code,
Assembler::ConversionMode mode,
const Condition cond) {
ASSERT(src_type != dst_type);
int D, Vd, M, Vm;
Expand All @@ -2162,7 +2163,7 @@ static Instr EncodeVCVT(const VFPType dst_type,
if (IsIntegerVFPType(dst_type)) {
opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4;
sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
op = 1; // round towards zero
op = mode;
} else {
ASSERT(IsIntegerVFPType(src_type));
opc2 = 0x0;
Expand All @@ -2186,57 +2187,64 @@ static Instr EncodeVCVT(const VFPType dst_type,

void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(F64, dst.code(), S32, src.code(), cond));
emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond));
}


void Assembler::vcvt_f32_s32(const SwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(F32, dst.code(), S32, src.code(), cond));
emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond));
}


void Assembler::vcvt_f64_u32(const DwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(F64, dst.code(), U32, src.code(), cond));
emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond));
}


void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(S32, dst.code(), F64, src.code(), cond));
emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond));
}


void Assembler::vcvt_u32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(U32, dst.code(), F64, src.code(), cond));
emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond));
}


void Assembler::vcvt_f64_f32(const DwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(F64, dst.code(), F32, src.code(), cond));
emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond));
}


void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(F32, dst.code(), F64, src.code(), cond));
emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond));
}


Expand Down Expand Up @@ -2329,6 +2337,16 @@ void Assembler::vcmp(const DwVfpRegister src1,
}


void Assembler::vmsr(Register dst, Condition cond) {
// Instruction details available in ARM DDI 0406A, A8-652.
// cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
// Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(cond | 0xE*B24 | 0xE*B20 | B16 |
dst.code()*B12 | 0xA*B8 | B4);
}


void Assembler::vmrs(Register dst, Condition cond) {
// Instruction details available in ARM DDI 0406A, A8-652.
// cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
Expand All @@ -2339,7 +2357,6 @@ void Assembler::vmrs(Register dst, Condition cond) {
}



void Assembler::vsqrt(const DwVfpRegister dst,
const DwVfpRegister src,
const Condition cond) {
Expand Down
13 changes: 13 additions & 0 deletions src/arm/assembler-arm.h
Expand Up @@ -1008,26 +1008,37 @@ class Assembler : public Malloced {
void vmov(const Register dst,
const SwVfpRegister src,
const Condition cond = al);
enum ConversionMode {
FPSCRRounding = 0,
RoundToZero = 1
};
void vcvt_f64_s32(const DwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vcvt_f32_s32(const SwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vcvt_f64_u32(const DwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vcvt_s32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vcvt_u32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vcvt_f64_f32(const DwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vcvt_f32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);

void vadd(const DwVfpRegister dst,
Expand Down Expand Up @@ -1056,6 +1067,8 @@ class Assembler : public Malloced {
const Condition cond = al);
void vmrs(const Register dst,
const Condition cond = al);
void vmsr(const Register dst,
const Condition cond = al);
void vsqrt(const DwVfpRegister dst,
const DwVfpRegister src,
const Condition cond = al);
Expand Down
7 changes: 7 additions & 0 deletions src/arm/constants-arm.h
Expand Up @@ -206,6 +206,13 @@ enum VFPRegPrecision {
kDoublePrecision = 1
};

// VFP rounding modes. See ARM DDI 0406B Page A2-29.
enum FPSCRRoundingModes {
RN, // Round to Nearest.
RP, // Round towards Plus Infinity.
RM, // Round towards Minus Infinity.
RZ // Round towards zero.
};

typedef int32_t instr_t;

Expand Down
4 changes: 2 additions & 2 deletions src/arm/ic-arm.cc
Expand Up @@ -1988,9 +1988,9 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,

// Not infinity or NaN simply convert to int.
if (IsElementTypeSigned(array_type)) {
__ vcvt_s32_f64(s0, d0, ne);
__ vcvt_s32_f64(s0, d0, Assembler::RoundToZero, ne);
} else {
__ vcvt_u32_f64(s0, d0, ne);
__ vcvt_u32_f64(s0, d0, Assembler::RoundToZero, ne);
}
__ vmov(r5, s0, ne);

Expand Down
108 changes: 93 additions & 15 deletions src/arm/simulator-arm.cc
Expand Up @@ -705,6 +705,7 @@ Simulator::Simulator() {
z_flag_FPSCR_ = false;
c_flag_FPSCR_ = false;
v_flag_FPSCR_ = false;
FPSCR_rounding_mode_ = RZ;

inv_op_vfp_flag_ = false;
div_zero_vfp_flag_ = false;
Expand Down Expand Up @@ -2501,10 +2502,45 @@ void Simulator::DecodeTypeVFP(Instr* instr) {
(instr->VAField() == 0x7) &&
(instr->Bits(19, 16) == 0x1)) {
// vmrs
if (instr->RtField() == 0xF)
uint32_t rt = instr->RtField();
if (rt == 0xF) {
Copy_FPSCR_to_APSR();
else
UNIMPLEMENTED(); // Not used by V8.
} else {
// Emulate FPSCR from the Simulator flags.
uint32_t fpscr = (n_flag_FPSCR_ << 31) |
(z_flag_FPSCR_ << 30) |
(c_flag_FPSCR_ << 29) |
(v_flag_FPSCR_ << 28) |
(inexact_vfp_flag_ << 4) |
(underflow_vfp_flag_ << 3) |
(overflow_vfp_flag_ << 2) |
(div_zero_vfp_flag_ << 1) |
(inv_op_vfp_flag_ << 0) |
(FPSCR_rounding_mode_ << 22);
set_register(rt, fpscr);
}
} else if ((instr->VLField() == 0x0) &&
(instr->VCField() == 0x0) &&
(instr->VAField() == 0x7) &&
(instr->Bits(19, 16) == 0x1)) {
// vmsr
uint32_t rt = instr->RtField();
if (rt == pc) {
UNREACHABLE();
} else {
uint32_t rt_value = get_register(rt);
n_flag_FPSCR_ = (rt_value >> 31) & 1;
z_flag_FPSCR_ = (rt_value >> 30) & 1;
c_flag_FPSCR_ = (rt_value >> 29) & 1;
v_flag_FPSCR_ = (rt_value >> 28) & 1;
inexact_vfp_flag_ = (rt_value >> 4) & 1;
underflow_vfp_flag_ = (rt_value >> 3) & 1;
overflow_vfp_flag_ = (rt_value >> 2) & 1;
div_zero_vfp_flag_ = (rt_value >> 1) & 1;
inv_op_vfp_flag_ = (rt_value >> 0) & 1;
FPSCR_rounding_mode_ =
static_cast<FPSCRRoundingModes>((rt_value >> 22) & 3);
}
} else {
UNIMPLEMENTED(); // Not used by V8.
}
Expand Down Expand Up @@ -2605,29 +2641,71 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) {

if (to_integer) {
bool unsigned_integer = (instr->Bit(16) == 0);
FPSCRRoundingModes mode;
if (instr->Bit(7) != 1) {
// Only rounding towards zero supported.
UNIMPLEMENTED(); // Not used by V8.
// Use FPSCR defined rounding mode.
mode = FPSCR_rounding_mode_;
// Only RZ and RM modes are supported.
ASSERT((mode == RM) || (mode == RZ));
} else {
// VFP uses round towards zero by default.
mode = RZ;
}

int dst = instr->VFPDRegCode(kSinglePrecision);
int src = instr->VFPMRegCode(src_precision);
int32_t kMaxInt = v8::internal::kMaxInt;
int32_t kMinInt = v8::internal::kMinInt;
switch (mode) {
case RM:
if (src_precision == kDoublePrecision) {
double val = get_double_from_d_register(src);

if (src_precision == kDoublePrecision) {
double val = get_double_from_d_register(src);
inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);

int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
sint = sint > val ? sint - 1 : sint;

set_s_register_from_sinteger(dst, sint);
} else {
float val = get_float_from_s_register(src);
set_s_register_from_sinteger(dst, sint);
} else {
float val = get_float_from_s_register(src);

inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);

int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
sint = sint > val ? sint - 1 : sint;

set_s_register_from_sinteger(dst, sint);
set_s_register_from_sinteger(dst, sint);
}
break;
case RZ:
if (src_precision == kDoublePrecision) {
double val = get_double_from_d_register(src);

inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);

int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);

set_s_register_from_sinteger(dst, sint);
} else {
float val = get_float_from_s_register(src);

inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);

int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);

set_s_register_from_sinteger(dst, sint);
}
break;

default:
UNREACHABLE();
}

} else {
bool unsigned_integer = (instr->Bit(7) == 0);

Expand Down
3 changes: 3 additions & 0 deletions src/arm/simulator-arm.h
Expand Up @@ -306,6 +306,9 @@ class Simulator {
bool c_flag_FPSCR_;
bool v_flag_FPSCR_;

// VFP rounding mode. See ARM DDI 0406B Page A2-29.
FPSCRRoundingModes FPSCR_rounding_mode_;

// VFP FP exception flags architecture state.
bool inv_op_vfp_flag_;
bool div_zero_vfp_flag_;
Expand Down

0 comments on commit 30c5dc9

Please sign in to comment.