aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Target
diff options
context:
space:
mode:
authorVikram S. Adve <vadve@cs.uiuc.edu>2001-11-04 19:34:49 +0000
committerVikram S. Adve <vadve@cs.uiuc.edu>2001-11-04 19:34:49 +0000
commitb7f06f46a176b2f19349d44581b0523297c8efb9 (patch)
treeb6a8073951335e67849887cc6b5a31b82ce3f826 /lib/Target
parent8e7f4091695aad705f84398ede1fccc3796b1fad (diff)
downloadexternal_llvm-b7f06f46a176b2f19349d44581b0523297c8efb9.zip
external_llvm-b7f06f46a176b2f19349d44581b0523297c8efb9.tar.gz
external_llvm-b7f06f46a176b2f19349d44581b0523297c8efb9.tar.bz2
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
Diffstat (limited to 'lib/Target')
-rw-r--r--lib/Target/SparcV9/SparcV9Instr.def7
-rw-r--r--lib/Target/SparcV9/SparcV9InstrSelection.cpp157
-rw-r--r--lib/Target/SparcV9/SparcV9Internals.h23
3 files changed, 128 insertions, 59 deletions
diff --git a/lib/Target/SparcV9/SparcV9Instr.def b/lib/Target/SparcV9/SparcV9Instr.def
index cf70b31..2e8d20b 100644
--- a/lib/Target/SparcV9/SparcV9Instr.def
+++ b/lib/Target/SparcV9/SparcV9Instr.def
@@ -426,15 +426,14 @@ I(CALL , "call", 1, -1, B29, true , 1, 2, SPARC_CTI, M_BRANCH_FLAG | M_CALL_F
I(JMPLCALL, "jmpl", 3, -1, B12, true , 1, 2, SPARC_CTI, M_BRANCH_FLAG | M_CALL_FLAG )
I(JMPLRET, "jmpl", 3, -1, B12, true , 1, 2, SPARC_CTI, M_BRANCH_FLAG | M_RET_FLAG)
I(RETURN, "return", 2, -1, 0, false, 1, 2, SPARC_CTI, M_BRANCH_FLAG | M_RET_FLAG)
-
+
// SAVE and restore instructions
I(SAVE , "save", 3, 2, B12, true , 0, 1, SPARC_SINGLE, M_INT_FLAG | M_ARITH_FLAG)
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.
diff --git a/lib/Target/SparcV9/SparcV9InstrSelection.cpp b/lib/Target/SparcV9/SparcV9InstrSelection.cpp
index 2533d14..921bcbc 100644
--- a/lib/Target/SparcV9/SparcV9InstrSelection.cpp
+++ b/lib/Target/SparcV9/SparcV9InstrSelection.cpp
@@ -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();
@@ -1150,7 +1183,7 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
mvec[n] = new MachineInstr(NOP);
break;
- }
+ }
case 3: // stmt: Store(reg,reg)
case 4: // stmt: Store(reg,ptrreg)
@@ -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);
@@ -1213,41 +1248,47 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
break;
}
// ELSE FALL THROUGH
- }
+ }
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);
-
+
// false branch
int n = numInstr++;
mvec[n] = new MachineInstr(BA);
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);
break;
- }
+ }
case 208: // stmt: BrCond(boolconst)
- {
+ {
// boolconst => boolean is a constant; use BA to first or second label
ConstPoolVal* constVal =
cast<ConstPoolVal>(subtreeRoot->leftChild()->getValue());
@@ -1262,13 +1303,12 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
// delay slot
mvec[numInstr++] = new MachineInstr(NOP);
break;
- }
+ }
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());
@@ -1289,7 +1329,7 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
// delay slot
mvec[numInstr++] = new MachineInstr(NOP);
break;
- }
+ }
case 9: // stmt: Switch(reg)
assert(0 && "*** SWITCH instruction is not implemented yet.");
@@ -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;
}
@@ -1637,8 +1698,8 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
SetOperandsForMemInstr(mvec[0], subtreeRoot, target);
break;
- case 57: // reg: Alloca: Implement as 1 instruction:
- { // add %fp, offsetFromFP -> result
+ case 57: // reg: Alloca: Implement as 1 instruction:
+ { // add %fp, offsetFromFP -> result
Instruction* instr = subtreeRoot->getInstruction();
const PointerType* instrType = (const PointerType*) instr->getType();
assert(instrType->isPointerType());
@@ -1666,12 +1727,12 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
mvec[0]->SetMachineOperand(2, MachineOperand::MO_VirtualRegister,
instr);
break;
- }
+ }
case 58: // reg: Alloca(reg): Implement as 3 instructions:
// mul num, typeSz -> tmp
// sub %sp, tmp -> %sp
- { // add %sp, frameSizeBelowDynamicArea -> result
+ { // add %sp, frameSizeBelowDynamicArea -> result
Instruction* instr = subtreeRoot->getInstruction();
const PointerType* instrType = (const PointerType*) instr->getType();
assert(instrType->isPointerType() &&
@@ -1730,17 +1791,17 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
lowerAreaSizeVal);
mvec[2]->SetMachineOperand(2,MachineOperand::MO_VirtualRegister,instr);
break;
- }
+ }
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();
@@ -1792,7 +1853,7 @@ GetInstructionsByRule(InstructionNode* subtreeRoot,
mvec[numInstr++] = new MachineInstr(NOP); // delay slot
break;
- }
+ }
case 62: // reg: Shl(reg, reg)
opType = subtreeRoot->leftChild()->getValue()->getType();
diff --git a/lib/Target/SparcV9/SparcV9Internals.h b/lib/Target/SparcV9/SparcV9Internals.h
index 2f151b7..cc25377 100644
--- a/lib/Target/SparcV9/SparcV9Internals.h
+++ b/lib/Target/SparcV9/SparcV9Internals.h
@@ -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