Skip to content

Commit

Permalink
Support NaN values w.r.t fmax/fmin/dmax/dmin opcodes on S390
Browse files Browse the repository at this point in the history
This commit adds support to the S390 MaxMin evaluator to handle NaN operands for [fd]min/max opcodes.

- Add NaN checks for f/d opcodes and set return register to NaN if either operands are NaN
- Pass float/double NaN values as immediate into GPR, to later load the NaN value into result FPR
- Enable the previously skipped S390 NaN test cases

Closes: #5157

Signed-off-by: Sarwat Shaheen [email protected]
  • Loading branch information
sarwat12 committed Jan 11, 2024
1 parent 3e1bb69 commit 63b4dbe
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 27 deletions.
48 changes: 42 additions & 6 deletions compiler/z/codegen/ControlFlowEvaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,21 +338,57 @@ xmaxxminHelper(TR::Node* node, TR::CodeGenerator* cg, TR::InstOpCode::Mnemonic c
generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart);
cFlowRegionStart->setStartInternalControlFlow();

TR::RegisterDependencyConditions* deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 3, cg);
deps->addPostConditionIfNotAlreadyInserted(lhsReg, TR::RealRegister::AssignAny);
deps->addPostConditionIfNotAlreadyInserted(rhsReg, TR::RealRegister::AssignAny);

//Checking common Condition Code and branching to cFlowRegionEnd
generateRREInstruction(cg, compareRROp, node, lhsReg, rhsReg);
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, branchCond, node, cFlowRegionEnd);

generateRREInstruction(cg, moveRROp, node, lhsReg, rhsReg);

TR::RegisterDependencyConditions* deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(0, 2, cg);
//Label Symbols for handling possible NaN operand case for float/double
TR::LabelSymbol* nanLabel = NULL;
TR::LabelSymbol* notNaNLabel = generateLabelSymbol(cg);
//For Double & Float operands only, branching to nanLabel for Condition Code 3 when operands are unordered
if (node->getOpCode().isDouble() || node->getOpCode().isFloat())
{
nanLabel = generateLabelSymbol(cg);
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_CC3, node, nanLabel);
//Branch to notNaNLabel as fallthrough
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, notNaNLabel);

//Handle NaN case
generateS390LabelInstruction(cg, TR::InstOpCode::label, node, nanLabel);
//Allocate GPR for holding immediate NaN value for float/double
TR::Register * nanReg = cg->allocateRegister(TR_GPR);
//Handle NaN case for doubles
if (node->getOpCode().isDouble())
{
//Load immediate DOUBLE_NAN value into GPR, then move it to result FPR
genLoadLongConstant(cg, node, DOUBLE_NAN, nanReg, NULL, deps, NULL);
generateRRInstruction(cg, TR::InstOpCode::LDGR, node, lhsReg, nanReg);
}
else if (node->getOpCode().isFloat())
{
//Handle NaN case for floats by loading immediate FLOAT_NAN value into GPR
//Shift left the 32 least significant bits for preserving float representation before moving to FPR
generateRILInstruction(cg, TR::InstOpCode::LGFI, node, nanReg, FLOAT_NAN, NULL);
generateRSInstruction(cg, TR::InstOpCode::SLLG, node, nanReg, 32);
generateRRInstruction(cg, TR::InstOpCode::LDGR, node, lhsReg, nanReg);
}
deps->addPostConditionIfNotAlreadyInserted(nanReg, TR::RealRegister::AssignAny);
cg->stopUsingRegister(nanReg);
generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionEnd);
}

deps->addPostConditionIfNotAlreadyInserted(lhsReg, TR::RealRegister::AssignAny);
deps->addPostConditionIfNotAlreadyInserted(rhsReg, TR::RealRegister::AssignAny);
generateS390LabelInstruction(cg, TR::InstOpCode::label, node, notNaNLabel);
//Move resulting operand to lhsReg as fallthrough for alternate Condition Code
generateRREInstruction(cg, moveRROp, node, lhsReg, rhsReg);

generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionEnd, deps);
cFlowRegionEnd->setEndInternalControlFlow();

node->setRegister(lhsReg);

cg->decReferenceCount(lhsNode);
cg->decReferenceCount(rhsNode);

Expand Down
21 changes: 0 additions & 21 deletions fvtest/compilertriltest/MaxMinTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,6 @@ TEST_P(FloatMaxMin, UsingConst) {

auto param = TRTest::to_struct(GetParam());

if (std::isnan(param.lhs) || std::isnan(param.rhs)) {
SKIP_ON_S390(KnownBug) << "fmin / fmax returns wrong value for NaN on Z (see issue #5157)";
SKIP_ON_S390X(KnownBug) << "fmin / fmax returns wrong value for NaN on Z (see issue #5157)";
}

char inputTrees[1024] = {0};
std::snprintf(inputTrees, sizeof(inputTrees),
"(method return=Float"
Expand Down Expand Up @@ -237,11 +232,6 @@ TEST_P(FloatMaxMin, UsingLoadParam) {

auto param = TRTest::to_struct(GetParam());

if (std::isnan(param.lhs) || std::isnan(param.rhs)) {
SKIP_ON_S390(KnownBug) << "fmin / fmax returns wrong value for NaN on Z (see issue #5157)";
SKIP_ON_S390X(KnownBug) << "fmin / fmax returns wrong value for NaN on Z (see issue #5157)";
}

char inputTrees[1024] = {0};
std::snprintf(inputTrees, sizeof(inputTrees),
"(method return=Float args=[Float, Float]"
Expand Down Expand Up @@ -280,11 +270,6 @@ TEST_P(DoubleMaxMin, UsingConst) {

auto param = TRTest::to_struct(GetParam());

if (std::isnan(param.lhs) || std::isnan(param.rhs)) {
SKIP_ON_S390(KnownBug) << "dmin / dmax returns wrong value for NaN on Z (see issue #5157)";
SKIP_ON_S390X(KnownBug) << "dmin / dmax returns wrong value for NaN on Z (see issue #5157)";
}

char inputTrees[1024] = {0};
std::snprintf(inputTrees, sizeof(inputTrees),
"(method return=Double"
Expand Down Expand Up @@ -315,12 +300,6 @@ TEST_P(DoubleMaxMin, UsingLoadParam) {

auto param = TRTest::to_struct(GetParam());

if (std::isnan(param.lhs) || std::isnan(param.rhs)) {
SKIP_ON_S390(KnownBug) << "dmin / dmax returns wrong value for NaN on Z (see issue #5157)";
SKIP_ON_S390X(KnownBug) << "dmin / dmax returns wrong value for NaN on Z (see issue #5157)";

}

char inputTrees[1024] = {0};
std::snprintf(inputTrees, sizeof(inputTrees),
"(method return=Double args=[Double, Double]"
Expand Down

0 comments on commit 63b4dbe

Please sign in to comment.