aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Target/X86
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2003-01-16 16:43:00 +0000
committerChris Lattner <sabre@nondot.org>2003-01-16 16:43:00 +0000
commit6d40c191ee4bf34ee437e7d8688d20a3eb54e88b (patch)
treeacd7639eff31e95eb3abfd7ea192add0913e8625 /lib/Target/X86
parentb037ee822c5fb19f5ec985221b602a8c3dd3267e (diff)
downloadexternal_llvm-6d40c191ee4bf34ee437e7d8688d20a3eb54e88b.zip
external_llvm-6d40c191ee4bf34ee437e7d8688d20a3eb54e88b.tar.gz
external_llvm-6d40c191ee4bf34ee437e7d8688d20a3eb54e88b.tar.bz2
Implement optimization folding setcc into branch.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@5324 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target/X86')
-rw-r--r--lib/Target/X86/InstSelectSimple.cpp151
-rw-r--r--lib/Target/X86/X86ISelSimple.cpp151
2 files changed, 226 insertions, 76 deletions
diff --git a/lib/Target/X86/InstSelectSimple.cpp b/lib/Target/X86/InstSelectSimple.cpp
index 8351f09..f14923b 100644
--- a/lib/Target/X86/InstSelectSimple.cpp
+++ b/lib/Target/X86/InstSelectSimple.cpp
@@ -151,14 +151,9 @@ namespace {
void visitOr (BinaryOperator &B) { visitSimpleBinary(B, 3); }
void visitXor(BinaryOperator &B) { visitSimpleBinary(B, 4); }
- // Binary comparison operators
- void visitSetCCInst(SetCondInst &I, unsigned OpNum);
- void visitSetEQ(SetCondInst &I) { visitSetCCInst(I, 0); }
- void visitSetNE(SetCondInst &I) { visitSetCCInst(I, 1); }
- void visitSetLT(SetCondInst &I) { visitSetCCInst(I, 2); }
- void visitSetGT(SetCondInst &I) { visitSetCCInst(I, 3); }
- void visitSetLE(SetCondInst &I) { visitSetCCInst(I, 4); }
- void visitSetGE(SetCondInst &I) { visitSetCCInst(I, 5); }
+ // Comparison operators...
+ void visitSetCondInst(SetCondInst &I);
+ bool EmitComparisonGetSignedness(unsigned OpNum, Value *Op0, Value *Op1);
// Memory Instructions
MachineInstr *doFPLoad(MachineBasicBlock *MBB,
@@ -482,31 +477,59 @@ void ISel::SelectPHINodes() {
}
}
+// canFoldSetCCIntoBranch - Return the setcc instruction if we can fold it into
+// the conditional branch instruction which is the only user of the cc
+// instruction. This is the case if the conditional branch is the only user of
+// the setcc, and if the setcc is in the same basic block as the conditional
+// branch. We also don't handle long arguments below, so we reject them here as
+// well.
+//
+static SetCondInst *canFoldSetCCIntoBranch(Value *V) {
+ if (SetCondInst *SCI = dyn_cast<SetCondInst>(V))
+ if (SCI->use_size() == 1 && isa<BranchInst>(SCI->use_back()) &&
+ SCI->getParent() == cast<BranchInst>(SCI->use_back())->getParent()) {
+ const Type *Ty = SCI->getOperand(0)->getType();
+ if (Ty != Type::LongTy && Ty != Type::ULongTy)
+ return SCI;
+ }
+ return 0;
+}
+// Return a fixed numbering for setcc instructions which does not depend on the
+// order of the opcodes.
+//
+static unsigned getSetCCNumber(unsigned Opcode) {
+ switch(Opcode) {
+ default: assert(0 && "Unknown setcc instruction!");
+ case Instruction::SetEQ: return 0;
+ case Instruction::SetNE: return 1;
+ case Instruction::SetLT: return 2;
+ case Instruction::SetGT: return 3;
+ case Instruction::SetLE: return 4;
+ case Instruction::SetGE: return 5;
+ }
+}
+
+// LLVM -> X86 signed X86 unsigned
+// ----- ---------- ------------
+// seteq -> sete sete
+// setne -> setne setne
+// setlt -> setl setb
+// setgt -> setg seta
+// setle -> setle setbe
+// setge -> setge setae
+static const unsigned SetCCOpcodeTab[2][6] = {
+ {X86::SETEr, X86::SETNEr, X86::SETBr, X86::SETAr, X86::SETBEr, X86::SETAEr},
+ {X86::SETEr, X86::SETNEr, X86::SETLr, X86::SETGr, X86::SETLEr, X86::SETGEr},
+};
+
+bool ISel::EmitComparisonGetSignedness(unsigned OpNum, Value *Op0, Value *Op1) {
-/// SetCC instructions - Here we just emit boilerplate code to set a byte-sized
-/// register, then move it to wherever the result should be.
-///
-void ISel::visitSetCCInst(SetCondInst &I, unsigned OpNum) {
// The arguments are already supposed to be of the same type.
- const Type *CompTy = I.getOperand(0)->getType();
+ const Type *CompTy = Op0->getType();
bool isSigned = CompTy->isSigned();
- unsigned reg1 = getReg(I.getOperand(0));
- unsigned reg2 = getReg(I.getOperand(1));
- unsigned DestReg = getReg(I);
-
- // LLVM -> X86 signed X86 unsigned
- // ----- ---------- ------------
- // seteq -> sete sete
- // setne -> setne setne
- // setlt -> setl setb
- // setgt -> setg seta
- // setle -> setle setbe
- // setge -> setge setae
- static const unsigned OpcodeTab[2][6] = {
- {X86::SETEr, X86::SETNEr, X86::SETBr, X86::SETAr, X86::SETBEr, X86::SETAEr},
- {X86::SETEr, X86::SETNEr, X86::SETLr, X86::SETGr, X86::SETLEr, X86::SETGEr},
- };
+ unsigned reg1 = getReg(Op0);
+ unsigned reg2 = getReg(Op1);
unsigned Class = getClassB(CompTy);
switch (Class) {
@@ -549,21 +572,43 @@ void ISel::visitSetCCInst(SetCondInst &I, unsigned OpNum) {
// dest = hi(op1) == hi(op2) ? AL : BL;
//
- // FIXME: This would be much better if we had heirarchical register
+ // FIXME: This would be much better if we had hierarchical register
// classes! Until then, hardcode registers so that we can deal with their
// aliases (because we don't have conditional byte moves).
//
BuildMI(BB, X86::CMPrr32, 2).addReg(reg1).addReg(reg2);
- BuildMI(BB, OpcodeTab[0][OpNum], 0, X86::AL);
+ BuildMI(BB, SetCCOpcodeTab[0][OpNum], 0, X86::AL);
BuildMI(BB, X86::CMPrr32, 2).addReg(reg1+1).addReg(reg2+1);
- BuildMI(BB, OpcodeTab[isSigned][OpNum], 0, X86::BL);
+ BuildMI(BB, SetCCOpcodeTab[isSigned][OpNum], 0, X86::BL);
BuildMI(BB, X86::CMOVErr16, 2, X86::BX).addReg(X86::BX).addReg(X86::AX);
- BuildMI(BB, X86::MOVrr8, 1, DestReg).addReg(X86::BL);
- return;
+ // NOTE: visitSetCondInst knows that the value is dumped into the BL
+ // register at this point for long values...
+ return isSigned;
}
}
+ return isSigned;
+}
- BuildMI(BB, OpcodeTab[isSigned][OpNum], 0, DestReg);
+
+/// SetCC instructions - Here we just emit boilerplate code to set a byte-sized
+/// register, then move it to wherever the result should be.
+///
+void ISel::visitSetCondInst(SetCondInst &I) {
+ if (canFoldSetCCIntoBranch(&I)) return; // Fold this into a branch...
+
+ unsigned OpNum = getSetCCNumber(I.getOpcode());
+ unsigned DestReg = getReg(I);
+ bool isSigned = EmitComparisonGetSignedness(OpNum, I.getOperand(0),
+ I.getOperand(1));
+
+ if (getClassB(I.getOperand(0)->getType()) != cLong || OpNum < 2) {
+ // Handle normal comparisons with a setcc instruction...
+ BuildMI(BB, SetCCOpcodeTab[isSigned][OpNum], 0, DestReg);
+ } else {
+ // Handle long comparisons by copying the value which is already in BL into
+ // the register we want...
+ BuildMI(BB, X86::MOVrr8, 1, DestReg).addReg(X86::BL);
+ }
}
/// promote32 - Emit instructions to turn a narrow operand into a 32-bit-wide
@@ -636,15 +681,45 @@ void ISel::visitReturnInst(ReturnInst &I) {
/// visitBranchInst - Handle conditional and unconditional branches here. Note
/// that since code layout is frozen at this point, that if we are trying to
/// jump to a block that is the immediate successor of the current block, we can
-/// just make a fall-through. (but we don't currently).
+/// just make a fall-through (but we don't currently).
///
void ISel::visitBranchInst(BranchInst &BI) {
- if (BI.isConditional()) {
+ if (!BI.isConditional()) {
+ BuildMI(BB, X86::JMP, 1).addPCDisp(BI.getSuccessor(0));
+ return;
+ }
+
+ // See if we can fold the setcc into the branch itself...
+ SetCondInst *SCI = canFoldSetCCIntoBranch(BI.getCondition());
+ if (SCI == 0) {
+ // Nope, cannot fold setcc into this branch. Emit a branch on a condition
+ // computed some other way...
unsigned condReg = getReg(BI.getCondition());
BuildMI(BB, X86::CMPri8, 2).addReg(condReg).addZImm(0);
BuildMI(BB, X86::JE, 1).addPCDisp(BI.getSuccessor(1));
+ BuildMI(BB, X86::JMP, 1).addPCDisp(BI.getSuccessor(0));
+ return;
}
- BuildMI(BB, X86::JMP, 1).addPCDisp(BI.getSuccessor(0));
+
+ unsigned OpNum = getSetCCNumber(SCI->getOpcode());
+ bool isSigned = EmitComparisonGetSignedness(OpNum, SCI->getOperand(0),
+ SCI->getOperand(1));
+
+ // LLVM -> X86 signed X86 unsigned
+ // ----- ---------- ------------
+ // seteq -> je je
+ // setne -> jne jne
+ // setlt -> jl jb
+ // setgt -> jg ja
+ // setle -> jle jbe
+ // setge -> jge jae
+ static const unsigned OpcodeTab[2][6] = {
+ { X86::JE, X86::JNE, X86::JB, X86::JA, X86::JBE, X86::JAE },
+ { X86::JE, X86::JNE, X86::JL, X86::JG, X86::JLE, X86::JGE },
+ };
+
+ BuildMI(BB, OpcodeTab[isSigned][OpNum], 1).addPCDisp(BI.getSuccessor(0));
+ BuildMI(BB, X86::JMP, 1).addPCDisp(BI.getSuccessor(1));
}
diff --git a/lib/Target/X86/X86ISelSimple.cpp b/lib/Target/X86/X86ISelSimple.cpp
index 8351f09..f14923b 100644
--- a/lib/Target/X86/X86ISelSimple.cpp
+++ b/lib/Target/X86/X86ISelSimple.cpp
@@ -151,14 +151,9 @@ namespace {
void visitOr (BinaryOperator &B) { visitSimpleBinary(B, 3); }
void visitXor(BinaryOperator &B) { visitSimpleBinary(B, 4); }
- // Binary comparison operators
- void visitSetCCInst(SetCondInst &I, unsigned OpNum);
- void visitSetEQ(SetCondInst &I) { visitSetCCInst(I, 0); }
- void visitSetNE(SetCondInst &I) { visitSetCCInst(I, 1); }
- void visitSetLT(SetCondInst &I) { visitSetCCInst(I, 2); }
- void visitSetGT(SetCondInst &I) { visitSetCCInst(I, 3); }
- void visitSetLE(SetCondInst &I) { visitSetCCInst(I, 4); }
- void visitSetGE(SetCondInst &I) { visitSetCCInst(I, 5); }
+ // Comparison operators...
+ void visitSetCondInst(SetCondInst &I);
+ bool EmitComparisonGetSignedness(unsigned OpNum, Value *Op0, Value *Op1);
// Memory Instructions
MachineInstr *doFPLoad(MachineBasicBlock *MBB,
@@ -482,31 +477,59 @@ void ISel::SelectPHINodes() {
}
}
+// canFoldSetCCIntoBranch - Return the setcc instruction if we can fold it into
+// the conditional branch instruction which is the only user of the cc
+// instruction. This is the case if the conditional branch is the only user of
+// the setcc, and if the setcc is in the same basic block as the conditional
+// branch. We also don't handle long arguments below, so we reject them here as
+// well.
+//
+static SetCondInst *canFoldSetCCIntoBranch(Value *V) {
+ if (SetCondInst *SCI = dyn_cast<SetCondInst>(V))
+ if (SCI->use_size() == 1 && isa<BranchInst>(SCI->use_back()) &&
+ SCI->getParent() == cast<BranchInst>(SCI->use_back())->getParent()) {
+ const Type *Ty = SCI->getOperand(0)->getType();
+ if (Ty != Type::LongTy && Ty != Type::ULongTy)
+ return SCI;
+ }
+ return 0;
+}
+// Return a fixed numbering for setcc instructions which does not depend on the
+// order of the opcodes.
+//
+static unsigned getSetCCNumber(unsigned Opcode) {
+ switch(Opcode) {
+ default: assert(0 && "Unknown setcc instruction!");
+ case Instruction::SetEQ: return 0;
+ case Instruction::SetNE: return 1;
+ case Instruction::SetLT: return 2;
+ case Instruction::SetGT: return 3;
+ case Instruction::SetLE: return 4;
+ case Instruction::SetGE: return 5;
+ }
+}
+
+// LLVM -> X86 signed X86 unsigned
+// ----- ---------- ------------
+// seteq -> sete sete
+// setne -> setne setne
+// setlt -> setl setb
+// setgt -> setg seta
+// setle -> setle setbe
+// setge -> setge setae
+static const unsigned SetCCOpcodeTab[2][6] = {
+ {X86::SETEr, X86::SETNEr, X86::SETBr, X86::SETAr, X86::SETBEr, X86::SETAEr},
+ {X86::SETEr, X86::SETNEr, X86::SETLr, X86::SETGr, X86::SETLEr, X86::SETGEr},
+};
+
+bool ISel::EmitComparisonGetSignedness(unsigned OpNum, Value *Op0, Value *Op1) {
-/// SetCC instructions - Here we just emit boilerplate code to set a byte-sized
-/// register, then move it to wherever the result should be.
-///
-void ISel::visitSetCCInst(SetCondInst &I, unsigned OpNum) {
// The arguments are already supposed to be of the same type.
- const Type *CompTy = I.getOperand(0)->getType();
+ const Type *CompTy = Op0->getType();
bool isSigned = CompTy->isSigned();
- unsigned reg1 = getReg(I.getOperand(0));
- unsigned reg2 = getReg(I.getOperand(1));
- unsigned DestReg = getReg(I);
-
- // LLVM -> X86 signed X86 unsigned
- // ----- ---------- ------------
- // seteq -> sete sete
- // setne -> setne setne
- // setlt -> setl setb
- // setgt -> setg seta
- // setle -> setle setbe
- // setge -> setge setae
- static const unsigned OpcodeTab[2][6] = {
- {X86::SETEr, X86::SETNEr, X86::SETBr, X86::SETAr, X86::SETBEr, X86::SETAEr},
- {X86::SETEr, X86::SETNEr, X86::SETLr, X86::SETGr, X86::SETLEr, X86::SETGEr},
- };
+ unsigned reg1 = getReg(Op0);
+ unsigned reg2 = getReg(Op1);
unsigned Class = getClassB(CompTy);
switch (Class) {
@@ -549,21 +572,43 @@ void ISel::visitSetCCInst(SetCondInst &I, unsigned OpNum) {
// dest = hi(op1) == hi(op2) ? AL : BL;
//
- // FIXME: This would be much better if we had heirarchical register
+ // FIXME: This would be much better if we had hierarchical register
// classes! Until then, hardcode registers so that we can deal with their
// aliases (because we don't have conditional byte moves).
//
BuildMI(BB, X86::CMPrr32, 2).addReg(reg1).addReg(reg2);
- BuildMI(BB, OpcodeTab[0][OpNum], 0, X86::AL);
+ BuildMI(BB, SetCCOpcodeTab[0][OpNum], 0, X86::AL);
BuildMI(BB, X86::CMPrr32, 2).addReg(reg1+1).addReg(reg2+1);
- BuildMI(BB, OpcodeTab[isSigned][OpNum], 0, X86::BL);
+ BuildMI(BB, SetCCOpcodeTab[isSigned][OpNum], 0, X86::BL);
BuildMI(BB, X86::CMOVErr16, 2, X86::BX).addReg(X86::BX).addReg(X86::AX);
- BuildMI(BB, X86::MOVrr8, 1, DestReg).addReg(X86::BL);
- return;
+ // NOTE: visitSetCondInst knows that the value is dumped into the BL
+ // register at this point for long values...
+ return isSigned;
}
}
+ return isSigned;
+}
- BuildMI(BB, OpcodeTab[isSigned][OpNum], 0, DestReg);
+
+/// SetCC instructions - Here we just emit boilerplate code to set a byte-sized
+/// register, then move it to wherever the result should be.
+///
+void ISel::visitSetCondInst(SetCondInst &I) {
+ if (canFoldSetCCIntoBranch(&I)) return; // Fold this into a branch...
+
+ unsigned OpNum = getSetCCNumber(I.getOpcode());
+ unsigned DestReg = getReg(I);
+ bool isSigned = EmitComparisonGetSignedness(OpNum, I.getOperand(0),
+ I.getOperand(1));
+
+ if (getClassB(I.getOperand(0)->getType()) != cLong || OpNum < 2) {
+ // Handle normal comparisons with a setcc instruction...
+ BuildMI(BB, SetCCOpcodeTab[isSigned][OpNum], 0, DestReg);
+ } else {
+ // Handle long comparisons by copying the value which is already in BL into
+ // the register we want...
+ BuildMI(BB, X86::MOVrr8, 1, DestReg).addReg(X86::BL);
+ }
}
/// promote32 - Emit instructions to turn a narrow operand into a 32-bit-wide
@@ -636,15 +681,45 @@ void ISel::visitReturnInst(ReturnInst &I) {
/// visitBranchInst - Handle conditional and unconditional branches here. Note
/// that since code layout is frozen at this point, that if we are trying to
/// jump to a block that is the immediate successor of the current block, we can
-/// just make a fall-through. (but we don't currently).
+/// just make a fall-through (but we don't currently).
///
void ISel::visitBranchInst(BranchInst &BI) {
- if (BI.isConditional()) {
+ if (!BI.isConditional()) {
+ BuildMI(BB, X86::JMP, 1).addPCDisp(BI.getSuccessor(0));
+ return;
+ }
+
+ // See if we can fold the setcc into the branch itself...
+ SetCondInst *SCI = canFoldSetCCIntoBranch(BI.getCondition());
+ if (SCI == 0) {
+ // Nope, cannot fold setcc into this branch. Emit a branch on a condition
+ // computed some other way...
unsigned condReg = getReg(BI.getCondition());
BuildMI(BB, X86::CMPri8, 2).addReg(condReg).addZImm(0);
BuildMI(BB, X86::JE, 1).addPCDisp(BI.getSuccessor(1));
+ BuildMI(BB, X86::JMP, 1).addPCDisp(BI.getSuccessor(0));
+ return;
}
- BuildMI(BB, X86::JMP, 1).addPCDisp(BI.getSuccessor(0));
+
+ unsigned OpNum = getSetCCNumber(SCI->getOpcode());
+ bool isSigned = EmitComparisonGetSignedness(OpNum, SCI->getOperand(0),
+ SCI->getOperand(1));
+
+ // LLVM -> X86 signed X86 unsigned
+ // ----- ---------- ------------
+ // seteq -> je je
+ // setne -> jne jne
+ // setlt -> jl jb
+ // setgt -> jg ja
+ // setle -> jle jbe
+ // setge -> jge jae
+ static const unsigned OpcodeTab[2][6] = {
+ { X86::JE, X86::JNE, X86::JB, X86::JA, X86::JBE, X86::JAE },
+ { X86::JE, X86::JNE, X86::JL, X86::JG, X86::JLE, X86::JGE },
+ };
+
+ BuildMI(BB, OpcodeTab[isSigned][OpNum], 1).addPCDisp(BI.getSuccessor(0));
+ BuildMI(BB, X86::JMP, 1).addPCDisp(BI.getSuccessor(1));
}