Skip to content

Commit

Permalink
AArch64: Use negated constant value for add/sub node if it is more co…
Browse files Browse the repository at this point in the history
…ncise

This commit changes `genericBinaryEvaluator` to use negated value for add/sub
operation if the negated value can be loaded into the register with the fewer
instructions than original value.
Also, `genericBinaryEvaluator` is changed to set a register to the constant node
if the constant cannot be encoded into the instruction and the negated value is not used.
This change prevents constant loading instructions from generated multiple times
even if the constant node has multiple reference counts.

Signed-off-by: Akira Saitoh <saiaki@jp.ibm.com>
  • Loading branch information
Akira Saitoh committed Jul 15, 2021
1 parent 3d4e5f6 commit 31a3582
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 22 deletions.
46 changes: 40 additions & 6 deletions compiler/aarch64/codegen/BinaryEvaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,17 +125,51 @@ genericBinaryEvaluator(TR::Node *node, TR::InstOpCode::Mnemonic regOp, TR::InstO
}
else
{
src2Reg = cg->allocateRegister();
if(is64Bit)
TR::InstOpCode::Mnemonic negatedOp = TR::InstOpCode::bad;

if ((secondChild->getReferenceCount() == 1) &&
(regOp == TR::InstOpCode::addw || regOp == TR::InstOpCode::addx ||
regOp == TR::InstOpCode::subw || regOp == TR::InstOpCode::subx) &&
(is64Bit ? shouldLoadNegatedConstant64(value) : shouldLoadNegatedConstant32(value)))
{
loadConstant64(cg, node, value, src2Reg);
switch (regOp)
{
case TR::InstOpCode::addw:
negatedOp = TR::InstOpCode::subw;
break;
case TR::InstOpCode::addx:
negatedOp = TR::InstOpCode::subx;
break;
case TR::InstOpCode::subw:
negatedOp = TR::InstOpCode::addw;
break;
case TR::InstOpCode::subx:
negatedOp = TR::InstOpCode::addx;
break;
default:
TR_ASSERT_FATAL(false, "Unsupported op");
}
}
if (negatedOp != TR::InstOpCode::bad)
{
src2Reg = cg->allocateRegister();

if(is64Bit)
{
loadConstant64(cg, node, -value, src2Reg);
}
else
{
loadConstant32(cg, node, -value, src2Reg);
}
generateTrg1Src2Instruction(cg, negatedOp, node, trgReg, src1Reg, src2Reg);
cg->stopUsingRegister(src2Reg);
}
else
{
loadConstant32(cg, node, value, src2Reg);
src2Reg = cg->evaluate(secondChild);
generateTrg1Src2Instruction(cg, regOp, node, trgReg, src1Reg, src2Reg);
}
generateTrg1Src2Instruction(cg, regOp, node, trgReg, src1Reg, src2Reg);
cg->stopUsingRegister(src2Reg);
}
}
else
Expand Down
18 changes: 18 additions & 0 deletions compiler/aarch64/codegen/OMRCodeGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,24 @@ namespace TR { class ARM64ConstantDataSnippet; }
namespace TR { class RegisterDependencyConditions; }
namespace TR { class DebugCounterBase; }

/**
* @brief Answers if loading negated value is more concise
*
* @param[in] value : 32bit constant value
*
* @return true if loading negated value is more concise.
*/
extern bool shouldLoadNegatedConstant32(int32_t value);

/**
* @brief Answers if loading negated value is more concise
*
* @param[in] value : 64bit constant value
*
* @return true if loading negated value is more concise.
*/
extern bool shouldLoadNegatedConstant64(int64_t value);

/**
* @brief Generates instructions for loading 32-bit integer value to a register
* @param[in] cg : CodeGenerator
Expand Down
100 changes: 84 additions & 16 deletions compiler/aarch64/codegen/OMRTreeEvaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/

#include <utility>
#include "codegen/ARM64HelperCallSnippet.hpp"
#include "codegen/ARM64Instruction.hpp"
#include "codegen/ARM64ShiftCode.hpp"
Expand Down Expand Up @@ -2169,6 +2170,87 @@ TR::Instruction *loadAddressConstantInSnippet(TR::CodeGenerator *cg, TR::Node *n
return generateTrg1ImmSymInstruction(cg, TR::InstOpCode::ldrx, node, targetRegister, 0, labelSym, cursor);
}

bool shouldLoadNegatedConstant32(int32_t value)
{
int32_t negatedValue = -value;
if ((value >= -65535 && value <= 65535) ||
((value & 0xFFFF) == 0) ||
((value & 0xFFFF) == 0xFFFF))
{
return false;
}
else if ((negatedValue >= -65535 && negatedValue <= 65535) ||
((negatedValue & 0xFFFF) == 0) ||
((negatedValue & 0xFFFF) == 0xFFFF))
{
return true;
}
else
{
return false;
}
}

/**
* @brief Helper function for analyzing instructions required for loading 64bit constant value.
* This functions returns a pair of number of instructions required and a bool flag.
* If the bool flag is true, movz instruction should be used. Otherwise, movz should be used.
*
* @param[out] h : 4 elements array of 16bit integer
* @param[in] value: 64bit value to load
*
* @return a pair of number of instructions required and a bool flag
*/
static
std::pair<int32_t, bool> analyzeLoadConstant64(uint16_t h[4], int64_t value)
{
int32_t count0000 = 0, countFFFF = 0;
int32_t i;

for (i = 0; i < 4; i++)
{
h[i] = (value >> (i * 16)) & 0xFFFF;
if (h[i] == 0)
{
count0000++;
}
else if (h[i] == 0xFFFF)
{
countFFFF++;
}
}

return std::make_pair(4 - std::max(count0000, countFFFF), count0000 >= countFFFF);
}

bool shouldLoadNegatedConstant64(int64_t value)
{
int64_t negatedValue = -value;
// If upper 48bit of value is all 0 or value is -1
if (((value & (~static_cast<int64_t>(0xffff))) == 0) || (~value == 0LL))
{
return false;
}
else if ((negatedValue & (~static_cast<int64_t>(0xffff))) == 0)
{
return true;
}
uint16_t h[4];

auto numInstrAndUseMovz = analyzeLoadConstant64(h, value);
if (numInstrAndUseMovz.first == 1)
{
return false;
}
auto numInstrAndUseMovzNeg = analyzeLoadConstant64(h, negatedValue);
if (numInstrAndUseMovzNeg.first == 1)
{
return true;
}

return numInstrAndUseMovzNeg.first < numInstrAndUseMovz.first;
}

TR::Instruction *loadConstant32(TR::CodeGenerator *cg, TR::Node *node, int32_t value, TR::Register *trgReg, TR::Instruction *cursor)
{
TR::Instruction *insertingInstructions = cursor;
Expand Down Expand Up @@ -2237,23 +2319,9 @@ TR::Instruction *loadConstant64(TR::CodeGenerator *cg, TR::Node *node, int64_t v
else
{
uint16_t h[4];
int32_t count0000 = 0, countFFFF = 0;
int32_t use_movz;
int32_t i;

for (i = 0; i < 4; i++)
{
h[i] = (value >> (i * 16)) & 0xFFFF;
if (h[i] == 0)
{
count0000++;
}
else if (h[i] == 0xFFFF)
{
countFFFF++;
}
}
use_movz = (count0000 >= countFFFF);
auto numInstrAndUseMovz = analyzeLoadConstant64(h, value);
int32_t use_movz = numInstrAndUseMovz.second;

TR::Instruction *start = cursor;

Expand Down

0 comments on commit 31a3582

Please sign in to comment.