aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2004-06-11 05:33:49 +0000
committerChris Lattner <sabre@nondot.org>2004-06-11 05:33:49 +0000
commit01cdb1b3670ee5dfacbf344182d8c79c09844393 (patch)
tree0f86add385f59a38bdcc873bc770987e2dacddb4
parentc31ae50c04ca42f447c649c6a528e20ab3ea791f (diff)
By far, one of the most common uses of isnan is to make 'isunordered'
comparisons. In an 'isunordered' predicate, which looks like this at the LLVM level: %a = call bool %llvm.isnan(double %X) %b = call bool %llvm.isnan(double %Y) %COM = or bool %a, %b We used to generate this code: fxch %ST(1) fucomip %ST(0), %ST(0) setp %AL fucomip %ST(0), %ST(0) setp %AH or %AL, %AH With this patch, we generate this code: fucomip %ST(0), %ST(1) fstp %ST(0) setp %AL Which should make alkis happy. Tested as X86/compare_folding.llx:test1 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@14148 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Target/X86/InstSelectSimple.cpp73
-rw-r--r--lib/Target/X86/X86ISelSimple.cpp73
2 files changed, 118 insertions, 28 deletions
diff --git a/lib/Target/X86/InstSelectSimple.cpp b/lib/Target/X86/InstSelectSimple.cpp
index 7ed3452278..87450909b6 100644
--- a/lib/Target/X86/InstSelectSimple.cpp
+++ b/lib/Target/X86/InstSelectSimple.cpp
@@ -329,6 +329,9 @@ namespace {
MachineBasicBlock::iterator MBBI,
Constant *C, unsigned Reg);
+ void emitUCOMr(MachineBasicBlock *MBB, MachineBasicBlock::iterator MBBI,
+ unsigned LHS, unsigned RHS);
+
/// makeAnotherReg - This method returns the next register number we haven't
/// yet used.
///
@@ -887,6 +890,19 @@ static const unsigned SetCCOpcodeTab[2][8] = {
X86::SETSr, X86::SETNSr },
};
+/// emitUCOMr - In the future when we support processors before the P6, this
+/// wraps the logic for emitting an FUCOMr vs FUCOMIr.
+void ISel::emitUCOMr(MachineBasicBlock *MBB, MachineBasicBlock::iterator IP,
+ unsigned LHS, unsigned RHS) {
+ if (0) { // for processors prior to the P6
+ BuildMI(*MBB, IP, X86::FUCOMr, 2).addReg(LHS).addReg(RHS);
+ BuildMI(*MBB, IP, X86::FNSTSW8r, 0);
+ BuildMI(*MBB, IP, X86::SAHF, 1);
+ } else {
+ BuildMI(*MBB, IP, X86::FUCOMIr, 2).addReg(LHS).addReg(RHS);
+ }
+}
+
// EmitComparison - This function emits a comparison of the two operands,
// returning the extended setcc code to use.
unsigned ISel::EmitComparison(unsigned OpNum, Value *Op0, Value *Op1,
@@ -1004,13 +1020,7 @@ unsigned ISel::EmitComparison(unsigned OpNum, Value *Op0, Value *Op1,
BuildMI(*MBB, IP, X86::CMP32rr, 2).addReg(Op0r).addReg(Op1r);
break;
case cFP:
- if (0) { // for processors prior to the P6
- BuildMI(*MBB, IP, X86::FUCOMr, 2).addReg(Op0r).addReg(Op1r);
- BuildMI(*MBB, IP, X86::FNSTSW8r, 0);
- BuildMI(*MBB, IP, X86::SAHF, 1);
- } else {
- BuildMI(*MBB, IP, X86::FUCOMIr, 2).addReg(Op0r).addReg(Op1r);
- }
+ emitUCOMr(MBB, IP, Op0r, Op1r);
break;
case cLong:
@@ -1609,6 +1619,31 @@ void ISel::visitCallInst(CallInst &CI) {
doCall(ValueRecord(DestReg, CI.getType()), TheCall, Args);
}
+/// dyncastIsNan - Return the operand of an isnan operation if this is an isnan.
+///
+static Value *dyncastIsNan(Value *V) {
+ if (CallInst *CI = dyn_cast<CallInst>(V))
+ if (Function *F = CI->getCalledFunction())
+ if (F->getIntrinsicID() == Intrinsic::isnan)
+ return CI->getOperand(1);
+ return 0;
+}
+
+/// isOnlyUsedByUnorderedComparisons - Return true if this value is only used by
+/// or's whos operands are all calls to the isnan predicate.
+static bool isOnlyUsedByUnorderedComparisons(Value *V) {
+ assert(dyncastIsNan(V) && "The value isn't an isnan call!");
+
+ // Check all uses, which will be or's of isnans if this predicate is true.
+ for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E;++UI){
+ Instruction *I = cast<Instruction>(*UI);
+ if (I->getOpcode() != Instruction::Or) return false;
+ if (I->getOperand(0) != V && !dyncastIsNan(I->getOperand(0))) return false;
+ if (I->getOperand(1) != V && !dyncastIsNan(I->getOperand(1))) return false;
+ }
+
+ return true;
+}
/// LowerUnknownIntrinsicFunctionCalls - This performs a prepass over the
/// function, lowering any calls to unknown intrinsic functions into the
@@ -1699,14 +1734,10 @@ void ISel::visitIntrinsicCall(Intrinsic::ID ID, CallInst &CI) {
return;
case Intrinsic::isnan:
+ // If this is only used by 'isunordered' style comparisons, don't emit it.
+ if (isOnlyUsedByUnorderedComparisons(&CI)) return;
TmpReg1 = getReg(CI.getOperand(1));
- if (0) { // for processors prior to the P6
- BuildMI(BB, X86::FUCOMr, 2).addReg(TmpReg1).addReg(TmpReg1);
- BuildMI(BB, X86::FNSTSW8r, 0);
- BuildMI(BB, X86::SAHF, 1);
- } else {
- BuildMI(BB, X86::FUCOMIr, 2).addReg(TmpReg1).addReg(TmpReg1);
- }
+ emitUCOMr(BB, BB->end(), TmpReg1, TmpReg1);
TmpReg2 = getReg(CI);
BuildMI(BB, X86::SETPr, 0, TmpReg2);
return;
@@ -2122,6 +2153,20 @@ void ISel::emitSimpleBinaryOperation(MachineBasicBlock *MBB,
return;
}
+ if (Op0->getType() == Type::BoolTy) {
+ if (OperatorClass == 3)
+ // If this is an or of two isnan's, emit an FP comparison directly instead
+ // of or'ing two isnan's together.
+ if (Value *LHS = dyncastIsNan(Op0))
+ if (Value *RHS = dyncastIsNan(Op1)) {
+ unsigned Op0Reg = getReg(RHS, MBB, IP), Op1Reg = getReg(LHS, MBB, IP);
+ emitUCOMr(MBB, IP, Op0Reg, Op1Reg);
+ BuildMI(*MBB, IP, X86::SETPr, 0, DestReg);
+ return;
+ }
+
+ }
+
// sub 0, X -> neg X
if (ConstantInt *CI = dyn_cast<ConstantInt>(Op0))
if (OperatorClass == 1 && CI->isNullValue()) {
diff --git a/lib/Target/X86/X86ISelSimple.cpp b/lib/Target/X86/X86ISelSimple.cpp
index 7ed3452278..87450909b6 100644
--- a/lib/Target/X86/X86ISelSimple.cpp
+++ b/lib/Target/X86/X86ISelSimple.cpp
@@ -329,6 +329,9 @@ namespace {
MachineBasicBlock::iterator MBBI,
Constant *C, unsigned Reg);
+ void emitUCOMr(MachineBasicBlock *MBB, MachineBasicBlock::iterator MBBI,
+ unsigned LHS, unsigned RHS);
+
/// makeAnotherReg - This method returns the next register number we haven't
/// yet used.
///
@@ -887,6 +890,19 @@ static const unsigned SetCCOpcodeTab[2][8] = {
X86::SETSr, X86::SETNSr },
};
+/// emitUCOMr - In the future when we support processors before the P6, this
+/// wraps the logic for emitting an FUCOMr vs FUCOMIr.
+void ISel::emitUCOMr(MachineBasicBlock *MBB, MachineBasicBlock::iterator IP,
+ unsigned LHS, unsigned RHS) {
+ if (0) { // for processors prior to the P6
+ BuildMI(*MBB, IP, X86::FUCOMr, 2).addReg(LHS).addReg(RHS);
+ BuildMI(*MBB, IP, X86::FNSTSW8r, 0);
+ BuildMI(*MBB, IP, X86::SAHF, 1);
+ } else {
+ BuildMI(*MBB, IP, X86::FUCOMIr, 2).addReg(LHS).addReg(RHS);
+ }
+}
+
// EmitComparison - This function emits a comparison of the two operands,
// returning the extended setcc code to use.
unsigned ISel::EmitComparison(unsigned OpNum, Value *Op0, Value *Op1,
@@ -1004,13 +1020,7 @@ unsigned ISel::EmitComparison(unsigned OpNum, Value *Op0, Value *Op1,
BuildMI(*MBB, IP, X86::CMP32rr, 2).addReg(Op0r).addReg(Op1r);
break;
case cFP:
- if (0) { // for processors prior to the P6
- BuildMI(*MBB, IP, X86::FUCOMr, 2).addReg(Op0r).addReg(Op1r);
- BuildMI(*MBB, IP, X86::FNSTSW8r, 0);
- BuildMI(*MBB, IP, X86::SAHF, 1);
- } else {
- BuildMI(*MBB, IP, X86::FUCOMIr, 2).addReg(Op0r).addReg(Op1r);
- }
+ emitUCOMr(MBB, IP, Op0r, Op1r);
break;
case cLong:
@@ -1609,6 +1619,31 @@ void ISel::visitCallInst(CallInst &CI) {
doCall(ValueRecord(DestReg, CI.getType()), TheCall, Args);
}
+/// dyncastIsNan - Return the operand of an isnan operation if this is an isnan.
+///
+static Value *dyncastIsNan(Value *V) {
+ if (CallInst *CI = dyn_cast<CallInst>(V))
+ if (Function *F = CI->getCalledFunction())
+ if (F->getIntrinsicID() == Intrinsic::isnan)
+ return CI->getOperand(1);
+ return 0;
+}
+
+/// isOnlyUsedByUnorderedComparisons - Return true if this value is only used by
+/// or's whos operands are all calls to the isnan predicate.
+static bool isOnlyUsedByUnorderedComparisons(Value *V) {
+ assert(dyncastIsNan(V) && "The value isn't an isnan call!");
+
+ // Check all uses, which will be or's of isnans if this predicate is true.
+ for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E;++UI){
+ Instruction *I = cast<Instruction>(*UI);
+ if (I->getOpcode() != Instruction::Or) return false;
+ if (I->getOperand(0) != V && !dyncastIsNan(I->getOperand(0))) return false;
+ if (I->getOperand(1) != V && !dyncastIsNan(I->getOperand(1))) return false;
+ }
+
+ return true;
+}
/// LowerUnknownIntrinsicFunctionCalls - This performs a prepass over the
/// function, lowering any calls to unknown intrinsic functions into the
@@ -1699,14 +1734,10 @@ void ISel::visitIntrinsicCall(Intrinsic::ID ID, CallInst &CI) {
return;
case Intrinsic::isnan:
+ // If this is only used by 'isunordered' style comparisons, don't emit it.
+ if (isOnlyUsedByUnorderedComparisons(&CI)) return;
TmpReg1 = getReg(CI.getOperand(1));
- if (0) { // for processors prior to the P6
- BuildMI(BB, X86::FUCOMr, 2).addReg(TmpReg1).addReg(TmpReg1);
- BuildMI(BB, X86::FNSTSW8r, 0);
- BuildMI(BB, X86::SAHF, 1);
- } else {
- BuildMI(BB, X86::FUCOMIr, 2).addReg(TmpReg1).addReg(TmpReg1);
- }
+ emitUCOMr(BB, BB->end(), TmpReg1, TmpReg1);
TmpReg2 = getReg(CI);
BuildMI(BB, X86::SETPr, 0, TmpReg2);
return;
@@ -2122,6 +2153,20 @@ void ISel::emitSimpleBinaryOperation(MachineBasicBlock *MBB,
return;
}
+ if (Op0->getType() == Type::BoolTy) {
+ if (OperatorClass == 3)
+ // If this is an or of two isnan's, emit an FP comparison directly instead
+ // of or'ing two isnan's together.
+ if (Value *LHS = dyncastIsNan(Op0))
+ if (Value *RHS = dyncastIsNan(Op1)) {
+ unsigned Op0Reg = getReg(RHS, MBB, IP), Op1Reg = getReg(LHS, MBB, IP);
+ emitUCOMr(MBB, IP, Op0Reg, Op1Reg);
+ BuildMI(*MBB, IP, X86::SETPr, 0, DestReg);
+ return;
+ }
+
+ }
+
// sub 0, X -> neg X
if (ConstantInt *CI = dyn_cast<ConstantInt>(Op0))
if (OperatorClass == 1 && CI->isNullValue()) {