Skip to content

Commit

Permalink
AArch64: Add support for tbz/tbnz instructions
Browse files Browse the repository at this point in the history
Add `TR::ARM64TestBitBranchInstruction` instruction class
to support tbz/tbnz instructions.

Signed-off-by: Akira Saitoh <saiaki@jp.ibm.com>
  • Loading branch information
Akira1Saitoh committed Oct 7, 2020
1 parent 9a61ecc commit 30c13bc
Show file tree
Hide file tree
Showing 8 changed files with 340 additions and 0 deletions.
28 changes: 28 additions & 0 deletions compiler/aarch64/codegen/ARM64BinaryEncoding.cpp
Expand Up @@ -311,6 +311,34 @@ uint8_t *TR::ARM64CompareBranchInstruction::generateBinaryEncoding()
return cursor;
}

uint8_t *TR::ARM64TestBitBranchInstruction::generateBinaryEncoding()
{
uint8_t *instructionStart = cg()->getBinaryBufferCursor();
uint8_t *cursor = instructionStart;
cursor = getOpCode().copyBinaryToBuffer(instructionStart);
insertSource1Register(toARM64Cursor(cursor));
insertBitposField(toARM64Cursor(cursor));

TR::LabelSymbol *label = getLabelSymbol();
uintptr_t destination = (uintptr_t)label->getCodeLocation();
if (destination != 0)
{
intptr_t distance = destination - (uintptr_t)cursor;
TR_ASSERT_FATAL(-0x8000 <= distance && distance < 0x8000, "Branch destination is too far away for tbz/tbnz.");

insertImmediateField(toARM64Cursor(cursor), distance);
}
else
{
cg()->addRelocation(new (cg()->trHeapMemory()) TR::LabelRelative24BitRelocation(cursor, label));
}

cursor += ARM64_INSTRUCTION_LENGTH;
setBinaryLength(ARM64_INSTRUCTION_LENGTH);
setBinaryEncoding(instructionStart);
return cursor;
}

uint8_t *TR::ARM64RegBranchInstruction::generateBinaryEncoding()
{
uint8_t *instructionStart = cg()->getBinaryBufferCursor();
Expand Down
21 changes: 21 additions & 0 deletions compiler/aarch64/codegen/ARM64Debug.cpp
Expand Up @@ -559,6 +559,9 @@ TR_Debug::print(TR::FILE *pOutFile, TR::Instruction *instr)
case OMR::Instruction::IsCompareBranch:
print(pOutFile, (TR::ARM64CompareBranchInstruction *)instr);
break;
case OMR::Instruction::IsTestBitBranch:
print(pOutFile, (TR::ARM64TestBitBranchInstruction *)instr);
break;
#ifdef J9_PROJECT_SPECIFIC
case OMR::Instruction::IsVirtualGuardNOP:
print(pOutFile, (TR::ARM64VirtualGuardNOPInstruction *)instr);
Expand Down Expand Up @@ -787,6 +790,24 @@ TR_Debug::print(TR::FILE *pOutFile, TR::ARM64CompareBranchInstruction *instr)
trfflush(_comp->getOutFile());
}

void
TR_Debug::print(TR::FILE *pOutFile, TR::ARM64TestBitBranchInstruction *instr)
{
printPrefix(pOutFile, instr);

TR::LabelSymbol *label = instr->getLabelSymbol();
TR::Snippet *snippet = label ? label->getSnippet() : NULL;
trfprintf(pOutFile, "%s \t", getOpCodeName(&instr->getOpCode()));
print(pOutFile, instr->getSource1Register(), TR_WordReg); trfprintf(pOutFile, ", ");
trfprintf(pOutFile, "#%d, ", instr->getBitPos());
print(pOutFile, label);
if (snippet)
{
trfprintf(pOutFile, " (%s)", getName(snippet));
}
trfflush(_comp->getOutFile());
}

void
TR_Debug::print(TR::FILE *pOutFile, TR::ARM64RegBranchInstruction *instr)
{
Expand Down
40 changes: 40 additions & 0 deletions compiler/aarch64/codegen/ARM64Instruction.cpp
Expand Up @@ -671,6 +671,46 @@ void TR::ARM64CompareBranchInstruction::assignRegisters(TR_RegisterKinds kindToB
assignRegistersForOutOfLineCodeSection(kindToBeAssigned);
}

// TR::ARM64TestBitBranchInstruction:: member functions

bool TR::ARM64TestBitBranchInstruction::refsRegister(TR::Register *reg)
{
return (reg == getSource1Register());
}

bool TR::ARM64TestBitBranchInstruction::usesRegister(TR::Register *reg)
{
return (reg == getSource1Register());
}

bool TR::ARM64TestBitBranchInstruction::defsRegister(TR::Register *reg)
{
return false;
}

bool TR::ARM64TestBitBranchInstruction::defsRealRegister(TR::Register *reg)
{
return false;
}

void TR::ARM64TestBitBranchInstruction::assignRegisters(TR_RegisterKinds kindToBeAssigned)
{
TR::Machine *machine = cg()->machine();
TR::Register *source1Virtual = getSource1Register();

if (getDependencyConditions())
getDependencyConditions()->assignPostConditionRegisters(this, kindToBeAssigned, cg());

TR::RealRegister *assignedSource1Register = machine->assignOneRegister(this, source1Virtual);

if (getDependencyConditions())
getDependencyConditions()->assignPreConditionRegisters(this->getPrev(), kindToBeAssigned, cg());

setSource1Register(assignedSource1Register);

assignRegistersForOutOfLineCodeSection(kindToBeAssigned);
}

// TR::ARM64RegBranchInstruction:: member functions

bool TR::ARM64RegBranchInstruction::refsRegister(TR::Register *reg)
Expand Down
190 changes: 190 additions & 0 deletions compiler/aarch64/codegen/ARM64Instruction.hpp
Expand Up @@ -861,6 +861,196 @@ class ARM64CompareBranchInstruction : public ARM64LabelInstruction
virtual uint8_t *generateBinaryEncoding();
};

class ARM64TestBitBranchInstruction : public ARM64LabelInstruction
{
int32_t _estimatedBinaryLocation;
TR::Register *_source1Register;
uint32_t _bitpos;

public:

/*
* @brief Constructor
* @param[in] op : instruction opcode
* @param[in] node : node
* @param[in] sreg : source register
* @param[in] bitpos : bit position to test
* @param[in] sym : label symbol
* @param[in] cg : CodeGenerator
*/
ARM64TestBitBranchInstruction(TR::InstOpCode::Mnemonic op, TR::Node *node, TR::Register *sreg, uint32_t bitpos, TR::LabelSymbol *sym,
TR::CodeGenerator *cg)
: ARM64LabelInstruction(op, node, sym, cg), _source1Register(sreg),
_estimatedBinaryLocation(0), _bitpos(bitpos)
{
useRegister(sreg);
}

/*
* @brief Constructor
* @param[in] op : instruction opcode
* @param[in] node : node
* @param[in] sreg : source register
* @param[in] bitpos : bit position to test
* @param[in] sym : label symbol
* @param[in] precedingInstruction : preceding instruction
* @param[in] cg : CodeGenerator
*/
ARM64TestBitBranchInstruction(TR::InstOpCode::Mnemonic op, TR::Node *node, TR::Register *sreg, uint32_t bitpos, TR::LabelSymbol *sym,
TR::Instruction *precedingInstruction, TR::CodeGenerator *cg)
: ARM64LabelInstruction(op, node, sym, precedingInstruction, cg), _source1Register(sreg),
_estimatedBinaryLocation(0), _bitpos(bitpos)
{
useRegister(sreg);
}

/*
* @brief Constructor
* @param[in] op : instruction opcode
* @param[in] node : node
* @param[in] sreg : source register
* @param[in] bitpos : bit position to test
* @param[in] sym : label symbol
* @param[in] cond : register dependency condition
* @param[in] cg : CodeGenerator
*/
ARM64TestBitBranchInstruction(TR::InstOpCode::Mnemonic op, TR::Node *node, TR::Register *sreg, uint32_t bitpos, TR::LabelSymbol *sym,
TR::RegisterDependencyConditions *cond, TR::CodeGenerator *cg)
: ARM64LabelInstruction(op, node, sym, cond, cg), _source1Register(sreg),
_estimatedBinaryLocation(0), _bitpos(bitpos)
{
useRegister(sreg);
}

/*
* @brief Constructor
* @param[in] op : instruction opcode
* @param[in] node : node
* @param[in] sreg : source register
* @param[in] bitpos : bit position to test
* @param[in] sym : label symbol
* @param[in] cond s : register dependency condition
* @param[in] precedingInstruction : preceding instruction
* @param[in] cg : CodeGenerator
*/
ARM64TestBitBranchInstruction(TR::InstOpCode::Mnemonic op, TR::Node *node, TR::Register *sreg, uint32_t bitpos, TR::LabelSymbol *sym,
TR::RegisterDependencyConditions *cond, TR::Instruction *precedingInstruction, TR::CodeGenerator *cg)
: ARM64LabelInstruction(op, node, sym, cond, precedingInstruction, cg), _source1Register(sreg),
_estimatedBinaryLocation(0), _bitpos(bitpos)
{
useRegister(sreg);
}

/**
* @brief Gets instruction kind
* @return instruction kind
*/
virtual Kind getKind() { return IsTestBitBranch; }

/**
* @brief Gets bit position
* @return bit position
*/
uint32_t getBitPos() { return _bitpos; }

/**
* @brief Sets bit position
* @param[in] bitpos : bit position
* @return bit position
*/
uint32_t setBitPos(uint32_t bitpos) { return (_bitpos = bitpos);}

/**
* @brief Gets estimated binary location
* @return estimated binary location
*/
int32_t getEstimatedBinaryLocation() {return _estimatedBinaryLocation;}
/**
* @brief Sets estimated binary location
* @param[in] l : estimated binary location
* @return estimated binary location
*/
int32_t setEstimatedBinaryLocation(int32_t l) {return (_estimatedBinaryLocation = l);}

/**
* @brief Gets source register
* @return source register
*/
TR::Register *getSource1Register() {return _source1Register;}
/**
* @brief Sets source register
* @param[in] sr : source register
* @return source register
*/
TR::Register *setSource1Register(TR::Register *sr) {return (_source1Register = sr);}
/**
* @brief Sets immediate field in binary encoding
* @param[in] instruction : instruction cursor
* @param[in] distance : branch distance
*/
void insertImmediateField(uint32_t *instruction, int32_t distance)
{
TR_ASSERT_FATAL((distance & 0x3) == 0, "branch distance is not aligned");
*instruction |= ((distance >> 2) & 0x3fff) << 5;
}

/**
* @brief Sets source register in binary encoding
* @param[in] instruction : instruction cursor
*/
void insertSource1Register(uint32_t *instruction)
{
TR::RealRegister *source1 = toRealRegister(_source1Register);
source1->setRegisterFieldRD(instruction);
}

/**
* @brief Sets bit position field in binary encoding
* @param[in] instruction : instruction cursor
*/
void insertBitposField(uint32_t *instruction)
{
TR_ASSERT_FATAL(_bitpos <= 63, "bit position must be 0 to 63");
*instruction |= (((_bitpos >> 5) & 1) << 31) | ((_bitpos & 0x1f) << 19);
}

/**
* @brief Answers whether this instruction references the given virtual register
* @param[in] reg : virtual register
* @return true when the instruction references the virtual register
*/
virtual bool refsRegister(TR::Register *reg);
/**
* @brief Answers whether this instruction uses the given virtual register
* @param[in] reg : virtual register
* @return true when the instruction uses the virtual register
*/
virtual bool usesRegister(TR::Register *reg);
/**
* @brief Answers whether this instruction defines the given virtual register
* @param[in] reg : virtual register
* @return true when the instruction defines the virtual register
*/
virtual bool defsRegister(TR::Register *reg);
/**
* @brief Answers whether this instruction defines the given real register
* @param[in] reg : real register
* @return true when the instruction defines the real register
*/
virtual bool defsRealRegister(TR::Register *reg);
/**
* @brief Assigns registers
* @param[in] kindToBeAssigned : register kind
*/
virtual void assignRegisters(TR_RegisterKinds kindToBeAssigned);

/**
* @brief Generates binary encoding of the instruction
* @return instruction cursor
*/
virtual uint8_t *generateBinaryEncoding();
};

class ARM64RegBranchInstruction : public TR::Instruction
{
TR::Register *_register;
Expand Down
16 changes: 16 additions & 0 deletions compiler/aarch64/codegen/GenerateInstructions.cpp
Expand Up @@ -125,6 +125,22 @@ TR::Instruction *generateCompareBranchInstruction(TR::CodeGenerator *cg, TR::Ins
return new (cg->trHeapMemory()) TR::ARM64CompareBranchInstruction(op, node, sreg, sym, cond, cg);
}

TR::Instruction *generateTestBitBranchInstruction(TR::CodeGenerator *cg, TR::InstOpCode::Mnemonic op, TR::Node *node,
TR::Register *sreg, uint32_t bitpos, TR::LabelSymbol *sym, TR::Instruction *preced)
{
if (preced)
return new (cg->trHeapMemory()) TR::ARM64TestBitBranchInstruction(op, node, sreg, bitpos, sym, preced, cg);
return new (cg->trHeapMemory()) TR::ARM64TestBitBranchInstruction(op, node, sreg, bitpos, sym, cg);
}

TR::Instruction *generateTestBitBranchInstruction(TR::CodeGenerator *cg, TR::InstOpCode::Mnemonic op, TR::Node *node,
TR::Register *sreg, uint32_t bitpos, TR::LabelSymbol *sym, TR::RegisterDependencyConditions *cond, TR::Instruction *preced)
{
if (preced)
return new (cg->trHeapMemory()) TR::ARM64TestBitBranchInstruction(op, node, sreg, bitpos, sym, cond, preced, cg);
return new (cg->trHeapMemory()) TR::ARM64TestBitBranchInstruction(op, node, sreg, bitpos, sym, cond, cg);
}

TR::Instruction *generateRegBranchInstruction(TR::CodeGenerator *cg, TR::InstOpCode::Mnemonic op, TR::Node *node,
TR::Register *treg, TR::Instruction *preced)
{
Expand Down
42 changes: 42 additions & 0 deletions compiler/aarch64/codegen/GenerateInstructions.hpp
Expand Up @@ -242,6 +242,48 @@ TR::Instruction *generateCompareBranchInstruction(
TR::RegisterDependencyConditions *cond,
TR::Instruction *preced = NULL);

/*
* @brief Generates test bit and branch instruction
* @param[in] cg : CodeGenerator
* @param[in] op : instruction opcode
* @param[in] node : node
* @param[in] sreg : source register
* @param[in] bitpos : bit position
* @param[in] sym : label symbol
* @param[in] cond : register dependency condition
* @param[in] preced : preceding instruction
* @return generated instruction
*/
TR::Instruction *generateTestBitBranchInstruction(
TR::CodeGenerator *cg,
TR::InstOpCode::Mnemonic op,
TR::Node *node,
TR::Register *sreg,
uint32_t bitpos,
TR::LabelSymbol *sym,
TR::RegisterDependencyConditions *cond,
TR::Instruction *preced = NULL);

/*
* @brief Generates test bit and branch instruction
* @param[in] cg : CodeGenerator
* @param[in] op : instruction opcode
* @param[in] node : node
* @param[in] sreg : source register
* @param[in] bitpos : bit position
* @param[in] sym : label symbol
* @param[in] preced : preceding instruction
* @return generated instruction
*/
TR::Instruction *generateTestBitBranchInstruction(
TR::CodeGenerator *cg,
TR::InstOpCode::Mnemonic op,
TR::Node *node,
TR::Register *sreg,
uint32_t bitpos,
TR::LabelSymbol *sym,
TR::Instruction *preced = NULL);

/*
* @brief Generates branch-to-register instruction
* @param[in] cg : CodeGenerator
Expand Down
1 change: 1 addition & 0 deletions compiler/aarch64/codegen/OMRInstructionKindEnum.hpp
Expand Up @@ -33,6 +33,7 @@
IsLabel,
IsConditionalBranch,
IsCompareBranch,
IsTestBitBranch,
IsVirtualGuardNOP,
IsRegBranch,
IsAdmin,
Expand Down

0 comments on commit 30c13bc

Please sign in to comment.