Skip to content

Commit

Permalink
Merge pull request #4894 from janvrany/pr/riscv-implement-min-max-eva…
Browse files Browse the repository at this point in the history
…luators

RISC-V: implement min max evaluators
  • Loading branch information
fjeremic authored Mar 16, 2020
2 parents db438fa + 3897cef commit be503a2
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 36 deletions.
65 changes: 64 additions & 1 deletion compiler/riscv/codegen/ControlFlowEvaluator.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019, 2019 IBM Corp. and others
* Copyright (c) 2019, 2020 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -27,6 +27,7 @@
#include "codegen/TreeEvaluator.hpp"
#include "il/Node.hpp"
#include "il/Node_inlines.hpp"
#include "il/LabelSymbol.hpp"

TR::Register *
genericReturnEvaluator(TR::Node *node, TR::RealRegister::RegNum rnum, TR_RegisterKinds rk, TR_ReturnInfo i, TR::CodeGenerator *cg)
Expand Down Expand Up @@ -570,3 +571,65 @@ OMR::RV::TreeEvaluator::ArrayCHKEvaluator(TR::Node *node, TR::CodeGenerator *cg)
// TODO:RV: Enable TR::TreeEvaluator::ArrayCHKEvaluator in compiler/aarch64/codegen/TreeEvaluatorTable.hpp when Implemented.
return OMR::RV::TreeEvaluator::unImpOpEvaluator(node, cg);
}

static TR::Register *
commonMinMaxEvaluator(TR::Node *node, TR::InstOpCode::Mnemonic op, TR::CodeGenerator *cg)
{
TR_ASSERT(node->getNumChildren() == 2, "The number of children for imax/imin/lmax/lmin must be 2.");

TR::Node *firstChild = node->getFirstChild();
TR::Register *src1Reg = cg->gprClobberEvaluate(firstChild);
TR::Node *secondChild = node->getSecondChild();
TR::Register *src2Reg = cg->evaluate(secondChild);

TR::LabelSymbol *startLabel = generateLabelSymbol(cg);
TR::LabelSymbol *joinLabel = generateLabelSymbol(cg);

startLabel->setStartInternalControlFlow();
joinLabel->setEndInternalControlFlow();

TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(2, 2, cg->trMemory());
addDependency(deps, src1Reg, TR::RealRegister::NoReg, TR_GPR, cg);
addDependency(deps, src2Reg, TR::RealRegister::NoReg, TR_GPR, cg);

generateLABEL(cg, TR::InstOpCode::label, node, startLabel);
generateBTYPE(op, node, joinLabel, src1Reg, src2Reg, cg);
generateITYPE(TR::InstOpCode::_addi, node, src1Reg, src2Reg, 0, cg);
generateLABEL(cg, TR::InstOpCode::label, node, joinLabel, deps);

node->setRegister(src1Reg);
cg->decReferenceCount(firstChild);
cg->decReferenceCount(secondChild);

return src1Reg;
}

// Also handles lmax
TR::Register *
OMR::RV::TreeEvaluator::imaxEvaluator(TR::Node *node, TR::CodeGenerator *cg)
{
return commonMinMaxEvaluator(node, TR::InstOpCode::_bge, cg);
}

// Also handles lumax
TR::Register *
OMR::RV::TreeEvaluator::iumaxEvaluator(TR::Node *node, TR::CodeGenerator *cg)
{
return commonMinMaxEvaluator(node, TR::InstOpCode::_bgeu, cg);
}


// Also handles lmin
TR::Register *
OMR::RV::TreeEvaluator::iminEvaluator(TR::Node *node, TR::CodeGenerator *cg)
{
return commonMinMaxEvaluator(node, TR::InstOpCode::_blt, cg);
}

// Also handles lumin
TR::Register *
OMR::RV::TreeEvaluator::iuminEvaluator(TR::Node *node, TR::CodeGenerator *cg)
{
return commonMinMaxEvaluator(node, TR::InstOpCode::_bltu, cg);
}

91 changes: 82 additions & 9 deletions compiler/riscv/codegen/FPTreeEvaluator.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019, 2019 IBM Corp. and others
* Copyright (c) 2019, 2020 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -27,6 +27,8 @@
#include "codegen/TreeEvaluator.hpp"
#include "il/Node.hpp"
#include "il/Node_inlines.hpp"
#include "il/LabelSymbol.hpp"


static void fpBitsMovHelper(TR::Node *node, TR::InstOpCode::Mnemonic op, TR::Register *trgReg, TR::CodeGenerator *cg)
{
Expand Down Expand Up @@ -565,19 +567,90 @@ OMR::RV::TreeEvaluator::fRegLoadEvaluator(TR::Node *node, TR::CodeGenerator *cg)
return globalReg;
}

static TR::Register *
commonFpMinMaxEvaluator(TR::Node *node, TR::InstOpCode::Mnemonic op, bool reverse, bool isDouble, TR::CodeGenerator *cg)
{
TR_ASSERT(node->getNumChildren() == 2, "The number of children for fmax/fmin/dmax/dmin must be 2.");

TR::Node *firstChild = node->getFirstChild();
TR::Register *src1Reg = cg->evaluate(firstChild);
TR::Node *secondChild = node->getSecondChild();
TR::Register *src2Reg = cg->evaluate(secondChild);

TR::Register *cmpReg = cg->allocateRegister();
TR::RealRegister *zero = cg->machine()->getRealRegister(TR::RealRegister::zero);
TR::Register *trgReg;

if (cg->canClobberNodesRegister(firstChild))
{
trgReg = src1Reg; // use the first child as the target
}
else
{
trgReg = cg->allocateRegister(TR_FPR);
if (isDouble)
generateRTYPE(TR::InstOpCode::_fsgnj_d, node, trgReg, src1Reg, src1Reg, cg);
else
generateRTYPE(TR::InstOpCode::_fsgnj_s, node, trgReg, src1Reg, src1Reg, cg);
}

TR::LabelSymbol *startLabel = generateLabelSymbol(cg);
TR::LabelSymbol *joinLabel = generateLabelSymbol(cg);

startLabel->setStartInternalControlFlow();
joinLabel->setEndInternalControlFlow();

TR::RegisterDependencyConditions *deps = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(3, 3, cg->trMemory());
addDependency(deps, cmpReg, TR::RealRegister::NoReg, TR_GPR, cg);
addDependency(deps, trgReg, TR::RealRegister::NoReg, TR_FPR, cg);
addDependency(deps, src2Reg, TR::RealRegister::NoReg, TR_FPR, cg);


if (reverse)
generateRTYPE(op, node, cmpReg, src2Reg, src1Reg, cg);
else
generateRTYPE(op, node, cmpReg, src1Reg, src2Reg, cg);

generateLABEL(cg, TR::InstOpCode::label, node, startLabel);
generateBTYPE(TR::InstOpCode::_bne, node, joinLabel, cmpReg, zero, cg);
if (isDouble)
generateRTYPE(TR::InstOpCode::_fsgnj_d, node, trgReg, src2Reg, src2Reg, cg);
else
generateRTYPE(TR::InstOpCode::_fsgnj_s, node, trgReg, src2Reg, src2Reg, cg);
generateLABEL(cg, TR::InstOpCode::label, node, joinLabel, deps);

cg->stopUsingRegister(cmpReg);
node->setRegister(trgReg);
cg->decReferenceCount(firstChild);
cg->decReferenceCount(secondChild);

return trgReg;
}

TR::Register *
OMR::RV::TreeEvaluator::fmaxEvaluator(TR::Node *node, TR::CodeGenerator *cg)
{
// TODO:RV: Enable TR::TreeEvaluator::fmaxEvaluator in compiler/aarch64/codegen/TreeEvaluatorTable.hpp when Implemented.
return OMR::RV::TreeEvaluator::unImpOpEvaluator(node, cg);
}
{
return commonFpMinMaxEvaluator(node, TR::InstOpCode::_flt_s, true, false, cg);
}

TR::Register *
OMR::RV::TreeEvaluator::fminEvaluator(TR::Node *node, TR::CodeGenerator *cg)
{
// TODO:RV: Enable TR::TreeEvaluator::fminEvaluator in compiler/aarch64/codegen/TreeEvaluatorTable.hpp when Implemented.
return OMR::RV::TreeEvaluator::unImpOpEvaluator(node, cg);
}
{
return commonFpMinMaxEvaluator(node, TR::InstOpCode::_flt_s, false, false, cg);
}

TR::Register *
OMR::RV::TreeEvaluator::dmaxEvaluator(TR::Node *node, TR::CodeGenerator *cg)
{
return commonFpMinMaxEvaluator(node, TR::InstOpCode::_flt_d, true, true, cg);
}

TR::Register *
OMR::RV::TreeEvaluator::dminEvaluator(TR::Node *node, TR::CodeGenerator *cg)
{
return commonFpMinMaxEvaluator(node, TR::InstOpCode::_flt_d, false, true, cg);
}


TR::Register *
OMR::RV::TreeEvaluator::b2dEvaluator(TR::Node *node, TR::CodeGenerator *cg)
Expand Down
1 change: 0 additions & 1 deletion compiler/riscv/codegen/RVInstruction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ class RtypeInstruction : public TR::Instruction
TR::Register *_target1Register;
TR::Register *_source1Register;
TR::Register *_source2Register;
uint32_t _imm;

public:

Expand Down
24 changes: 12 additions & 12 deletions compiler/riscv/codegen/TreeEvaluatorTable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -729,18 +729,18 @@
TR::TreeEvaluator::unImpOpEvaluator , // TODO:RV: Enable when Implemented: TR::TreeEvaluator::getpmEvaluator , // TR::getpm // get program mask
TR::TreeEvaluator::unImpOpEvaluator , // TODO:RV: Enable when Implemented: TR::TreeEvaluator::setpmEvaluator , // TR::setpm // set program mask
TR::TreeEvaluator::unImpOpEvaluator , // TODO:RV: Enable when Implemented: TR::TreeEvaluator::loadAutoOffsetEvaluator , // TR::loadAutoOffset // loads the offset (from the SP) of an auto
TR::TreeEvaluator::unImpOpEvaluator , // TODO:RV: Enable when Implemented: TR::TreeEvaluator::imaxEvaluator , // TR::imax // max of 2 or more integers
TR::TreeEvaluator::unImpOpEvaluator , // TODO:RV: Enable when Implemented: TR::TreeEvaluator::iumaxEvaluator , // TR::iumax // max of 2 or more unsigned integers
TR::TreeEvaluator::unImpOpEvaluator , // TODO:RV: Enable when Implemented: TR::TreeEvaluator::lmaxEvaluator , // TR::lmax // max of 2 or more longs
TR::TreeEvaluator::unImpOpEvaluator , // TODO:RV: Enable when Implemented: TR::TreeEvaluator::lumaxEvaluator , // TR::lumax // max of 2 or more unsigned longs
TR::TreeEvaluator::unImpOpEvaluator , // TODO:RV: Enable when Implemented: TR::TreeEvaluator::fmaxEvaluator , // TR::fmax // max of 2 or more floats
TR::TreeEvaluator::unImpOpEvaluator , // TODO:RV: Enable when Implemented: TR::TreeEvaluator::dmaxEvaluator , // TR::dmax // max of 2 or more doubles
TR::TreeEvaluator::unImpOpEvaluator , // TODO:RV: Enable when Implemented: TR::TreeEvaluator::iminEvaluator , // TR::imin // min of 2 or more integers
TR::TreeEvaluator::unImpOpEvaluator , // TODO:RV: Enable when Implemented: TR::TreeEvaluator::iuminEvaluator , // TR::iumin // min of 2 or more unsigned integers
TR::TreeEvaluator::unImpOpEvaluator , // TODO:RV: Enable when Implemented: TR::TreeEvaluator::lminEvaluator , // TR::lmin // min of 2 or more longs
TR::TreeEvaluator::unImpOpEvaluator , // TODO:RV: Enable when Implemented: TR::TreeEvaluator::luminEvaluator , // TR::lumin // min of 2 or more unsigned longs
TR::TreeEvaluator::unImpOpEvaluator , // TODO:RV: Enable when Implemented: TR::TreeEvaluator::fminEvaluator , // TR::fmin // min of 2 or more floats
TR::TreeEvaluator::unImpOpEvaluator , // TODO:RV: Enable when Implemented: TR::TreeEvaluator::dminEvaluator , // TR::dmin // min of 2 or more doubles
TR::TreeEvaluator::imaxEvaluator , // TR::imax // max of 2 or more integers
TR::TreeEvaluator::iumaxEvaluator , // TR::iumax // max of 2 or more unsigned integers
TR::TreeEvaluator::imaxEvaluator , // TR::lmax // max of 2 or more longs
TR::TreeEvaluator::iumaxEvaluator , // TR::lumax // max of 2 or more unsigned longs
TR::TreeEvaluator::fmaxEvaluator , // TR::fmax // max of 2 or more floats
TR::TreeEvaluator::dmaxEvaluator , // TR::dmax // max of 2 or more doubles
TR::TreeEvaluator::iminEvaluator , // TR::imin // min of 2 or more integers
TR::TreeEvaluator::iuminEvaluator , // TR::iumin // min of 2 or more unsigned integers
TR::TreeEvaluator::iminEvaluator , // TR::lmin // min of 2 or more longs
TR::TreeEvaluator::iuminEvaluator , // TR::lumin // min of 2 or more unsigned longs
TR::TreeEvaluator::fminEvaluator , // TR::fmin // min of 2 or more floats
TR::TreeEvaluator::dminEvaluator , // TR::dmin // min of 2 or more doubles
TR::TreeEvaluator::unImpOpEvaluator , // TODO:RV: Enable when Implemented: TR::TreeEvaluator::trtEvaluator , // TR::trt // translate and test
TR::TreeEvaluator::unImpOpEvaluator , // TODO:RV: Enable when Implemented: TR::TreeEvaluator::trtSimpleEvaluator , // TR::trtSimple // same as TRT but ignoring the returned source byte address and table entry value
TR::TreeEvaluator::unImpOpEvaluator , // TODO:RV: Enable when Implemented: TR::TreeEvaluator::ihbitEvaluator , // TR::ihbit
Expand Down
15 changes: 2 additions & 13 deletions fvtest/compilertriltest/MaxMinTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ bool smallFp_filter(std::tuple<T, T> a)
class Int32MaxMin : public TRTest::BinaryOpTest<int32_t> {};

TEST_P(Int32MaxMin, UsingConst) {
SKIP_ON_RISCV(MissingImplementation);
auto param = TRTest::to_struct(GetParam());

char inputTrees[150] = {0};
Expand Down Expand Up @@ -95,8 +94,6 @@ TEST_P(Int32MaxMin, UsingConst) {
}

TEST_P(Int32MaxMin, UsingLoadParam) {
SKIP_ON_RISCV(MissingImplementation);

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

char inputTrees[150] = {0};
Expand Down Expand Up @@ -131,8 +128,6 @@ INSTANTIATE_TEST_CASE_P(MaxMin, Int32MaxMin, ::testing::Combine(
class Int64MaxMin : public TRTest::BinaryOpTest<int64_t> {};

TEST_P(Int64MaxMin, UsingConst) {
SKIP_ON_RISCV(MissingImplementation);

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

char inputTrees[150] = {0};
Expand Down Expand Up @@ -160,8 +155,6 @@ TEST_P(Int64MaxMin, UsingConst) {
}

TEST_P(Int64MaxMin, UsingLoadParam) {
SKIP_ON_RISCV(MissingImplementation);

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

char inputTrees[150] = {0};
Expand Down Expand Up @@ -198,8 +191,7 @@ class FloatMaxMin : public TRTest::BinaryOpTest<float> {};
TEST_P(FloatMaxMin, UsingConst) {
SKIP_ON_X86(KnownBug) << "The X86 code generator currently doesn't support fmax/fmin (see issue #4276)";
SKIP_ON_HAMMER(KnownBug) << "The AMD64 code generator currently doesn't support fmax/fmin (see issue #4276)";
SKIP_ON_RISCV(MissingImplementation) << "The RISC-V code generator currently doesn't support fmax/fmin (see issue #4276)";


auto param = TRTest::to_struct(GetParam());
char inputTrees[1024] = {0};
std::snprintf(inputTrees, sizeof(inputTrees),
Expand Down Expand Up @@ -228,8 +220,7 @@ TEST_P(FloatMaxMin, UsingConst) {
TEST_P(FloatMaxMin, UsingLoadParam) {
SKIP_ON_X86(KnownBug) << "The X86 code generator currently doesn't support fmax/fmin (see issue #4276)";
SKIP_ON_HAMMER(KnownBug) << "The AMD64 code generator currently doesn't support fmax/fmin (see issue #4276)";
SKIP_ON_RISCV(MissingImplementation) << "The RISC-V code generator currently doesn't support fmax/fmin (see issue #4276)";


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

char inputTrees[1024] = {0};
Expand Down Expand Up @@ -267,7 +258,6 @@ class DoubleMaxMin : public TRTest::BinaryOpTest<double> {};
TEST_P(DoubleMaxMin, UsingConst) {
SKIP_ON_X86(KnownBug) << "The X86 code generator currently doesn't support fmax/fmin (see issue #4276)";
SKIP_ON_HAMMER(KnownBug) << "The AMD64 code generator currently doesn't support fmax/fmin (see issue #4276)";
SKIP_ON_RISCV(MissingImplementation) << "The RISC-V code generator currently doesn't support fmax/fmin (see issue #4276)";

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

Expand Down Expand Up @@ -298,7 +288,6 @@ TEST_P(DoubleMaxMin, UsingConst) {
TEST_P(DoubleMaxMin, UsingLoadParam) {
SKIP_ON_X86(KnownBug) << "The X86 code generator currently doesn't support fmax/fmin (see issue #4276)";
SKIP_ON_HAMMER(KnownBug) << "The AMD64 code generator currently doesn't support fmax/fmin (see issue #4276)";
SKIP_ON_RISCV(MissingImplementation) << "The RISC-V code generator currently doesn't support fmax/fmin (see issue #4276)";

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

Expand Down

0 comments on commit be503a2

Please sign in to comment.