Commit 06d7276b authored by joransiu's avatar joransiu Committed by Commit bot

S390: Use FIEBRA/FIDBRA for FP Floor/Ceil

The existing FloatFloor/Ceiling functions had an issue with handling
Number.MIN_VALUE (0x1 ==> 5e-324), and would incorrectly return
MIN_VALUE instead of 0/1.  Simplify the entire sequence by using the
available hardware instruction with the appropriate rounding mode
(POS_INF for Ceiling, NEG_INF for Floor).

Add missing FIEBRA/FIDBRA cases to disassembler.

R=jyan@ca.ibm.com,michael_dawson@ca.ibm.com,mbrandy@us.ibm.com
BUG=

Review URL: https://codereview.chromium.org/1853973002

Cr-Commit-Position: refs/heads/master@{#35239}
parent 3dc43a75
...@@ -1203,13 +1203,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -1203,13 +1203,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
ASSEMBLE_FLOAT_UNOP(sqebr); ASSEMBLE_FLOAT_UNOP(sqebr);
break; break;
case kS390_FloorFloat: case kS390_FloorFloat:
// ASSEMBLE_FLOAT_UNOP_RC(frim); __ fiebra(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
__ FloatFloor32(i.OutputDoubleRegister(), i.InputDoubleRegister(0), v8::internal::Assembler::FIDBRA_ROUND_TOWARD_NEG_INF);
kScratchReg);
break; break;
case kS390_CeilFloat: case kS390_CeilFloat:
__ FloatCeiling32(i.OutputDoubleRegister(), i.InputDoubleRegister(0), __ fiebra(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
kScratchReg, kScratchDoubleReg); v8::internal::Assembler::FIDBRA_ROUND_TOWARD_POS_INF);
break; break;
case kS390_TruncateFloat: case kS390_TruncateFloat:
__ fiebra(i.OutputDoubleRegister(), i.InputDoubleRegister(0), __ fiebra(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
...@@ -1235,12 +1234,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -1235,12 +1234,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
ASSEMBLE_FLOAT_UNOP(sqdbr); ASSEMBLE_FLOAT_UNOP(sqdbr);
break; break;
case kS390_FloorDouble: case kS390_FloorDouble:
__ FloatFloor64(i.OutputDoubleRegister(), i.InputDoubleRegister(0), __ fidbra(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
kScratchReg); v8::internal::Assembler::FIDBRA_ROUND_TOWARD_NEG_INF);
break; break;
case kS390_CeilDouble: case kS390_CeilDouble:
__ FloatCeiling64(i.OutputDoubleRegister(), i.InputDoubleRegister(0), __ fidbra(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
kScratchReg, kScratchDoubleReg); v8::internal::Assembler::FIDBRA_ROUND_TOWARD_POS_INF);
break; break;
case kS390_TruncateDouble: case kS390_TruncateDouble:
__ fidbra(i.OutputDoubleRegister(), i.InputDoubleRegister(0), __ fidbra(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
......
...@@ -308,14 +308,18 @@ int Decoder::FormatOption(Instruction* instr, const char* format) { ...@@ -308,14 +308,18 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
int Decoder::FormatMask(Instruction* instr, const char* format) { int Decoder::FormatMask(Instruction* instr, const char* format) {
DCHECK(format[0] == 'm'); DCHECK(format[0] == 'm');
int32_t value = 0; int32_t value = 0;
if ((format[1] == '1')) { // prints the mask format in bit 8-12 if ((format[1] == '1')) { // prints the mask format in bits 8-12
value = reinterpret_cast<RRInstruction*>(instr)->R1Value(); value = reinterpret_cast<RRInstruction*>(instr)->R1Value();
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", value); out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", value);
return 2; return 2;
} else if (format[1] == '2') { // mask format in bit 16 - 19 } else if (format[1] == '2') { // mask format in bits 16-19
value = reinterpret_cast<RXInstruction*>(instr)->B2Value(); value = reinterpret_cast<RXInstruction*>(instr)->B2Value();
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", value); out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", value);
return 2; return 2;
} else if (format[1] == '3') { // mask format in bits 20-23
value = reinterpret_cast<RRFInstruction*>(instr)->M4Value();
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", value);
return 2;
} }
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value); out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
...@@ -991,6 +995,12 @@ bool Decoder::DecodeFourByte(Instruction* instr) { ...@@ -991,6 +995,12 @@ bool Decoder::DecodeFourByte(Instruction* instr) {
case FLOGR: case FLOGR:
Format(instr, "flogr\t'r5,'r6"); Format(instr, "flogr\t'r5,'r6");
break; break;
case FIEBRA:
Format(instr, "fiebra\t'f5,'m2,'f6,'m3");
break;
case FIDBRA:
Format(instr, "fidbra\t'f5,'m2,'f6,'m3");
break;
// TRAP4 is used in calling to native function. it will not be generated // TRAP4 is used in calling to native function. it will not be generated
// in native code. // in native code.
case TRAP4: { case TRAP4: {
......
...@@ -2407,160 +2407,6 @@ void MacroAssembler::TryInt32Floor(Register result, DoubleRegister double_input, ...@@ -2407,160 +2407,6 @@ void MacroAssembler::TryInt32Floor(Register result, DoubleRegister double_input,
bind(&exception); bind(&exception);
} }
void MacroAssembler::FloatCeiling32(DoubleRegister double_output,
DoubleRegister double_input,
Register scratch,
DoubleRegister double_scratch) {
Label not_zero, no_nan_inf, done, do_ceil;
Register scratch2 = r0;
// Move high word into scratch
MovFloatToInt(scratch, double_input);
// Test for NaN/Inf which results in NaN/Inf respectively
static const uint32_t float32ExponentMask = 0x7f800000u;
ExtractBitMask(scratch2, scratch, float32ExponentMask);
CmpLogical32(scratch2, Operand(0xff));
bne(&no_nan_inf, Label::kNear);
Move(double_output, double_input);
b(&done);
bind(&no_nan_inf);
// Test for double_input in (-1, -0) which results in -0
LoadFloat32Literal(double_scratch, -1.0, scratch2);
cebr(double_input, double_scratch);
ble(&do_ceil, Label::kNear);
Cmp32(scratch, Operand::Zero());
bgt(&do_ceil, Label::kNear);
bne(&not_zero, Label::kNear);
// double_input = +/- 0 which results in +/- 0 respectively
Move(double_output, double_input);
b(&done);
bind(&not_zero);
// double_output = -0
llihf(scratch2, Operand(0x80000000));
ldgr(double_output, scratch2);
b(&done);
bind(&do_ceil);
// Regular case
// cgdbr(Condition(6), scratch, double_input);
// cdfbr(double_output, scratch);
fiebra(double_output, double_input, FIDBRA_ROUND_TOWARD_POS_INF);
bind(&done);
}
void MacroAssembler::FloatFloor32(DoubleRegister double_output,
DoubleRegister double_input,
Register scratch) {
Label not_zero, no_nan_inf, done, do_floor;
Register scratch2 = r0;
// Move high word into scratch
MovFloatToInt(scratch, double_input);
// Test for NaN/Inf which results in NaN/Inf respectively
static const uint32_t float32ExponentMask = 0x7f800000u;
ExtractBitMask(scratch2, scratch, float32ExponentMask);
CmpLogical32(scratch2, Operand(0xff));
bne(&no_nan_inf, Label::kNear);
Move(double_output, double_input);
b(&done);
bind(&no_nan_inf);
// Test for double_input=+/- 0 which results in +/- 0 respectively
ltebr(double_input, double_input);
bne(&do_floor, Label::kNear);
Move(double_output, double_input);
b(&done);
bind(&do_floor);
// Regular case
// cgdbr(Condition(7), scratch, double_input);
// cdfbr(double_output, scratch);
fiebra(double_output, double_input, FIDBRA_ROUND_TOWARD_NEG_INF);
bind(&done);
}
void MacroAssembler::FloatCeiling64(DoubleRegister double_output,
DoubleRegister double_input,
Register scratch,
DoubleRegister double_scratch) {
Label not_zero, no_nan_inf, done, do_ceil;
Register scratch2 = r0;
// Move high word into scratch
StoreDouble(double_input, MemOperand(sp, -kDoubleSize));
LoadlW(scratch, MemOperand(sp, -kDoubleSize + Register::kExponentOffset));
// Test for NaN/Inf which results in NaN/Inf respectively
ExtractBitMask(scratch2, scratch, HeapNumber::kExponentMask);
CmpLogicalP(scratch2, Operand(0x7ff));
bne(&no_nan_inf, Label::kNear);
Move(double_output, double_input);
b(&done);
bind(&no_nan_inf);
// Test for double_input in (-1, -0) which results in -0
LoadDoubleLiteral(double_scratch, -1.0, scratch2);
cdbr(double_input, double_scratch);
ble(&do_ceil, Label::kNear);
Cmp32(scratch, Operand::Zero());
bgt(&do_ceil, Label::kNear);
bne(&not_zero, Label::kNear);
// double_input = +/- 0 which results in +/- 0 respectively
Move(double_output, double_input);
b(&done);
bind(&not_zero);
// double_output = -0
llihf(scratch2, Operand(0x80000000));
ldgr(double_output, scratch2);
b(&done);
bind(&do_ceil);
// Regular case
// cgdbr(Condition(6), scratch, double_input);
// cdfbr(double_output, scratch);
fidbra(double_output, double_input, FIDBRA_ROUND_TOWARD_POS_INF);
bind(&done);
}
void MacroAssembler::FloatFloor64(DoubleRegister double_output,
DoubleRegister double_input,
Register scratch) {
Label not_zero, no_nan_inf, done, do_floor;
Register scratch2 = r0;
// Move high word into scratch
StoreDouble(double_input, MemOperand(sp, -kDoubleSize));
LoadlW(scratch, MemOperand(sp, -kDoubleSize + Register::kExponentOffset));
// Test for NaN/Inf which results in NaN/Inf respectively
ExtractBitMask(scratch2, scratch, HeapNumber::kExponentMask);
CmpLogicalP(scratch2, Operand(0x7ff));
bne(&no_nan_inf, Label::kNear);
Move(double_output, double_input);
b(&done);
bind(&no_nan_inf);
// Test for double_input=+/- 0 which results in +/- 0 respectively
ltdbr(double_input, double_input);
bne(&do_floor, Label::kNear);
Move(double_output, double_input);
b(&done);
bind(&do_floor);
// Regular case
// cgdbr(Condition(7), scratch, double_input);
// cdfbr(double_output, scratch);
fidbra(double_output, double_input, FIDBRA_ROUND_TOWARD_NEG_INF);
bind(&done);
}
void MacroAssembler::TryInlineTruncateDoubleToI(Register result, void MacroAssembler::TryInlineTruncateDoubleToI(Register result,
DoubleRegister double_input, DoubleRegister double_input,
Label* done) { Label* done) {
......
...@@ -1180,22 +1180,6 @@ class MacroAssembler : public Assembler { ...@@ -1180,22 +1180,6 @@ class MacroAssembler : public Assembler {
Register input_high, Register scratch, Register input_high, Register scratch,
DoubleRegister double_scratch, Label* done, Label* exact); DoubleRegister double_scratch, Label* done, Label* exact);
// Perform ceiling of float in input_register and store in double_output.
void FloatCeiling32(DoubleRegister double_output, DoubleRegister double_input,
Register scratch, DoubleRegister double_scratch);
// Perform floor of float in input_register and store in double_output.
void FloatFloor32(DoubleRegister double_output, DoubleRegister double_input,
Register scratch);
// Perform ceiling of double in input_register and store in double_output.
void FloatCeiling64(DoubleRegister double_output, DoubleRegister double_input,
Register scratch, DoubleRegister double_scratch);
// Perform floor of double in input_register and store in double_output.
void FloatFloor64(DoubleRegister double_output, DoubleRegister double_input,
Register scratch);
// Performs a truncating conversion of a floating point number as used by // Performs a truncating conversion of a floating point number as used by
// the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it // the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it
// succeeds, otherwise falls through if result is saturated. On return // succeeds, otherwise falls through if result is saturated. On return
......
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