PPC/s390: [turbofan] Add Float32(Max|Min) machine operators.
Port 2027b0bed1
Original commit message:
The new operators are implemented similar to the Float64(Max|Min) which
already exist. The purpose of the new operators is the implementation
of the F32Max and F32Min instructions in WebAssembly.
R=ahaas@chromium.org, joransiu@ca.ibm.com, jyan@ca.ibm.com, michael_dawson@ca.ibm.com, mbrandy@us.ibm.com
BUG=
LOG=N
Review-Url: https://codereview.chromium.org/2263383002
Cr-Commit-Position: refs/heads/master@{#38803}
This commit is contained in:
parent
232a33602b
commit
ad82a40509
@ -1310,6 +1310,9 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
|
||||
g.UseFixed(node->InputAt(1), d2))->MarkAsCall();
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat32Max(Node* node) {
|
||||
VisitRRR(this, kPPC_MaxDouble | MiscField::encode(1), node);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Max(Node* node) {
|
||||
VisitRRR(this, kPPC_MaxDouble, node);
|
||||
@ -1320,6 +1323,9 @@ void InstructionSelector::VisitFloat64SilenceNaN(Node* node) {
|
||||
VisitRR(this, kPPC_Float64SilenceNaN, node);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat32Min(Node* node) {
|
||||
VisitRRR(this, kPPC_MinDouble | MiscField::encode(1), node);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Min(Node* node) {
|
||||
VisitRRR(this, kPPC_MinDouble, node);
|
||||
|
@ -390,96 +390,185 @@ Condition FlagsConditionToCondition(FlagsCondition condition, ArchOpcode op) {
|
||||
__ MovFromFloatResult(i.OutputDoubleRegister()); \
|
||||
} 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; \
|
||||
__ 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.is(result_reg)) { \
|
||||
__ ldr(result_reg, right_reg); \
|
||||
} \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_left); \
|
||||
if (!left_reg.is(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; \
|
||||
__ 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.is(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.is(result_reg)) { \
|
||||
__ ldr(result_reg, right_reg); \
|
||||
} \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_left); \
|
||||
if (!left_reg.is(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_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.is(result_reg)) { \
|
||||
__ ldr(result_reg, right_reg); \
|
||||
} \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_left); \
|
||||
if (!left_reg.is(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.is(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.is(result_reg)) { \
|
||||
__ ldr(result_reg, right_reg); \
|
||||
} \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_left); \
|
||||
if (!left_reg.is(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.is(result_reg)) { \
|
||||
__ ldr(result_reg, right_reg); \
|
||||
} \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_left); \
|
||||
if (!left_reg.is(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.is(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.is(result_reg)) { \
|
||||
__ ldr(result_reg, right_reg); \
|
||||
} \
|
||||
__ b(&done, Label::kNear); \
|
||||
\
|
||||
__ bind(&return_left); \
|
||||
if (!left_reg.is(result_reg)) { \
|
||||
__ ldr(result_reg, left_reg); \
|
||||
} \
|
||||
__ bind(&done); \
|
||||
} while (0)
|
||||
// Only MRI mode for these instructions available
|
||||
#define ASSEMBLE_LOAD_FLOAT(asm_instr) \
|
||||
do { \
|
||||
@ -1512,12 +1601,18 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kS390_Neg64:
|
||||
__ lcgr(i.OutputRegister(), i.InputRegister(0));
|
||||
break;
|
||||
case kS390_MaxDouble:
|
||||
case kS390_MaxFloat:
|
||||
ASSEMBLE_FLOAT_MAX();
|
||||
break;
|
||||
case kS390_MinDouble:
|
||||
case kS390_MaxDouble:
|
||||
ASSEMBLE_DOUBLE_MAX();
|
||||
break;
|
||||
case kS390_MinFloat:
|
||||
ASSEMBLE_FLOAT_MIN();
|
||||
break;
|
||||
case kS390_MinDouble:
|
||||
ASSEMBLE_DOUBLE_MIN();
|
||||
break;
|
||||
case kS390_AbsDouble:
|
||||
__ lpdbr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
|
||||
break;
|
||||
|
@ -78,7 +78,9 @@ namespace compiler {
|
||||
V(S390_CeilDouble) \
|
||||
V(S390_TruncateDouble) \
|
||||
V(S390_RoundDouble) \
|
||||
V(S390_MaxFloat) \
|
||||
V(S390_MaxDouble) \
|
||||
V(S390_MinFloat) \
|
||||
V(S390_MinDouble) \
|
||||
V(S390_AbsDouble) \
|
||||
V(S390_Cntlz32) \
|
||||
|
@ -79,7 +79,9 @@ int InstructionScheduler::GetTargetInstructionFlags(
|
||||
case kS390_CeilDouble:
|
||||
case kS390_TruncateDouble:
|
||||
case kS390_RoundDouble:
|
||||
case kS390_MaxFloat:
|
||||
case kS390_MaxDouble:
|
||||
case kS390_MinFloat:
|
||||
case kS390_MinDouble:
|
||||
case kS390_AbsDouble:
|
||||
case kS390_Cntlz32:
|
||||
|
@ -1337,6 +1337,10 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
|
||||
->MarkAsCall();
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat32Max(Node* node) {
|
||||
VisitRRR(this, kS390_MaxFloat, node);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Max(Node* node) {
|
||||
VisitRRR(this, kS390_MaxDouble, node);
|
||||
}
|
||||
@ -1345,6 +1349,10 @@ void InstructionSelector::VisitFloat64SilenceNaN(Node* node) {
|
||||
VisitRR(this, kS390_Float64SilenceNaN, node);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat32Min(Node* node) {
|
||||
VisitRRR(this, kS390_MinFloat, node);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Min(Node* node) {
|
||||
VisitRRR(this, kS390_MinDouble, node);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user