Skip to content

Commit

Permalink
AArch64: Enable shifted immediate for add/sub instructions
Browse files Browse the repository at this point in the history
This commit enables use of shifted immediate value for
`add` and `sub` instructions and their variants.

Signed-off-by: Akira Saitoh <saiaki@jp.ibm.com>
  • Loading branch information
Akira1Saitoh committed Jul 9, 2021
1 parent 42d7f62 commit 72c6a8f
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 21 deletions.
34 changes: 33 additions & 1 deletion compiler/aarch64/codegen/ARM64Debug.cpp
Expand Up @@ -1288,13 +1288,13 @@ TR_Debug::print(TR::FILE *pOutFile, TR::ARM64Trg1Src1ImmInstruction *instr)
if (op == TR::InstOpCode::subsimmx || op == TR::InstOpCode::subsimmw ||
op == TR::InstOpCode::addsimmx || op == TR::InstOpCode::addsimmw)
{
done = true;
TR::Register *r = instr->getTargetRegister();
if (r && r->getRealRegister()
&& toRealRegister(r)->getRegisterNumber() == TR::RealRegister::xzr)
{
// cmp/cmn alias
char *mnemonic = NULL;
done = true;
switch (op)
{
case TR::InstOpCode::subsimmx:
Expand All @@ -1313,6 +1313,30 @@ TR_Debug::print(TR::FILE *pOutFile, TR::ARM64Trg1Src1ImmInstruction *instr)
print(pOutFile, instr->getSource1Register(), TR_WordReg);
trfprintf(pOutFile, ", %d", instr->getSourceImmediate());
}
else
{
trfprintf(pOutFile, "%s \t", getOpCodeName(&instr->getOpCode()));
print(pOutFile, instr->getTargetRegister(), TR_WordReg); trfprintf(pOutFile, ", ");
print(pOutFile, instr->getSource1Register(), TR_WordReg);
trfprintf(pOutFile, ", %d", instr->getSourceImmediate());
}
if (instr->getNbit())
{
trfprintf(pOutFile, ", LSL #%d", 12);
}
}
else if ((op == TR::InstOpCode::subimmx || op == TR::InstOpCode::subimmw ||
op == TR::InstOpCode::addimmx || op == TR::InstOpCode::addimmw))
{
done = true;
trfprintf(pOutFile, "%s \t", getOpCodeName(&instr->getOpCode()));
print(pOutFile, instr->getTargetRegister(), TR_WordReg); trfprintf(pOutFile, ", ");
print(pOutFile, instr->getSource1Register(), TR_WordReg);
trfprintf(pOutFile, ", %d", instr->getSourceImmediate());
if (instr->getNbit())
{
trfprintf(pOutFile, ", LSL #%d", 12);
}
}
else if (op == TR::InstOpCode::sbfmx || op == TR::InstOpCode::sbfmw)
{
Expand Down Expand Up @@ -1495,6 +1519,10 @@ TR_Debug::print(TR::FILE *pOutFile, TR::ARM64ZeroSrc1ImmInstruction *instr)
trfprintf(pOutFile, "cmpimm%c \t", (op == TR::InstOpCode::subsimmx) ? 'x' : 'w');
print(pOutFile, instr->getSource1Register(), TR_WordReg);
trfprintf(pOutFile, ", %d", instr->getSourceImmediate());
if (instr->getNbit())
{
trfprintf(pOutFile, ", LSL #%d", 12);
}
}
else if (op == TR::InstOpCode::addsimmx || op == TR::InstOpCode::addsimmw)
{
Expand All @@ -1503,6 +1531,10 @@ TR_Debug::print(TR::FILE *pOutFile, TR::ARM64ZeroSrc1ImmInstruction *instr)
trfprintf(pOutFile, "cmnimm%c \t", (op == TR::InstOpCode::addsimmx) ? 'x' : 'w');
print(pOutFile, instr->getSource1Register(), TR_WordReg);
trfprintf(pOutFile, ", %d", instr->getSourceImmediate());
if (instr->getNbit())
{
trfprintf(pOutFile, ", LSL #%d", 12);
}
}
else if (op == TR::InstOpCode::andsimmx || op == TR::InstOpCode::andsimmw)
{
Expand Down
10 changes: 10 additions & 0 deletions compiler/aarch64/codegen/ARM64Instruction.hpp
Expand Up @@ -121,6 +121,16 @@ inline bool constantIsUnsignedImm12(uint64_t intValue)
return (intValue < (1<<12)); // 4096
}

/*
* @brief Answers if the unsigned integer value can be encoded in a 12-bit field with 12 bits shift
* @param[in] intValue : unsigned integer value
* @return true if the value can be encoded in a 12-bit field with 12 bits shift, false otherwise
*/
inline bool constantIsUnsignedImm12Shifted(uint64_t intValue)
{
return ((intValue & (~(static_cast<uint64_t>(0xfff000)))) == 0);
}

/*
* @brief Answers if the signed integer value can be placed in a 16-bit field
* @param[in] intValue : signed integer value
Expand Down
4 changes: 2 additions & 2 deletions compiler/aarch64/codegen/BinaryEvaluator.cpp
Expand Up @@ -95,11 +95,11 @@ genericBinaryEvaluator(TR::Node *node, TR::InstOpCode::Mnemonic regOp, TR::InstO
value = secondChild->getInt();
}
/* When regOp == regOpImm, an immediate version of the instruction does not exist. */
if(constantIsUnsignedImm12(value) && regOp != regOpImm)
if((constantIsUnsignedImm12(value) || constantIsUnsignedImm12Shifted(value)) && regOp != regOpImm)
{
generateTrg1Src1ImmInstruction(cg, regOpImm, node, trgReg, src1Reg, value);
}
else if (constantIsUnsignedImm12(-value) &&
else if ((constantIsUnsignedImm12(-value) || constantIsUnsignedImm12Shifted(-value)) &&
(regOpImm == TR::InstOpCode::addimmw || regOpImm == TR::InstOpCode::addimmx ||
regOpImm == TR::InstOpCode::subimmw || regOpImm == TR::InstOpCode::subimmx))
{
Expand Down
16 changes: 4 additions & 12 deletions compiler/aarch64/codegen/ControlFlowEvaluator.cpp
Expand Up @@ -179,12 +179,8 @@ if (cg->profiledPointersRequireRelocation() && secondChild->getOpCodeValue() ==
if (secondChild->getOpCode().isLoadConst() && secondChild->getRegister() == NULL)
{
int64_t value = is64bit ? secondChild->getLongInt() : secondChild->getInt();
if (constantIsUnsignedImm12(value))
{
generateCompareImmInstruction(cg, node, src1Reg, value, is64bit);
useRegCompare = false;
}
else if (constantIsUnsignedImm12(-value))
if (constantIsUnsignedImm12(value) || constantIsUnsignedImm12(-value) ||
constantIsUnsignedImm12Shifted(value) || constantIsUnsignedImm12Shifted(-value))
{
generateCompareImmInstruction(cg, node, src1Reg, value, is64bit);
useRegCompare = false;
Expand Down Expand Up @@ -379,12 +375,8 @@ static TR::Register *icmpHelper(TR::Node *node, TR::ARM64ConditionCode cc, bool
if (secondChild->getOpCode().isLoadConst() && secondChild->getRegister() == NULL)
{
int64_t value = is64bit ? secondChild->getLongInt() : secondChild->getInt();
if (constantIsUnsignedImm12(value))
{
generateCompareImmInstruction(cg, node, src1Reg, value, is64bit);
useRegCompare = false;
}
else if (constantIsUnsignedImm12(-value))
if (constantIsUnsignedImm12(value) || constantIsUnsignedImm12(-value) ||
constantIsUnsignedImm12Shifted(value) || constantIsUnsignedImm12Shifted(-value))
{
generateCompareImmInstruction(cg, node, src1Reg, value, is64bit);
useRegCompare = false;
Expand Down
45 changes: 39 additions & 6 deletions compiler/aarch64/codegen/GenerateInstructions.cpp
Expand Up @@ -208,9 +208,28 @@ TR::Instruction *generateTrg1Src1Instruction(TR::CodeGenerator *cg, TR::InstOpCo
TR::Instruction *generateTrg1Src1ImmInstruction(TR::CodeGenerator *cg, TR::InstOpCode::Mnemonic op, TR::Node *node,
TR::Register *treg, TR::Register *s1reg, uint32_t imm, TR::Instruction *preced)
{
bool isShifted = false;

if ((op == TR::InstOpCode::addimmx) || (op == TR::InstOpCode::addimmw) ||
(op == TR::InstOpCode::addsimmx) || (op == TR::InstOpCode::addsimmw) ||
(op == TR::InstOpCode::subimmx) || (op == TR::InstOpCode::subimmw) ||
(op == TR::InstOpCode::subsimmx) || (op == TR::InstOpCode::subsimmw))
{
if (constantIsUnsignedImm12(imm))
{
isShifted = false;
}
else
{
TR_ASSERT_FATAL(constantIsUnsignedImm12Shifted(imm), "immediate value out of range");
isShifted = true;
imm = imm >> 12;
}
}

if (preced)
return new (cg->trHeapMemory()) TR::ARM64Trg1Src1ImmInstruction(op, node, treg, s1reg, imm, preced, cg);
return new (cg->trHeapMemory()) TR::ARM64Trg1Src1ImmInstruction(op, node,treg, s1reg, imm, cg);
return new (cg->trHeapMemory()) TR::ARM64Trg1Src1ImmInstruction(op, node, treg, s1reg, isShifted, imm, preced, cg);
return new (cg->trHeapMemory()) TR::ARM64Trg1Src1ImmInstruction(op, node,treg, s1reg, isShifted, imm, cg);
}

TR::Instruction *generateTrg1Src2Instruction(TR::CodeGenerator *cg, TR::InstOpCode::Mnemonic op, TR::Node *node,
Expand Down Expand Up @@ -392,24 +411,38 @@ TR::Instruction *generateCompareImmInstruction(TR::CodeGenerator *cg, TR::Node *
TR::Register *sreg, int32_t imm, bool is64bit, TR::Instruction *preced)
{
TR::InstOpCode::Mnemonic op;
bool isShifted = false;

if (constantIsUnsignedImm12(imm))
{
/* Alias of SUBS instruction */
op = is64bit ? TR::InstOpCode::subsimmx : TR::InstOpCode::subsimmw;
}
else if (constantIsUnsignedImm12Shifted(imm))
{
op = is64bit ? TR::InstOpCode::subsimmx : TR::InstOpCode::subsimmw;
isShifted = true;
imm = imm >> 12;
}
else if (constantIsUnsignedImm12(-imm))
{
/* Alias of ADDS instruction */
op = is64bit ? TR::InstOpCode::addsimmx : TR::InstOpCode::addsimmw;
imm = -imm;
}
else
{
TR_ASSERT_FATAL(constantIsUnsignedImm12(-imm), "Immediate value is out of range for cmp/cmn");
TR_ASSERT_FATAL(constantIsUnsignedImm12Shifted(-imm), "Immediate value is out of range for cmp/cmn");

/* Alias of ADDS instruction */
op = is64bit ? TR::InstOpCode::addsimmx : TR::InstOpCode::addsimmw;
imm = -imm;
isShifted = true;
imm = (-imm) >> 12;
}

if (preced)
return new (cg->trHeapMemory()) TR::ARM64ZeroSrc1ImmInstruction(op, node, sreg, imm, preced, cg);
return new (cg->trHeapMemory()) TR::ARM64ZeroSrc1ImmInstruction(op, node, sreg, imm, cg);
return new (cg->trHeapMemory()) TR::ARM64ZeroSrc1ImmInstruction(op, node, sreg, isShifted, imm, preced, cg);
return new (cg->trHeapMemory()) TR::ARM64ZeroSrc1ImmInstruction(op, node, sreg, isShifted, imm, cg);
}

TR::Instruction *generateTestImmInstruction(TR::CodeGenerator *cg, TR::Node *node,
Expand Down

0 comments on commit 72c6a8f

Please sign in to comment.