diff options
author | Chris Lattner <sabre@nondot.org> | 2007-02-04 20:18:17 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2007-02-04 20:18:17 +0000 |
commit | 6241226b097f1a71c25e2e30272aa508abaafc6d (patch) | |
tree | ab23c5e65ff9c65a3d173fdfb6a8935660aaefa7 /lib | |
parent | 2b5d75c35b8f62d67bd8029ea2ca2862b0757475 (diff) | |
download | llvm-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.cpp | 37 |
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) { |