Skip to content

Commit

Permalink
AArch64: Use add/sub shifted register instruction if possible
Browse files Browse the repository at this point in the history
Use add (shifted register) instruction if add operation can be
encoded into this instruction.
Similarly, use sub (shifted register) instruction if sub operation
can be encoded into this instruction.

Signed-off-by: Akira Saitoh <saiaki@jp.ibm.com>
  • Loading branch information
Akira Saitoh committed Jul 9, 2021
1 parent 42d7f62 commit 1f9ed3a
Showing 1 changed file with 121 additions and 0 deletions.
121 changes: 121 additions & 0 deletions compiler/aarch64/codegen/BinaryEvaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,103 @@ generateMaddOrMsub(TR::Node *node, TR::Node *mulNode, TR::Node *anotherNode, TR:
}
}

/**
* @brief Generates add (shifted register) or sub (shifted register) instruction if possible
*
* @param[in] node: node
* @param[in] op: mnemonic for this node
* @param[in] cg: code generator
*
* @return register which contains the result of the operation. NULL if the operation cannot be encoded in add or sub shifted register instruction.
*/
static TR::Register *
generateAddOrSubShifted(TR::Node *node, TR::InstOpCode::Mnemonic op, TR::CodeGenerator *cg)
{
TR::Node *firstChild = node->getFirstChild();
TR::Node *secondChild = node->getSecondChild();
TR::Node *source1Node = NULL;
TR::Node *source2Node = NULL;
TR::Node *shiftNode = NULL;

int32_t shiftValue;

if ((!firstChild->getOpCode().isLoadConst()) &&
(secondChild->getReferenceCount() == 1) &&
(secondChild->getRegister() == NULL) &&
secondChild->getOpCode().isShift() &&
(secondChild->getSecondChild()->getOpCodeValue() == TR::iconst))
{
source1Node = firstChild;
source2Node = secondChild->getFirstChild();
shiftValue = secondChild->getSecondChild()->getInt();
shiftNode = secondChild;
}
else if (node->getOpCode().isAdd() &&
(!secondChild->getOpCode().isLoadConst()) &&
(firstChild->getReferenceCount() == 1) &&
(firstChild->getRegister() == NULL) &&
firstChild->getOpCode().isShift() &&
(firstChild->getSecondChild()->getOpCodeValue() == TR::iconst))
{
source1Node = secondChild;
source2Node = firstChild->getFirstChild();
shiftValue = firstChild->getSecondChild()->getInt();
shiftNode = firstChild;
}
else
{
return NULL;
}

const bool is64bit = node->getDataType().isInt64();
if ((shiftValue <= 0) || (shiftValue > (is64bit ? 63 : 31)))
{
return NULL;
}
TR::Register *treg;
TR::Register *s1reg = cg->evaluate(source1Node);
TR::Register *s2reg = cg->evaluate(source2Node);
if (node->getOpCodeValue() != TR::aladd)
{
if (source1Node->getReferenceCount() == 1)
{
treg = s1reg;
}
else if (source2Node->getReferenceCount() == 1)
{
treg = s2reg;
}
else
{
treg = cg->allocateRegister();
}
}
else
{
/*
* Because treg can contain an internal pointer, we cannot use the same virtual register
* for treg and sources for aladd except for the case
* where s1reg also contains an internal pointer and has the same pinning array as the node.
*/
if ((1 == source1Node->getReferenceCount()) && node->isInternalPointer() && s1reg->containsInternalPointer() &&
(node->getPinningArrayPointer() == s1reg->getPinningArrayPointer()))
{
treg = s1reg;
}
else
{
treg = cg->allocateRegister();
}
}
TR::ARM64ShiftCode code = (shiftNode->getOpCode().isLeftShift() ? TR::SH_LSL : (shiftNode->getOpCode().isShiftLogical() ? TR::SH_LSR : TR::SH_ASR));

generateTrg1Src2ShiftedInstruction(cg, op, node, treg, s1reg, s2reg, code, shiftValue);
node->setRegister(treg);
cg->recursivelyDecReferenceCount(shiftNode);
cg->decReferenceCount(source1Node);
return treg;
}

TR::Register *
OMR::ARM64::TreeEvaluator::iaddEvaluator(TR::Node *node, TR::CodeGenerator *cg)
{
Expand All @@ -197,6 +294,12 @@ OMR::ARM64::TreeEvaluator::iaddEvaluator(TR::Node *node, TR::CodeGenerator *cg)
return retReg;
}

retReg = generateAddOrSubShifted(node, TR::InstOpCode::addw, cg);
if (retReg)
{
return retReg;
}

return genericBinaryEvaluator(node, TR::InstOpCode::addw, TR::InstOpCode::addimmw, false, cg);
}

Expand All @@ -218,6 +321,12 @@ OMR::ARM64::TreeEvaluator::laddEvaluator(TR::Node *node, TR::CodeGenerator *cg)
return retReg;
}

retReg = generateAddOrSubShifted(node, TR::InstOpCode::addx, cg);
if (retReg)
{
return retReg;
}

return genericBinaryEvaluator(node, TR::InstOpCode::addx, TR::InstOpCode::addimmx, true, cg);
}

Expand All @@ -234,6 +343,12 @@ OMR::ARM64::TreeEvaluator::isubEvaluator(TR::Node *node, TR::CodeGenerator *cg)
return retReg;
}

retReg = generateAddOrSubShifted(node, TR::InstOpCode::subw, cg);
if (retReg)
{
return retReg;
}

return genericBinaryEvaluator(node, TR::InstOpCode::subw, TR::InstOpCode::subimmw, false, cg);
}

Expand All @@ -250,6 +365,12 @@ OMR::ARM64::TreeEvaluator::lsubEvaluator(TR::Node *node, TR::CodeGenerator *cg)
return retReg;
}

retReg = generateAddOrSubShifted(node, TR::InstOpCode::subx, cg);
if (retReg)
{
return retReg;
}

return genericBinaryEvaluator(node, TR::InstOpCode::subx, TR::InstOpCode::subimmx, true, cg);
}

Expand Down

0 comments on commit 1f9ed3a

Please sign in to comment.