mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-18 12:29:21 +00:00
Fixed instruction information for RDCCR and WRCCR.
Fixed selection to create a TmpInstruction for each integer CC register (since it is an implicit side-effect, unlike FP CC registers which are explicit operands). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@1120 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
8e7f409169
commit
b7f06f46a1
@ -432,9 +432,8 @@ I(SAVE , "save", 3, 2, B12, true , 0, 1, SPARC_SINGLE, M_INT_FLAG | M_ARITH_F
|
||||
I(RESTORE, "restore", 3, 2, B12, true , 0, 1, SPARC_SINGLE, M_INT_FLAG | M_ARITH_FLAG)
|
||||
|
||||
// Read and Write CCR register from/to an int reg
|
||||
I(RDCCR, "rd", 2, 1, 0, false, 0, 1, SPARC_IEUN, M_INT_FLAG)
|
||||
I(WRCCR, "wr", 3, 2, 0, false, 0, 1, SPARC_IEUN, M_INT_FLAG)
|
||||
|
||||
I(RDCCR, "rd", 2, 1, 0, false, 0, 1, SPARC_SINGLE, M_INT_FLAG | M_CC_FLAG)
|
||||
I(WRCCR, "wr", 3, 2, 0, false, 0, 1, SPARC_SINGLE, M_INT_FLAG | M_CC_FLAG)
|
||||
|
||||
// Synthetic phi operation for near-SSA form of machine code
|
||||
// Number of operands is variable, indicated by -1. Result is the first op.
|
||||
|
@ -134,6 +134,39 @@ ChooseBFpccInstruction(const InstructionNode* instrNode,
|
||||
}
|
||||
|
||||
|
||||
// Create a unique TmpInstruction for a boolean value,
|
||||
// representing the CC register used by a branch on that value.
|
||||
// For now, hack this using a little static cache of TmpInstructions.
|
||||
// Eventually the entire BURG instruction selection should be put
|
||||
// into a separate class that can hold such information.
|
||||
// The static cache is not too bad because that memory for these
|
||||
// TmpInstructions will be freed elsewhere in any case.
|
||||
//
|
||||
static TmpInstruction*
|
||||
GetTmpForCC(Value* boolVal, const Method* method)
|
||||
{
|
||||
typedef hash_map<const Value*, TmpInstruction*> BoolTmpCache;
|
||||
static BoolTmpCache boolToTmpCache; // Map boolVal -> TmpInstruction*
|
||||
static const Method* lastMethod = NULL; // Use to flush cache between methods
|
||||
|
||||
assert(boolVal->getType() == Type::BoolTy && "Weird but ok! Delete assert");
|
||||
|
||||
if (lastMethod != method)
|
||||
{
|
||||
lastMethod = method;
|
||||
boolToTmpCache.clear();
|
||||
}
|
||||
|
||||
// Look for tmpI and create a new one otherswise.
|
||||
// new value is directly written to map using
|
||||
TmpInstruction*& tmpI = boolToTmpCache[boolVal];
|
||||
if (tmpI == NULL)
|
||||
tmpI = new TmpInstruction(TMP_INSTRUCTION_OPCODE, boolVal, NULL);
|
||||
|
||||
return tmpI;
|
||||
}
|
||||
|
||||
|
||||
static inline MachineOpCode
|
||||
ChooseBccInstruction(const InstructionNode* instrNode,
|
||||
bool& isFPBranch)
|
||||
@ -1123,12 +1156,12 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
|
||||
switch(ruleForNode) {
|
||||
case 1: // stmt: Ret
|
||||
case 2: // stmt: RetValue(reg)
|
||||
// NOTE: Prepass of register allocation is responsible
|
||||
{ // NOTE: Prepass of register allocation is responsible
|
||||
// for moving return value to appropriate register.
|
||||
// Mark the return-address register as a hidden virtual reg.
|
||||
// Mark the return value register as an implicit ref of
|
||||
// the machine instruction.
|
||||
{ // Finally put a NOP in the delay slot.
|
||||
// Finally put a NOP in the delay slot.
|
||||
ReturnInst* returnInstr = (ReturnInst*) subtreeRoot->getInstruction();
|
||||
assert(returnInstr->getOpcode() == Instruction::Ret);
|
||||
Method* method = returnInstr->getParent()->getParent();
|
||||
@ -1172,11 +1205,11 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
|
||||
break;
|
||||
|
||||
case 206: // stmt: BrCond(setCCconst)
|
||||
// setCCconst => boolean was computed with `%b = setCC type reg1 const'
|
||||
{ // setCCconst => boolean was computed with `%b = setCC type reg1 const'
|
||||
// If the constant is ZERO, we can use the branch-on-integer-register
|
||||
// instructions and avoid the SUBcc instruction entirely.
|
||||
// Otherwise this is just the same as case 5, so just fall through.
|
||||
{
|
||||
//
|
||||
InstrTreeNode* constNode = subtreeRoot->leftChild()->rightChild();
|
||||
assert(constNode &&
|
||||
constNode->getNodeType() ==InstrTreeNode::NTConstNode);
|
||||
@ -1188,13 +1221,15 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
|
||||
&& GetConstantValueAsSignedInt(constVal, isValidConst) == 0
|
||||
&& isValidConst)
|
||||
{
|
||||
BranchInst* brInst=cast<BranchInst>(subtreeRoot->getInstruction());
|
||||
|
||||
// That constant is a zero after all...
|
||||
// Use the left child of setCC as the first argument!
|
||||
mvec[0] = new MachineInstr(ChooseBprInstruction(subtreeRoot));
|
||||
mvec[0]->SetMachineOperand(0, MachineOperand::MO_VirtualRegister,
|
||||
subtreeRoot->leftChild()->leftChild()->getValue());
|
||||
mvec[0]->SetMachineOperand(1, MachineOperand::MO_PCRelativeDisp,
|
||||
((BranchInst*) subtreeRoot->getInstruction())->getSuccessor(0));
|
||||
brInst->getSuccessor(0));
|
||||
|
||||
// delay slot
|
||||
mvec[numInstr++] = new MachineInstr(NOP);
|
||||
@ -1205,7 +1240,7 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
|
||||
mvec[n]->SetMachineOperand(0, MachineOperand::MO_CCRegister,
|
||||
(Value*) NULL);
|
||||
mvec[n]->SetMachineOperand(1, MachineOperand::MO_PCRelativeDisp,
|
||||
((BranchInst*) subtreeRoot->getInstruction())->getSuccessor(1));
|
||||
brInst->getSuccessor(1));
|
||||
|
||||
// delay slot
|
||||
mvec[numInstr++] = new MachineInstr(NOP);
|
||||
@ -1216,19 +1251,25 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
|
||||
}
|
||||
|
||||
case 6: // stmt: BrCond(bool)
|
||||
// bool => boolean was computed with some boolean operator
|
||||
{ // bool => boolean was computed with some boolean operator
|
||||
// (SetCC, Not, ...). We need to check whether the type was a FP,
|
||||
// signed int or unsigned int, and check the branching condition in
|
||||
// order to choose the branch to use.
|
||||
// If it is an integer CC, we also need to find the unique
|
||||
// TmpInstruction representing that CC.
|
||||
//
|
||||
{
|
||||
BranchInst* brInst = cast<BranchInst>(subtreeRoot->getInstruction());
|
||||
bool isFPBranch;
|
||||
mvec[0] = new MachineInstr(ChooseBccInstruction(subtreeRoot,
|
||||
isFPBranch));
|
||||
mvec[0]->SetMachineOperand(0, MachineOperand::MO_CCRegister,
|
||||
subtreeRoot->leftChild()->getValue());
|
||||
|
||||
Value* ccValue = isFPBranch? subtreeRoot->leftChild()->getValue()
|
||||
: GetTmpForCC(subtreeRoot->leftChild()->getValue(),
|
||||
brInst->getParent()->getParent());
|
||||
|
||||
mvec[0]->SetMachineOperand(0, MachineOperand::MO_CCRegister, ccValue);
|
||||
mvec[0]->SetMachineOperand(1, MachineOperand::MO_PCRelativeDisp,
|
||||
((BranchInst*) subtreeRoot->getInstruction())->getSuccessor(0));
|
||||
brInst->getSuccessor(0));
|
||||
|
||||
// delay slot
|
||||
mvec[numInstr++] = new MachineInstr(NOP);
|
||||
@ -1239,7 +1280,7 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
|
||||
mvec[n]->SetMachineOperand(0, MachineOperand::MO_CCRegister,
|
||||
(Value*) NULL);
|
||||
mvec[n]->SetMachineOperand(1, MachineOperand::MO_PCRelativeDisp,
|
||||
((BranchInst*) subtreeRoot->getInstruction())->getSuccessor(1));
|
||||
brInst->getSuccessor(1));
|
||||
|
||||
// delay slot
|
||||
mvec[numInstr++] = new MachineInstr(NOP);
|
||||
@ -1265,10 +1306,9 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
|
||||
}
|
||||
|
||||
case 8: // stmt: BrCond(boolreg)
|
||||
// boolreg => boolean is stored in an existing register.
|
||||
{ // boolreg => boolean is stored in an existing register.
|
||||
// Just use the branch-on-integer-register instruction!
|
||||
//
|
||||
{
|
||||
mvec[0] = new MachineInstr(BRNZ);
|
||||
mvec[0]->SetMachineOperand(0, MachineOperand::MO_VirtualRegister,
|
||||
subtreeRoot->leftChild()->getValue());
|
||||
@ -1518,24 +1558,32 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
|
||||
|
||||
case 42: // bool: SetCC(reg, reg):
|
||||
{
|
||||
// If result of the SetCC is only used for a single branch, we can
|
||||
// discard the boolean result and keep only the condition code.
|
||||
// Otherwise, the boolean value must go into an integer register.
|
||||
// To put the boolean result in a register we use a conditional move,
|
||||
// unless the result of the SUBCC instruction can be used as the bool!
|
||||
// This assumes that zero is FALSE and any non-zero integer is TRUE.
|
||||
// This generates a SUBCC instruction, putting the difference in
|
||||
// a result register, and setting a condition code.
|
||||
//
|
||||
bool keepBoolVal = (subtreeRoot->parent() == NULL ||
|
||||
((InstructionNode*) subtreeRoot->parent())
|
||||
->getInstruction()->getOpcode() !=Instruction::Br);
|
||||
bool subValIsBoolVal =
|
||||
subtreeRoot->getInstruction()->getOpcode() == Instruction::SetNE;
|
||||
// If the boolean result of the SetCC is used by anything other
|
||||
// than a single branch instruction, the boolean must be
|
||||
// computed and stored in the result register. Otherwise, discard
|
||||
// the difference (by using %g0) and keep only the condition code.
|
||||
//
|
||||
// To compute the boolean result in a register we use a conditional
|
||||
// move, unless the result of the SUBCC instruction can be used as
|
||||
// the bool! This assumes that zero is FALSE and any non-zero
|
||||
// integer is TRUE.
|
||||
//
|
||||
InstructionNode* parentNode = (InstructionNode*) subtreeRoot->parent();
|
||||
Instruction* setCCInstr = subtreeRoot->getInstruction();
|
||||
bool keepBoolVal = (parentNode == NULL ||
|
||||
parentNode->getInstruction()->getOpcode()
|
||||
!= Instruction::Br);
|
||||
bool subValIsBoolVal = setCCInstr->getOpcode() == Instruction::SetNE;
|
||||
bool keepSubVal = keepBoolVal && subValIsBoolVal;
|
||||
bool computeBoolVal = keepBoolVal && ! subValIsBoolVal;
|
||||
|
||||
bool mustClearReg;
|
||||
int valueToMove;
|
||||
MachineOpCode movOpCode;
|
||||
Value* ccValue = NULL;
|
||||
|
||||
if (subtreeRoot->leftChild()->getValue()->getType()->isIntegral() ||
|
||||
subtreeRoot->leftChild()->getValue()->getType()->isPointerType())
|
||||
@ -1548,22 +1596,32 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
|
||||
mvec[0] = new MachineInstr(SUBcc);
|
||||
Set3OperandsFromInstr(mvec[0], subtreeRoot, target, ! keepSubVal);
|
||||
|
||||
// mark the 4th operand as being a CC register, and a "result"
|
||||
// Mark the 4th operand as being a CC register, and as a def
|
||||
// A TmpInstruction is created to represent the int CC "result".
|
||||
// Unlike other instances of TmpInstruction, this one is used by
|
||||
// used by machine code of multiple LLVM instructions, viz.,
|
||||
// the SetCC and the branch. Make sure to get the same one!
|
||||
//
|
||||
TmpInstruction* tmpForCC = GetTmpForCC(setCCInstr,
|
||||
setCCInstr->getParent()->getParent());
|
||||
setCCInstr->getMachineInstrVec().addTempValue(tmpForCC);
|
||||
|
||||
mvec[0]->SetMachineOperand(3, MachineOperand::MO_CCRegister,
|
||||
subtreeRoot->getValue(),/*def*/true);
|
||||
tmpForCC, /*def*/true);
|
||||
|
||||
if (computeBoolVal)
|
||||
{ // recompute bool using the integer condition codes
|
||||
movOpCode =
|
||||
ChooseMovpccAfterSub(subtreeRoot,mustClearReg,valueToMove);
|
||||
ccValue = tmpForCC;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// FP condition: dest of FCMP should be some FCCn register
|
||||
mvec[0] = new MachineInstr(ChooseFcmpInstruction(subtreeRoot));
|
||||
mvec[0]->SetMachineOperand(0,MachineOperand::MO_CCRegister,
|
||||
subtreeRoot->getValue());
|
||||
mvec[0]->SetMachineOperand(0, MachineOperand::MO_CCRegister,
|
||||
setCCInstr);
|
||||
mvec[0]->SetMachineOperand(1,MachineOperand::MO_VirtualRegister,
|
||||
subtreeRoot->leftChild()->getValue());
|
||||
mvec[0]->SetMachineOperand(2,MachineOperand::MO_VirtualRegister,
|
||||
@ -1574,11 +1632,14 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
|
||||
mustClearReg = true;
|
||||
valueToMove = 1;
|
||||
movOpCode = ChooseMovFpccInstruction(subtreeRoot);
|
||||
ccValue = setCCInstr;
|
||||
}
|
||||
}
|
||||
|
||||
if (computeBoolVal)
|
||||
{
|
||||
assert(ccValue && "Inconsistent logic above and here");
|
||||
|
||||
if (mustClearReg)
|
||||
{// Unconditionally set register to 0
|
||||
int n = numInstr++;
|
||||
@ -1586,18 +1647,18 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
|
||||
mvec[n]->SetMachineOperand(0,MachineOperand::MO_UnextendedImmed,
|
||||
s0);
|
||||
mvec[n]->SetMachineOperand(1,MachineOperand::MO_VirtualRegister,
|
||||
subtreeRoot->getValue());
|
||||
setCCInstr);
|
||||
}
|
||||
|
||||
// Now conditionally move `valueToMove' (0 or 1) into the register
|
||||
int n = numInstr++;
|
||||
mvec[n] = new MachineInstr(movOpCode);
|
||||
mvec[n]->SetMachineOperand(0, MachineOperand::MO_CCRegister,
|
||||
subtreeRoot->getValue());
|
||||
ccValue);
|
||||
mvec[n]->SetMachineOperand(1, MachineOperand::MO_UnextendedImmed,
|
||||
valueToMove);
|
||||
mvec[n]->SetMachineOperand(2, MachineOperand::MO_VirtualRegister,
|
||||
subtreeRoot->getValue());
|
||||
setCCInstr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1733,14 +1794,14 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
|
||||
}
|
||||
|
||||
case 61: // reg: Call
|
||||
// Generate a call-indirect (i.e., jmpl) for now to expose
|
||||
{ // Generate a call-indirect (i.e., jmpl) for now to expose
|
||||
// the potential need for registers. If an absolute address
|
||||
// is available, replace this with a CALL instruction.
|
||||
// Mark both the indirection register and the return-address
|
||||
// register as hidden virtual registers.
|
||||
// Also, mark the operands of the Call and return value (if
|
||||
// any) as implicit operands of the CALL machine instruction.
|
||||
{
|
||||
//
|
||||
CallInst *callInstr = cast<CallInst>(subtreeRoot->getInstruction());
|
||||
Value *callee = callInstr->getCalledValue();
|
||||
|
||||
|
@ -871,10 +871,6 @@ const InstrIssueDelta SparcInstrIssueDeltas[] = {
|
||||
{ RETURN, true, true, 0 },
|
||||
//{ DONE, true, true, 0 },
|
||||
//{ RETRY, true, true, 0 },
|
||||
//{ WR, true, true, 0 },
|
||||
//{ WRPR, true, true, 4 },
|
||||
//{ RD, true, true, 0 },
|
||||
//{ RDPR, true, true, 0 },
|
||||
//{ TCC, true, true, 0 },
|
||||
//{ SHUTDOWN, true, true, 0 },
|
||||
|
||||
@ -902,8 +898,10 @@ const InstrIssueDelta SparcInstrIssueDeltas[] = {
|
||||
{ UDIVX, true, true, 68 },
|
||||
//{ SDIVcc, true, true, 36 },
|
||||
//{ UDIVcc, true, true, 37 },
|
||||
//{ WR, false, false, 4 },
|
||||
//{ WRPR, false, false, 4 },
|
||||
{ WRCCR, true, true, 4 },
|
||||
//{ WRPR, true, true, 4 },
|
||||
//{ RDCCR, true, true, 0 }, // no bubbles after, but see below
|
||||
//{ RDPR, true, true, 0 },
|
||||
};
|
||||
|
||||
|
||||
@ -950,7 +948,7 @@ const InstrRUsageDelta SparcInstrUsageDeltas[] = {
|
||||
|
||||
//
|
||||
// Some instructions are stalled in the GROUP stage if a CTI is in
|
||||
// the E or C stage
|
||||
// the E or C stage. We model that with a fake resource CTIDelayCycle.
|
||||
//
|
||||
{ LDD, CTIDelayCycle.rid, 1, 1 },
|
||||
//{ LDDA, CTIDelayCycle.rid, 1, 1 },
|
||||
@ -976,6 +974,17 @@ const InstrRUsageDelta SparcInstrUsageDeltas[] = {
|
||||
{ LDSW, LdReturn.rid, 2, -1 },
|
||||
{ LDSW, LdReturn.rid, 3, 1 },
|
||||
|
||||
//
|
||||
// RDPR from certain registers and RD from any register are not dispatchable
|
||||
// until four clocks after they reach the head of the instr. buffer.
|
||||
// Together with their single-issue requirement, this means all four issue
|
||||
// slots are effectively blocked for those cycles, plus the issue cycle.
|
||||
// This does not increase the latency of the instruction itself.
|
||||
//
|
||||
{ RDCCR, AllIssueSlots.rid, 0, 5 },
|
||||
{ RDCCR, AllIssueSlots.rid, 0, 5 },
|
||||
{ RDCCR, AllIssueSlots.rid, 0, 5 },
|
||||
{ RDCCR, AllIssueSlots.rid, 0, 5 },
|
||||
|
||||
#undef EXPLICIT_BUBBLES_NEEDED
|
||||
#ifdef EXPLICIT_BUBBLES_NEEDED
|
||||
|
Loading…
Reference in New Issue
Block a user