Commit 3ae4a987 authored by Milad Farazmand's avatar Milad Farazmand Committed by Commit Bot

PPC/s390: [turbofan][wasm] Improved float32 to int32.

Port 51b53dd3

R=rstz@chromium.org, joransiu@ca.ibm.com, jyan@ca.ibm.com, michael_dawson@ca.ibm.com
BUG=
LOG=N

Change-Id: Ic2ee6e75afd5da8bb7f35dfde4b1d85231f1cf4a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2318045Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarJunliang Yan <jyan@ca.ibm.com>
Commit-Queue: Milad Farazmand <miladfar@ca.ibm.com>
Cr-Commit-Position: refs/heads/master@{#69100}
parent 94cf4347
......@@ -1631,6 +1631,10 @@ void Assembler::fctiw(const DoubleRegister frt, const DoubleRegister frb) {
emit(EXT4 | FCTIW | frt.code() * B21 | frb.code() * B11);
}
void Assembler::fctiwuz(const DoubleRegister frt, const DoubleRegister frb) {
emit(EXT4 | FCTIWUZ | frt.code() * B21 | frb.code() * B11);
}
void Assembler::frin(const DoubleRegister frt, const DoubleRegister frb,
RCBit rc) {
emit(EXT4 | FRIN | frt.code() * B21 | frb.code() * B11 | rc);
......
......@@ -966,6 +966,7 @@ class Assembler : public AssemblerBase {
RCBit rc = LeaveRC);
void fctiwz(const DoubleRegister frt, const DoubleRegister frb);
void fctiw(const DoubleRegister frt, const DoubleRegister frb);
void fctiwuz(const DoubleRegister frt, const DoubleRegister frb);
void frin(const DoubleRegister frt, const DoubleRegister frb,
RCBit rc = LeaveRC);
void friz(const DoubleRegister frt, const DoubleRegister frb,
......
......@@ -1852,17 +1852,42 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
DCHECK_EQ(LeaveRC, i.OutputRCBit());
break;
case kPPC_Float32ToInt32: {
__ mtfsb0(VXCVI); // clear FPSCR:VXCVI bit
bool set_overflow_to_min_i32 = MiscField::decode(instr->opcode());
if (set_overflow_to_min_i32) {
__ mtfsb0(VXCVI); // clear FPSCR:VXCVI bit
}
__ fctiwz(kScratchDoubleReg, i.InputDoubleRegister(0));
__ MovDoubleLowToInt(i.OutputRegister(), kScratchDoubleReg);
// Use INT32_MIN s an overflow indicator because it allows for easier
// out-of-bounds detection.
CRegister cr = cr7;
int crbit = v8::internal::Assembler::encode_crbit(
cr, static_cast<CRBit>(VXCVI % CRWIDTH));
__ mcrfs(cr, VXCVI); // extract FPSCR field containing VXCVI into cr7
__ lis(kScratchReg, Operand(static_cast<int16_t>(0x8000)));
__ isel(i.OutputRegister(0), kScratchReg, i.OutputRegister(0), crbit);
if (set_overflow_to_min_i32) {
// Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead,
// because INT32_MIN allows easier out-of-bounds detection.
CRegister cr = cr7;
int crbit = v8::internal::Assembler::encode_crbit(
cr, static_cast<CRBit>(VXCVI % CRWIDTH));
__ mcrfs(cr, VXCVI); // extract FPSCR field containing VXCVI into cr7
__ li(kScratchReg, Operand(1));
__ sldi(kScratchReg, kScratchReg, Operand(31)); // generate INT32_MIN.
__ isel(i.OutputRegister(0), kScratchReg, i.OutputRegister(0), crbit);
}
break;
}
case kPPC_Float32ToUint32: {
bool set_overflow_to_min_u32 = MiscField::decode(instr->opcode());
if (set_overflow_to_min_u32) {
__ mtfsb0(VXCVI); // clear FPSCR:VXCVI bit
}
__ fctiwuz(kScratchDoubleReg, i.InputDoubleRegister(0));
__ MovDoubleLowToInt(i.OutputRegister(), kScratchDoubleReg);
if (set_overflow_to_min_u32) {
// Avoid UINT32_MAX as an overflow indicator and use 0 instead,
// because 0 allows easier out-of-bounds detection.
CRegister cr = cr7;
int crbit = v8::internal::Assembler::encode_crbit(
cr, static_cast<CRBit>(VXCVI % CRWIDTH));
__ mcrfs(cr, VXCVI); // extract FPSCR field containing VXCVI into cr7
__ li(kScratchReg, Operand::Zero());
__ isel(i.OutputRegister(0), kScratchReg, i.OutputRegister(0), crbit);
}
break;
}
case kPPC_DoubleToInt32:
......
......@@ -96,6 +96,7 @@ namespace compiler {
V(PPC_Int32ToDouble) \
V(PPC_Uint32ToFloat32) \
V(PPC_Float32ToInt32) \
V(PPC_Float32ToUint32) \
V(PPC_Uint32ToDouble) \
V(PPC_Float32ToDouble) \
V(PPC_Float64SilenceNaN) \
......
......@@ -93,6 +93,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kPPC_Uint32ToFloat32:
case kPPC_Uint32ToDouble:
case kPPC_Float32ToInt32:
case kPPC_Float32ToUint32:
case kPPC_Float32ToDouble:
case kPPC_Float64SilenceNaN:
case kPPC_DoubleToInt32:
......
......@@ -1227,11 +1227,27 @@ void InstructionSelector::VisitRoundFloat64ToInt32(Node* node) {
}
void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
VisitRR(this, kPPC_Float32ToInt32, node);
PPCOperandGenerator g(this);
InstructionCode opcode = kPPC_Float32ToInt32;
TruncateKind kind = OpParameter<TruncateKind>(node->op());
if (kind == TruncateKind::kSetOverflowToMin) {
opcode |= MiscField::encode(true);
}
Emit(opcode, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
VisitRR(this, kPPC_DoubleToUint32, node);
PPCOperandGenerator g(this);
InstructionCode opcode = kPPC_Float32ToUint32;
TruncateKind kind = OpParameter<TruncateKind>(node->op());
if (kind == TruncateKind::kSetOverflowToMin) {
opcode |= MiscField::encode(true);
}
Emit(opcode, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
}
#if V8_TARGET_ARCH_PPC64
......
......@@ -2420,10 +2420,13 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
Label done;
__ ConvertFloat32ToInt32(i.OutputRegister(0), i.InputDoubleRegister(0),
kRoundToZero);
__ b(Condition(0xE), &done, Label::kNear); // normal case
// Use INT32_MIN s an overflow indicator because it allows for easier
// out-of-bounds detection.
__ llilh(i.OutputRegister(0), Operand(0x8000));
bool set_overflow_to_min_i32 = MiscField::decode(instr->opcode());
if (set_overflow_to_min_i32) {
// Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead,
// because INT32_MIN allows easier out-of-bounds detection.
__ b(Condition(0xE), &done, Label::kNear); // normal case
__ llilh(i.OutputRegister(0), Operand(0x8000));
}
__ bind(&done);
break;
}
......@@ -2431,8 +2434,13 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
Label done;
__ ConvertFloat32ToUnsignedInt32(i.OutputRegister(0),
i.InputDoubleRegister(0));
__ b(Condition(0xE), &done, Label::kNear); // normal case
__ lghi(i.OutputRegister(0), Operand::Zero());
bool set_overflow_to_min_u32 = MiscField::decode(instr->opcode());
if (set_overflow_to_min_u32) {
// Avoid UINT32_MAX as an overflow indicator and use 0 instead,
// because 0 allows easier out-of-bounds detection.
__ b(Condition(0xE), &done, Label::kNear); // normal case
__ lghi(i.OutputRegister(0), Operand::Zero());
}
__ bind(&done);
break;
}
......
......@@ -1392,10 +1392,6 @@ static inline bool TryMatchDoubleConstructFromInsert(
OperandMode::kNone, null) \
V(Float64, RoundFloat64ToInt32, kS390_DoubleToInt32, OperandMode::kNone, \
null) \
V(Float32, TruncateFloat32ToInt32, kS390_Float32ToInt32, OperandMode::kNone, \
null) \
V(Float32, TruncateFloat32ToUint32, kS390_Float32ToUint32, \
OperandMode::kNone, null) \
V(Float64, TruncateFloat64ToUint32, kS390_DoubleToUint32, \
OperandMode::kNone, null) \
V(Float64, ChangeFloat64ToInt32, kS390_DoubleToInt32, OperandMode::kNone, \
......@@ -2932,6 +2928,30 @@ void InstructionSelector::VisitLoadTransform(Node* node) {
UNREACHABLE();
}
void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) {
S390OperandGenerator g(this);
InstructionCode opcode = kS390_Float32ToInt32;
TruncateKind kind = OpParameter<TruncateKind>(node->op());
if (kind == TruncateKind::kSetOverflowToMin) {
opcode |= MiscField::encode(true);
}
Emit(opcode, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) {
S390OperandGenerator g(this);
InstructionCode opcode = kS390_Float32ToUint32;
TruncateKind kind = OpParameter<TruncateKind>(node->op());
if (kind == TruncateKind::kSetOverflowToMin) {
opcode |= MiscField::encode(true);
}
Emit(opcode, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
}
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
......
......@@ -1142,6 +1142,10 @@ void Decoder::DecodeExt4(Instruction* instr) {
Format(instr, "fctiwz'. 'Dt, 'Db");
break;
}
case FCTIWUZ: {
Format(instr, "fctiwuz 'Dt, 'Db");
break;
}
case FMR: {
Format(instr, "fmr'. 'Dt, 'Db");
break;
......
......@@ -3373,6 +3373,50 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
if (invalid_convert) SetFPSCR(VXCVI);
return;
}
case FCTIWU:
case FCTIWUZ: {
int frt = instr->RTValue();
int frb = instr->RBValue();
double frb_val = get_double_from_d_register(frb);
int mode = (opcode == FCTIWUZ)
? kRoundToZero
: (fp_condition_reg_ & kFPRoundingModeMask);
uint64_t frt_val;
uint64_t kMinVal = 0;
uint64_t kMaxVal = kMinVal - 1;
bool invalid_convert = false;
if (std::isnan(frb_val)) {
frt_val = kMinVal;
} else {
switch (mode) {
case kRoundToZero:
frb_val = std::trunc(frb_val);
break;
case kRoundToPlusInf:
frb_val = std::ceil(frb_val);
break;
case kRoundToMinusInf:
frb_val = std::floor(frb_val);
break;
default:
UNIMPLEMENTED(); // Not used by V8.
break;
}
if (frb_val < kMinVal) {
frt_val = kMinVal;
invalid_convert = true;
} else if (frb_val > kMaxVal) {
frt_val = kMaxVal;
invalid_convert = true;
} else {
frt_val = (uint64_t)frb_val;
}
}
set_d_register(frt, frt_val);
if (invalid_convert) SetFPSCR(VXCVI);
return;
}
case FNEG: {
int frt = instr->RTValue();
int frb = instr->RBValue();
......
......@@ -4192,12 +4192,14 @@ TEST(RunTruncateFloat32ToInt32) {
} else if (i >= upper_bound) {
#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64
CHECK_FLOAT_EQ(std::numeric_limits<int32_t>::min(), m.Call(i));
#elif V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_ARM
#elif V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_S390X || \
V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64
CHECK_FLOAT_EQ(std::numeric_limits<int32_t>::max(), m.Call(i));
#endif
} else {
DCHECK(std::isnan(i));
#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64
#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_S390X || \
V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64
CHECK_FLOAT_EQ(std::numeric_limits<int32_t>::min(), m.Call(i));
#elif V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_ARM
CHECK_FLOAT_EQ(0, m.Call(i));
......@@ -4216,7 +4218,8 @@ TEST(RunTruncateFloat32ToInt32) {
CHECK_FLOAT_EQ(std::numeric_limits<int32_t>::min(), m.Call(i));
} else {
DCHECK(std::isnan(i));
#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64
#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_S390X || \
V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64
CHECK_FLOAT_EQ(std::numeric_limits<int32_t>::min(), m.Call(i));
#elif V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_ARM
CHECK_FLOAT_EQ(0, m.Call(i));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment