summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2007-02-04 20:18:17 +0000
committerChris Lattner <sabre@nondot.org>2007-02-04 20:18:17 +0000
commit6241226b097f1a71c25e2e30272aa508abaafc6d (patch)
treeab23c5e65ff9c65a3d173fdfb6a8935660aaefa7 /lib
parent2b5d75c35b8f62d67bd8029ea2ca2862b0757475 (diff)
downloadllvm-6241226b097f1a71c25e2e30272aa508abaafc6d.tar.gz
llvm-6241226b097f1a71c25e2e30272aa508abaafc6d.tar.bz2
llvm-6241226b097f1a71c25e2e30272aa508abaafc6d.tar.xz
Fix a miscompilation in the addr mode code trying to implement X | C and
X + C to promote LEA formation. We would incorrectly apply it in some cases (test) and miss it in others. This fixes CodeGen/X86/2007-02-04-OrAddrMode.ll git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@33884 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/Target/X86/X86ISelDAGToDAG.cpp37
1 files changed, 17 insertions, 20 deletions
diff --git a/lib/Target/X86/X86ISelDAGToDAG.cpp b/lib/Target/X86/X86ISelDAGToDAG.cpp
index 7c61febf00..e7d318264a 100644
--- a/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -677,7 +677,7 @@ bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM,
if (!Available &&
AM.BaseType == X86ISelAddressMode::RegBase &&
AM.Base.Reg.Val == 0 &&
- AM.IndexReg.Val == 0)
+ AM.IndexReg.Val == 0) {
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.Val->getOperand(1)))
if (CN->getValue() == 3 || CN->getValue() == 5 || CN->getValue() == 9) {
AM.Scale = unsigned(CN->getValue())-1;
@@ -705,9 +705,10 @@ bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM,
AM.IndexReg = AM.Base.Reg = Reg;
return false;
}
+ }
break;
- case ISD::ADD: {
+ case ISD::ADD:
if (!Available) {
X86ISelAddressMode Backup = AM;
if (!MatchAddress(N.Val->getOperand(0), AM, false) &&
@@ -720,32 +721,28 @@ bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM,
AM = Backup;
}
break;
- }
- case ISD::OR: {
+ case ISD::OR:
+ // Handle "X | C" as "X + C" iff X is known to have C bits clear.
if (!Available) {
- X86ISelAddressMode Backup = AM;
- // Look for (x << c1) | c2 where (c2 < c1)
- ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.Val->getOperand(0));
- if (CN && !MatchAddress(N.Val->getOperand(1), AM, false)) {
- if (AM.GV == NULL && AM.Disp == 0 && CN->getValue() < AM.Scale) {
- AM.Disp = CN->getValue();
+ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
+ X86ISelAddressMode Backup = AM;
+ // Start with the LHS as an addr mode.
+ if (!MatchAddress(N.getOperand(0), AM, false) &&
+ // Address could not have picked a GV address for the displacement.
+ AM.GV == NULL &&
+ // On x86-64, the resultant disp must fit in 32-bits.
+ isInt32(AM.Disp + CN->getSignExtended()) &&
+ // Check to see if the LHS & C is zero.
+ TLI.MaskedValueIsZero(N.getOperand(0), CN->getValue())) {
+ AM.Disp += CN->getValue();
return false;
}
+ AM = Backup;
}
- AM = Backup;
- CN = dyn_cast<ConstantSDNode>(N.Val->getOperand(1));
- if (CN && !MatchAddress(N.Val->getOperand(0), AM, false)) {
- if (AM.GV == NULL && AM.Disp == 0 && CN->getValue() < AM.Scale) {
- AM.Disp = CN->getValue();
- return false;
- }
- }
- AM = Backup;
}
break;
}
- }
// Is the base register already occupied?
if (AM.BaseType != X86ISelAddressMode::RegBase || AM.Base.Reg.Val) {