PPC/s390: fix NAN propagation on float/double min and max
Using the proper `add` operation assures the NAN value is properly propagated to the result register. Change-Id: Icb86193f85534604f2a4a583d177a6f319ca38c3 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2429804 Reviewed-by: Junliang Yan <junyan@redhat.com> Commit-Queue: Milad Farazmand <mfarazma@redhat.com> Cr-Commit-Position: refs/heads/master@{#70127}
This commit is contained in:
parent
e487a7daa2
commit
1474e595cf
@ -449,41 +449,42 @@ void EmitWordLoadPoisoningIfNeeded(CodeGenerator* codegen, Instruction* instr,
|
||||
DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_FLOAT_MAX() \
|
||||
do { \
|
||||
DoubleRegister left_reg = i.InputDoubleRegister(0); \
|
||||
DoubleRegister right_reg = i.InputDoubleRegister(1); \
|
||||
DoubleRegister result_reg = i.OutputDoubleRegister(); \
|
||||
Label check_nan_left, check_zero, return_left, return_right, done; \
|
||||
__ fcmpu(left_reg, right_reg); \
|
||||
__ bunordered(&check_nan_left); \
|
||||
__ beq(&check_zero); \
|
||||
__ bge(&return_left); \
|
||||
__ b(&return_right); \
|
||||
\
|
||||
__ bind(&check_zero); \
|
||||
__ fcmpu(left_reg, kDoubleRegZero); \
|
||||
/* left == right != 0. */ \
|
||||
__ bne(&return_left); \
|
||||
/* At this point, both left and right are either 0 or -0. */ \
|
||||
__ fadd(result_reg, left_reg, right_reg); \
|
||||
__ b(&done); \
|
||||
\
|
||||
__ bind(&check_nan_left); \
|
||||
__ fcmpu(left_reg, left_reg); \
|
||||
/* left == NaN. */ \
|
||||
__ bunordered(&return_left); \
|
||||
__ bind(&return_right); \
|
||||
if (right_reg != result_reg) { \
|
||||
__ fmr(result_reg, right_reg); \
|
||||
} \
|
||||
__ b(&done); \
|
||||
\
|
||||
__ bind(&return_left); \
|
||||
if (left_reg != result_reg) { \
|
||||
__ fmr(result_reg, left_reg); \
|
||||
} \
|
||||
__ bind(&done); \
|
||||
#define ASSEMBLE_FLOAT_MAX() \
|
||||
do { \
|
||||
DoubleRegister left_reg = i.InputDoubleRegister(0); \
|
||||
DoubleRegister right_reg = i.InputDoubleRegister(1); \
|
||||
DoubleRegister result_reg = i.OutputDoubleRegister(); \
|
||||
Label check_zero, return_left, return_right, return_nan, done; \
|
||||
__ fcmpu(left_reg, right_reg); \
|
||||
__ bunordered(&return_nan); \
|
||||
__ beq(&check_zero); \
|
||||
__ bge(&return_left); \
|
||||
__ b(&return_right); \
|
||||
\
|
||||
__ bind(&check_zero); \
|
||||
__ fcmpu(left_reg, kDoubleRegZero); \
|
||||
/* left == right != 0. */ \
|
||||
__ bne(&return_left); \
|
||||
/* At this point, both left and right are either 0 or -0. */ \
|
||||
__ fadd(result_reg, left_reg, right_reg); \
|
||||
__ b(&done); \
|
||||
\
|
||||
__ bind(&return_nan); \
|
||||
/* If left or right are NaN, fadd propagates the appropriate one.*/ \
|
||||
__ fadd(result_reg, left_reg, right_reg); \
|
||||
__ b(&done); \
|
||||
\
|
||||
__ bind(&return_right); \
|
||||
if (right_reg != result_reg) { \
|
||||
__ fmr(result_reg, right_reg); \
|
||||
} \
|
||||
__ b(&done); \
|
||||
\
|
||||
__ bind(&return_left); \
|
||||
if (left_reg != result_reg) { \
|
||||
__ fmr(result_reg, left_reg); \
|
||||
} \
|
||||
__ bind(&done); \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_FLOAT_MIN() \
|
||||
@ -491,9 +492,9 @@ void EmitWordLoadPoisoningIfNeeded(CodeGenerator* codegen, Instruction* instr,
|
||||
DoubleRegister left_reg = i.InputDoubleRegister(0); \
|
||||
DoubleRegister right_reg = i.InputDoubleRegister(1); \
|
||||
DoubleRegister result_reg = i.OutputDoubleRegister(); \
|
||||
Label check_nan_left, check_zero, return_left, return_right, done; \
|
||||
Label check_zero, return_left, return_right, return_nan, done; \
|
||||
__ fcmpu(left_reg, right_reg); \
|
||||
__ bunordered(&check_nan_left); \
|
||||
__ bunordered(&return_nan); \
|
||||
__ beq(&check_zero); \
|
||||
__ ble(&return_left); \
|
||||
__ b(&return_right); \
|
||||
@ -515,10 +516,10 @@ void EmitWordLoadPoisoningIfNeeded(CodeGenerator* codegen, Instruction* instr,
|
||||
__ fneg(result_reg, result_reg); \
|
||||
__ b(&done); \
|
||||
\
|
||||
__ bind(&check_nan_left); \
|
||||
__ fcmpu(left_reg, left_reg); \
|
||||
/* left == NaN. */ \
|
||||
__ bunordered(&return_left); \
|
||||
__ bind(&return_nan); \
|
||||
/* If left or right are NaN, fadd propagates the appropriate one.*/ \
|
||||
__ fadd(result_reg, left_reg, right_reg); \
|
||||
__ b(&done); \
|
||||
\
|
||||
__ bind(&return_right); \
|
||||
if (right_reg != result_reg) { \
|
||||
|
@ -643,184 +643,184 @@ static inline int AssembleUnaryOp(Instruction* instr, _R _r, _M _m, _I _i) {
|
||||
__ MovFromFloatResult(i.OutputDoubleRegister()); \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_DOUBLE_MAX() \
|
||||
do { \
|
||||
DoubleRegister left_reg = i.InputDoubleRegister(0); \
|
||||
DoubleRegister right_reg = i.InputDoubleRegister(1); \
|
||||
DoubleRegister result_reg = i.OutputDoubleRegister(); \
|
||||
Label check_nan_left, check_zero, return_left, return_right, done; \
|
||||
__ cdbr(left_reg, right_reg); \
|
||||
__ bunordered(&check_nan_left, Label::kNear); \
|
||||
__ beq(&check_zero); \
|
||||
__ bge(&return_left, Label::kNear); \
|
||||
__ b(&return_right, Label::kNear); \
|
||||
\
|
||||
__ bind(&check_zero); \
|
||||
__ lzdr(kDoubleRegZero); \
|
||||
__ cdbr(left_reg, kDoubleRegZero); \
|
||||
/* left == right != 0. */ \
|
||||
__ bne(&return_left, Label::kNear); \
|
||||
/* At this point, both left and right are either 0 or -0. */ \
|
||||
/* N.B. The following works because +0 + -0 == +0 */ \
|
||||
/* For max we want logical-and of sign bit: (L + R) */ \
|
||||
__ ldr(result_reg, left_reg); \
|
||||
__ adbr(result_reg, right_reg); \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&check_nan_left); \
|
||||
__ cdbr(left_reg, left_reg); \
|
||||
/* left == NaN. */ \
|
||||
__ bunordered(&return_left, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_right); \
|
||||
if (right_reg != result_reg) { \
|
||||
__ ldr(result_reg, right_reg); \
|
||||
} \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_left); \
|
||||
if (left_reg != result_reg) { \
|
||||
__ ldr(result_reg, left_reg); \
|
||||
} \
|
||||
__ bind(&done); \
|
||||
#define ASSEMBLE_DOUBLE_MAX() \
|
||||
do { \
|
||||
DoubleRegister left_reg = i.InputDoubleRegister(0); \
|
||||
DoubleRegister right_reg = i.InputDoubleRegister(1); \
|
||||
DoubleRegister result_reg = i.OutputDoubleRegister(); \
|
||||
Label check_zero, return_left, return_right, return_nan, done; \
|
||||
__ cdbr(left_reg, right_reg); \
|
||||
__ bunordered(&return_nan, Label::kNear); \
|
||||
__ beq(&check_zero); \
|
||||
__ bge(&return_left, Label::kNear); \
|
||||
__ b(&return_right, Label::kNear); \
|
||||
\
|
||||
__ bind(&check_zero); \
|
||||
__ lzdr(kDoubleRegZero); \
|
||||
__ cdbr(left_reg, kDoubleRegZero); \
|
||||
/* left == right != 0. */ \
|
||||
__ bne(&return_left, Label::kNear); \
|
||||
/* At this point, both left and right are either 0 or -0. */ \
|
||||
/* N.B. The following works because +0 + -0 == +0 */ \
|
||||
/* For max we want logical-and of sign bit: (L + R) */ \
|
||||
__ ldr(result_reg, left_reg); \
|
||||
__ adbr(result_reg, right_reg); \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_nan); \
|
||||
/* If left or right are NaN, adbr propagates the appropriate one.*/ \
|
||||
__ adbr(left_reg, right_reg); \
|
||||
__ b(&return_left, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_right); \
|
||||
if (right_reg != result_reg) { \
|
||||
__ ldr(result_reg, right_reg); \
|
||||
} \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_left); \
|
||||
if (left_reg != result_reg) { \
|
||||
__ ldr(result_reg, left_reg); \
|
||||
} \
|
||||
__ bind(&done); \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_DOUBLE_MIN() \
|
||||
do { \
|
||||
DoubleRegister left_reg = i.InputDoubleRegister(0); \
|
||||
DoubleRegister right_reg = i.InputDoubleRegister(1); \
|
||||
DoubleRegister result_reg = i.OutputDoubleRegister(); \
|
||||
Label check_nan_left, check_zero, return_left, return_right, done; \
|
||||
__ cdbr(left_reg, right_reg); \
|
||||
__ bunordered(&check_nan_left, Label::kNear); \
|
||||
__ beq(&check_zero); \
|
||||
__ ble(&return_left, Label::kNear); \
|
||||
__ b(&return_right, Label::kNear); \
|
||||
\
|
||||
__ bind(&check_zero); \
|
||||
__ lzdr(kDoubleRegZero); \
|
||||
__ cdbr(left_reg, kDoubleRegZero); \
|
||||
/* left == right != 0. */ \
|
||||
__ bne(&return_left, Label::kNear); \
|
||||
/* At this point, both left and right are either 0 or -0. */ \
|
||||
/* N.B. The following works because +0 + -0 == +0 */ \
|
||||
/* For min we want logical-or of sign bit: -(-L + -R) */ \
|
||||
__ lcdbr(left_reg, left_reg); \
|
||||
__ ldr(result_reg, left_reg); \
|
||||
if (left_reg == right_reg) { \
|
||||
__ adbr(result_reg, right_reg); \
|
||||
} else { \
|
||||
__ sdbr(result_reg, right_reg); \
|
||||
} \
|
||||
__ lcdbr(result_reg, result_reg); \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&check_nan_left); \
|
||||
__ cdbr(left_reg, left_reg); \
|
||||
/* left == NaN. */ \
|
||||
__ bunordered(&return_left, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_right); \
|
||||
if (right_reg != result_reg) { \
|
||||
__ ldr(result_reg, right_reg); \
|
||||
} \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_left); \
|
||||
if (left_reg != result_reg) { \
|
||||
__ ldr(result_reg, left_reg); \
|
||||
} \
|
||||
__ bind(&done); \
|
||||
#define ASSEMBLE_DOUBLE_MIN() \
|
||||
do { \
|
||||
DoubleRegister left_reg = i.InputDoubleRegister(0); \
|
||||
DoubleRegister right_reg = i.InputDoubleRegister(1); \
|
||||
DoubleRegister result_reg = i.OutputDoubleRegister(); \
|
||||
Label check_zero, return_left, return_right, return_nan, done; \
|
||||
__ cdbr(left_reg, right_reg); \
|
||||
__ bunordered(&return_nan, Label::kNear); \
|
||||
__ beq(&check_zero); \
|
||||
__ ble(&return_left, Label::kNear); \
|
||||
__ b(&return_right, Label::kNear); \
|
||||
\
|
||||
__ bind(&check_zero); \
|
||||
__ lzdr(kDoubleRegZero); \
|
||||
__ cdbr(left_reg, kDoubleRegZero); \
|
||||
/* left == right != 0. */ \
|
||||
__ bne(&return_left, Label::kNear); \
|
||||
/* At this point, both left and right are either 0 or -0. */ \
|
||||
/* N.B. The following works because +0 + -0 == +0 */ \
|
||||
/* For min we want logical-or of sign bit: -(-L + -R) */ \
|
||||
__ lcdbr(left_reg, left_reg); \
|
||||
__ ldr(result_reg, left_reg); \
|
||||
if (left_reg == right_reg) { \
|
||||
__ adbr(result_reg, right_reg); \
|
||||
} else { \
|
||||
__ sdbr(result_reg, right_reg); \
|
||||
} \
|
||||
__ lcdbr(result_reg, result_reg); \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_nan); \
|
||||
/* If left or right are NaN, adbr propagates the appropriate one.*/ \
|
||||
__ adbr(left_reg, right_reg); \
|
||||
__ b(&return_left, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_right); \
|
||||
if (right_reg != result_reg) { \
|
||||
__ ldr(result_reg, right_reg); \
|
||||
} \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_left); \
|
||||
if (left_reg != result_reg) { \
|
||||
__ ldr(result_reg, left_reg); \
|
||||
} \
|
||||
__ bind(&done); \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_FLOAT_MAX() \
|
||||
do { \
|
||||
DoubleRegister left_reg = i.InputDoubleRegister(0); \
|
||||
DoubleRegister right_reg = i.InputDoubleRegister(1); \
|
||||
DoubleRegister result_reg = i.OutputDoubleRegister(); \
|
||||
Label check_nan_left, check_zero, return_left, return_right, done; \
|
||||
__ cebr(left_reg, right_reg); \
|
||||
__ bunordered(&check_nan_left, Label::kNear); \
|
||||
__ beq(&check_zero); \
|
||||
__ bge(&return_left, Label::kNear); \
|
||||
__ b(&return_right, Label::kNear); \
|
||||
\
|
||||
__ bind(&check_zero); \
|
||||
__ lzdr(kDoubleRegZero); \
|
||||
__ cebr(left_reg, kDoubleRegZero); \
|
||||
/* left == right != 0. */ \
|
||||
__ bne(&return_left, Label::kNear); \
|
||||
/* At this point, both left and right are either 0 or -0. */ \
|
||||
/* N.B. The following works because +0 + -0 == +0 */ \
|
||||
/* For max we want logical-and of sign bit: (L + R) */ \
|
||||
__ ldr(result_reg, left_reg); \
|
||||
__ aebr(result_reg, right_reg); \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&check_nan_left); \
|
||||
__ cebr(left_reg, left_reg); \
|
||||
/* left == NaN. */ \
|
||||
__ bunordered(&return_left, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_right); \
|
||||
if (right_reg != result_reg) { \
|
||||
__ ldr(result_reg, right_reg); \
|
||||
} \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_left); \
|
||||
if (left_reg != result_reg) { \
|
||||
__ ldr(result_reg, left_reg); \
|
||||
} \
|
||||
__ bind(&done); \
|
||||
#define ASSEMBLE_FLOAT_MAX() \
|
||||
do { \
|
||||
DoubleRegister left_reg = i.InputDoubleRegister(0); \
|
||||
DoubleRegister right_reg = i.InputDoubleRegister(1); \
|
||||
DoubleRegister result_reg = i.OutputDoubleRegister(); \
|
||||
Label check_zero, return_left, return_right, return_nan, done; \
|
||||
__ cebr(left_reg, right_reg); \
|
||||
__ bunordered(&return_nan, Label::kNear); \
|
||||
__ beq(&check_zero); \
|
||||
__ bge(&return_left, Label::kNear); \
|
||||
__ b(&return_right, Label::kNear); \
|
||||
\
|
||||
__ bind(&check_zero); \
|
||||
__ lzdr(kDoubleRegZero); \
|
||||
__ cebr(left_reg, kDoubleRegZero); \
|
||||
/* left == right != 0. */ \
|
||||
__ bne(&return_left, Label::kNear); \
|
||||
/* At this point, both left and right are either 0 or -0. */ \
|
||||
/* N.B. The following works because +0 + -0 == +0 */ \
|
||||
/* For max we want logical-and of sign bit: (L + R) */ \
|
||||
__ ldr(result_reg, left_reg); \
|
||||
__ aebr(result_reg, right_reg); \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_nan); \
|
||||
/* If left or right are NaN, aebr propagates the appropriate one.*/ \
|
||||
__ aebr(left_reg, right_reg); \
|
||||
__ b(&return_left, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_right); \
|
||||
if (right_reg != result_reg) { \
|
||||
__ ldr(result_reg, right_reg); \
|
||||
} \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_left); \
|
||||
if (left_reg != result_reg) { \
|
||||
__ ldr(result_reg, left_reg); \
|
||||
} \
|
||||
__ bind(&done); \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_FLOAT_MIN() \
|
||||
do { \
|
||||
DoubleRegister left_reg = i.InputDoubleRegister(0); \
|
||||
DoubleRegister right_reg = i.InputDoubleRegister(1); \
|
||||
DoubleRegister result_reg = i.OutputDoubleRegister(); \
|
||||
Label check_nan_left, check_zero, return_left, return_right, done; \
|
||||
__ cebr(left_reg, right_reg); \
|
||||
__ bunordered(&check_nan_left, Label::kNear); \
|
||||
__ beq(&check_zero); \
|
||||
__ ble(&return_left, Label::kNear); \
|
||||
__ b(&return_right, Label::kNear); \
|
||||
\
|
||||
__ bind(&check_zero); \
|
||||
__ lzdr(kDoubleRegZero); \
|
||||
__ cebr(left_reg, kDoubleRegZero); \
|
||||
/* left == right != 0. */ \
|
||||
__ bne(&return_left, Label::kNear); \
|
||||
/* At this point, both left and right are either 0 or -0. */ \
|
||||
/* N.B. The following works because +0 + -0 == +0 */ \
|
||||
/* For min we want logical-or of sign bit: -(-L + -R) */ \
|
||||
__ lcebr(left_reg, left_reg); \
|
||||
__ ldr(result_reg, left_reg); \
|
||||
if (left_reg == right_reg) { \
|
||||
__ aebr(result_reg, right_reg); \
|
||||
} else { \
|
||||
__ sebr(result_reg, right_reg); \
|
||||
} \
|
||||
__ lcebr(result_reg, result_reg); \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&check_nan_left); \
|
||||
__ cebr(left_reg, left_reg); \
|
||||
/* left == NaN. */ \
|
||||
__ bunordered(&return_left, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_right); \
|
||||
if (right_reg != result_reg) { \
|
||||
__ ldr(result_reg, right_reg); \
|
||||
} \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_left); \
|
||||
if (left_reg != result_reg) { \
|
||||
__ ldr(result_reg, left_reg); \
|
||||
} \
|
||||
__ bind(&done); \
|
||||
#define ASSEMBLE_FLOAT_MIN() \
|
||||
do { \
|
||||
DoubleRegister left_reg = i.InputDoubleRegister(0); \
|
||||
DoubleRegister right_reg = i.InputDoubleRegister(1); \
|
||||
DoubleRegister result_reg = i.OutputDoubleRegister(); \
|
||||
Label check_zero, return_left, return_right, return_nan, done; \
|
||||
__ cebr(left_reg, right_reg); \
|
||||
__ bunordered(&return_nan, Label::kNear); \
|
||||
__ beq(&check_zero); \
|
||||
__ ble(&return_left, Label::kNear); \
|
||||
__ b(&return_right, Label::kNear); \
|
||||
\
|
||||
__ bind(&check_zero); \
|
||||
__ lzdr(kDoubleRegZero); \
|
||||
__ cebr(left_reg, kDoubleRegZero); \
|
||||
/* left == right != 0. */ \
|
||||
__ bne(&return_left, Label::kNear); \
|
||||
/* At this point, both left and right are either 0 or -0. */ \
|
||||
/* N.B. The following works because +0 + -0 == +0 */ \
|
||||
/* For min we want logical-or of sign bit: -(-L + -R) */ \
|
||||
__ lcebr(left_reg, left_reg); \
|
||||
__ ldr(result_reg, left_reg); \
|
||||
if (left_reg == right_reg) { \
|
||||
__ aebr(result_reg, right_reg); \
|
||||
} else { \
|
||||
__ sebr(result_reg, right_reg); \
|
||||
} \
|
||||
__ lcebr(result_reg, result_reg); \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_nan); \
|
||||
/* If left or right are NaN, aebr propagates the appropriate one.*/ \
|
||||
__ aebr(left_reg, right_reg); \
|
||||
__ b(&return_left, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_right); \
|
||||
if (right_reg != result_reg) { \
|
||||
__ ldr(result_reg, right_reg); \
|
||||
} \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_left); \
|
||||
if (left_reg != result_reg) { \
|
||||
__ ldr(result_reg, left_reg); \
|
||||
} \
|
||||
__ bind(&done); \
|
||||
} while (0)
|
||||
//
|
||||
// Only MRI mode for these instructions available
|
||||
|
Loading…
Reference in New Issue
Block a user