12cab237bSDimitry Andric //==- llvm/CodeGen/SelectionDAGAddressAnalysis.cpp - DAG Address Analysis --==//
2edd7eaddSDimitry Andric //
3edd7eaddSDimitry Andric //                     The LLVM Compiler Infrastructure
4edd7eaddSDimitry Andric //
5edd7eaddSDimitry Andric // This file is distributed under the University of Illinois Open Source
6edd7eaddSDimitry Andric // License. See LICENSE.TXT for details.
7edd7eaddSDimitry Andric //
8edd7eaddSDimitry Andric //===----------------------------------------------------------------------===//
9edd7eaddSDimitry Andric 
10edd7eaddSDimitry Andric #include "llvm/CodeGen/SelectionDAGAddressAnalysis.h"
11edd7eaddSDimitry Andric #include "llvm/CodeGen/ISDOpcodes.h"
12a580b014SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
132cab237bSDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
14edd7eaddSDimitry Andric #include "llvm/CodeGen/SelectionDAG.h"
15edd7eaddSDimitry Andric #include "llvm/CodeGen/SelectionDAGNodes.h"
162cab237bSDimitry Andric #include "llvm/CodeGen/TargetLowering.h"
172cab237bSDimitry Andric #include "llvm/Support/Casting.h"
182cab237bSDimitry Andric #include <cstdint>
19edd7eaddSDimitry Andric 
202cab237bSDimitry Andric using namespace llvm;
21edd7eaddSDimitry Andric 
equalBaseIndex(const BaseIndexOffset & Other,const SelectionDAG & DAG,int64_t & Off) const22*b5893f02SDimitry Andric bool BaseIndexOffset::equalBaseIndex(const BaseIndexOffset &Other,
23*b5893f02SDimitry Andric                                      const SelectionDAG &DAG,
24*b5893f02SDimitry Andric                                      int64_t &Off) const {
25042b1c2eSDimitry Andric   // Conservatively fail if we a match failed..
26042b1c2eSDimitry Andric   if (!Base.getNode() || !Other.Base.getNode())
27042b1c2eSDimitry Andric     return false;
28a580b014SDimitry Andric   // Initial Offset difference.
29edd7eaddSDimitry Andric   Off = Other.Offset - Offset;
30a580b014SDimitry Andric 
31a580b014SDimitry Andric   if ((Other.Index == Index) && (Other.IsIndexSignExt == IsIndexSignExt)) {
32a580b014SDimitry Andric     // Trivial match.
33a580b014SDimitry Andric     if (Other.Base == Base)
34edd7eaddSDimitry Andric       return true;
35edd7eaddSDimitry Andric 
36edd7eaddSDimitry Andric     // Match GlobalAddresses
37a580b014SDimitry Andric     if (auto *A = dyn_cast<GlobalAddressSDNode>(Base))
38a580b014SDimitry Andric       if (auto *B = dyn_cast<GlobalAddressSDNode>(Other.Base))
39edd7eaddSDimitry Andric         if (A->getGlobal() == B->getGlobal()) {
40edd7eaddSDimitry Andric           Off += B->getOffset() - A->getOffset();
41edd7eaddSDimitry Andric           return true;
42edd7eaddSDimitry Andric         }
43edd7eaddSDimitry Andric 
44da09e106SDimitry Andric     // Match Constants
45da09e106SDimitry Andric     if (auto *A = dyn_cast<ConstantPoolSDNode>(Base))
46da09e106SDimitry Andric       if (auto *B = dyn_cast<ConstantPoolSDNode>(Other.Base)) {
47da09e106SDimitry Andric         bool IsMatch =
48da09e106SDimitry Andric             A->isMachineConstantPoolEntry() == B->isMachineConstantPoolEntry();
49da09e106SDimitry Andric         if (IsMatch) {
50da09e106SDimitry Andric           if (A->isMachineConstantPoolEntry())
51da09e106SDimitry Andric             IsMatch = A->getMachineCPVal() == B->getMachineCPVal();
52da09e106SDimitry Andric           else
53da09e106SDimitry Andric             IsMatch = A->getConstVal() == B->getConstVal();
54da09e106SDimitry Andric         }
55da09e106SDimitry Andric         if (IsMatch) {
56da09e106SDimitry Andric           Off += B->getOffset() - A->getOffset();
57da09e106SDimitry Andric           return true;
58da09e106SDimitry Andric         }
59da09e106SDimitry Andric       }
60da09e106SDimitry Andric 
61a580b014SDimitry Andric     const MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
62edd7eaddSDimitry Andric 
63c4394386SDimitry Andric     // Match non-equal FrameIndexes - If both frame indices are fixed
64c4394386SDimitry Andric     // we know their relative offsets and can compare them. Otherwise
65c4394386SDimitry Andric     // we must be conservative.
66a580b014SDimitry Andric     if (auto *A = dyn_cast<FrameIndexSDNode>(Base))
67a580b014SDimitry Andric       if (auto *B = dyn_cast<FrameIndexSDNode>(Other.Base))
68c4394386SDimitry Andric         if (MFI.isFixedObjectIndex(A->getIndex()) &&
69c4394386SDimitry Andric             MFI.isFixedObjectIndex(B->getIndex())) {
70a580b014SDimitry Andric           Off += MFI.getObjectOffset(B->getIndex()) -
71a580b014SDimitry Andric                  MFI.getObjectOffset(A->getIndex());
72a580b014SDimitry Andric           return true;
73a580b014SDimitry Andric         }
74a580b014SDimitry Andric   }
75edd7eaddSDimitry Andric   return false;
76edd7eaddSDimitry Andric }
77edd7eaddSDimitry Andric 
78edd7eaddSDimitry Andric /// Parses tree in Ptr for base, index, offset addresses.
match(const LSBaseSDNode * N,const SelectionDAG & DAG)79*b5893f02SDimitry Andric BaseIndexOffset BaseIndexOffset::match(const LSBaseSDNode *N,
80042b1c2eSDimitry Andric                                        const SelectionDAG &DAG) {
81042b1c2eSDimitry Andric   SDValue Ptr = N->getBasePtr();
82042b1c2eSDimitry Andric 
83edd7eaddSDimitry Andric   // (((B + I*M) + c)) + c ...
842cab237bSDimitry Andric   SDValue Base = DAG.getTargetLoweringInfo().unwrapAddress(Ptr);
85edd7eaddSDimitry Andric   SDValue Index = SDValue();
86edd7eaddSDimitry Andric   int64_t Offset = 0;
87edd7eaddSDimitry Andric   bool IsIndexSignExt = false;
88edd7eaddSDimitry Andric 
89042b1c2eSDimitry Andric   // pre-inc/pre-dec ops are components of EA.
90042b1c2eSDimitry Andric   if (N->getAddressingMode() == ISD::PRE_INC) {
91042b1c2eSDimitry Andric     if (auto *C = dyn_cast<ConstantSDNode>(N->getOffset()))
92042b1c2eSDimitry Andric       Offset += C->getSExtValue();
93042b1c2eSDimitry Andric     else // If unknown, give up now.
94042b1c2eSDimitry Andric       return BaseIndexOffset(SDValue(), SDValue(), 0, false);
95042b1c2eSDimitry Andric   } else if (N->getAddressingMode() == ISD::PRE_DEC) {
96042b1c2eSDimitry Andric     if (auto *C = dyn_cast<ConstantSDNode>(N->getOffset()))
97042b1c2eSDimitry Andric       Offset -= C->getSExtValue();
98042b1c2eSDimitry Andric     else // If unknown, give up now.
99042b1c2eSDimitry Andric       return BaseIndexOffset(SDValue(), SDValue(), 0, false);
100042b1c2eSDimitry Andric   }
101042b1c2eSDimitry Andric 
102c4394386SDimitry Andric   // Consume constant adds & ors with appropriate masking.
1034ba319b5SDimitry Andric   while (true) {
1044ba319b5SDimitry Andric     switch (Base->getOpcode()) {
1054ba319b5SDimitry Andric     case ISD::OR:
106c4394386SDimitry Andric       // Only consider ORs which act as adds.
1074ba319b5SDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Base->getOperand(1)))
1084ba319b5SDimitry Andric         if (DAG.MaskedValueIsZero(Base->getOperand(0), C->getAPIntValue())) {
109c4394386SDimitry Andric           Offset += C->getSExtValue();
110*b5893f02SDimitry Andric           Base = DAG.getTargetLoweringInfo().unwrapAddress(Base->getOperand(0));
111c4394386SDimitry Andric           continue;
112c4394386SDimitry Andric         }
113c4394386SDimitry Andric       break;
1144ba319b5SDimitry Andric     case ISD::ADD:
1154ba319b5SDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Base->getOperand(1))) {
1164ba319b5SDimitry Andric         Offset += C->getSExtValue();
117*b5893f02SDimitry Andric         Base = DAG.getTargetLoweringInfo().unwrapAddress(Base->getOperand(0));
1184ba319b5SDimitry Andric         continue;
1194ba319b5SDimitry Andric       }
1204ba319b5SDimitry Andric       break;
1214ba319b5SDimitry Andric     case ISD::LOAD:
1224ba319b5SDimitry Andric     case ISD::STORE: {
1234ba319b5SDimitry Andric       auto *LSBase = cast<LSBaseSDNode>(Base.getNode());
1244ba319b5SDimitry Andric       unsigned int IndexResNo = (Base->getOpcode() == ISD::LOAD) ? 1 : 0;
1254ba319b5SDimitry Andric       if (LSBase->isIndexed() && Base.getResNo() == IndexResNo)
1264ba319b5SDimitry Andric         if (auto *C = dyn_cast<ConstantSDNode>(LSBase->getOffset())) {
1274ba319b5SDimitry Andric           auto Off = C->getSExtValue();
1284ba319b5SDimitry Andric           if (LSBase->getAddressingMode() == ISD::PRE_DEC ||
1294ba319b5SDimitry Andric               LSBase->getAddressingMode() == ISD::POST_DEC)
1304ba319b5SDimitry Andric             Offset -= Off;
1314ba319b5SDimitry Andric           else
1324ba319b5SDimitry Andric             Offset += Off;
133*b5893f02SDimitry Andric           Base = DAG.getTargetLoweringInfo().unwrapAddress(LSBase->getBasePtr());
1344ba319b5SDimitry Andric           continue;
1354ba319b5SDimitry Andric         }
1364ba319b5SDimitry Andric       break;
1374ba319b5SDimitry Andric     }
1384ba319b5SDimitry Andric     }
1394ba319b5SDimitry Andric     // If we get here break out of the loop.
1404ba319b5SDimitry Andric     break;
141edd7eaddSDimitry Andric   }
142edd7eaddSDimitry Andric 
143edd7eaddSDimitry Andric   if (Base->getOpcode() == ISD::ADD) {
144edd7eaddSDimitry Andric     // TODO: The following code appears to be needless as it just
145edd7eaddSDimitry Andric     //       bails on some Ptrs early, reducing the cases where we
146edd7eaddSDimitry Andric     //       find equivalence. We should be able to remove this.
147edd7eaddSDimitry Andric     // Inside a loop the current BASE pointer is calculated using an ADD and a
148edd7eaddSDimitry Andric     // MUL instruction. In this case Base is the actual BASE pointer.
149edd7eaddSDimitry Andric     // (i64 add (i64 %array_ptr)
150edd7eaddSDimitry Andric     //          (i64 mul (i64 %induction_var)
151edd7eaddSDimitry Andric     //                   (i64 %element_size)))
152edd7eaddSDimitry Andric     if (Base->getOperand(1)->getOpcode() == ISD::MUL)
153edd7eaddSDimitry Andric       return BaseIndexOffset(Base, Index, Offset, IsIndexSignExt);
154edd7eaddSDimitry Andric 
155edd7eaddSDimitry Andric     // Look at Base + Index + Offset cases.
156edd7eaddSDimitry Andric     Index = Base->getOperand(1);
157edd7eaddSDimitry Andric     SDValue PotentialBase = Base->getOperand(0);
158edd7eaddSDimitry Andric 
159edd7eaddSDimitry Andric     // Skip signextends.
160edd7eaddSDimitry Andric     if (Index->getOpcode() == ISD::SIGN_EXTEND) {
161edd7eaddSDimitry Andric       Index = Index->getOperand(0);
162edd7eaddSDimitry Andric       IsIndexSignExt = true;
163edd7eaddSDimitry Andric     }
164edd7eaddSDimitry Andric 
165edd7eaddSDimitry Andric     // Check if Index Offset pattern
166edd7eaddSDimitry Andric     if (Index->getOpcode() != ISD::ADD ||
167edd7eaddSDimitry Andric         !isa<ConstantSDNode>(Index->getOperand(1)))
168edd7eaddSDimitry Andric       return BaseIndexOffset(PotentialBase, Index, Offset, IsIndexSignExt);
169edd7eaddSDimitry Andric 
170edd7eaddSDimitry Andric     Offset += cast<ConstantSDNode>(Index->getOperand(1))->getSExtValue();
171edd7eaddSDimitry Andric     Index = Index->getOperand(0);
172edd7eaddSDimitry Andric     if (Index->getOpcode() == ISD::SIGN_EXTEND) {
173edd7eaddSDimitry Andric       Index = Index->getOperand(0);
174edd7eaddSDimitry Andric       IsIndexSignExt = true;
175edd7eaddSDimitry Andric     } else
176edd7eaddSDimitry Andric       IsIndexSignExt = false;
177edd7eaddSDimitry Andric     Base = PotentialBase;
178edd7eaddSDimitry Andric   }
179edd7eaddSDimitry Andric   return BaseIndexOffset(Base, Index, Offset, IsIndexSignExt);
180edd7eaddSDimitry Andric }
181