#include "llvm/CodeGen/SelectionDAGAddressAnalysis.h"
#include "llvm/CodeGen/ISDOpcodes.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/SelectionDAGNodes.h"
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/Support/Casting.h"
#include <cstdint>
using namespace llvm;
bool BaseIndexOffset::equalBaseIndex(BaseIndexOffset &Other,
const SelectionDAG &DAG, int64_t &Off) {
if (!Base.getNode() || !Other.Base.getNode())
return false;
Off = Other.Offset - Offset;
if ((Other.Index == Index) && (Other.IsIndexSignExt == IsIndexSignExt)) {
if (Other.Base == Base)
return true;
if (auto *A = dyn_cast<GlobalAddressSDNode>(Base))
if (auto *B = dyn_cast<GlobalAddressSDNode>(Other.Base))
if (A->getGlobal() == B->getGlobal()) {
Off += B->getOffset() - A->getOffset();
return true;
}
if (auto *A = dyn_cast<ConstantPoolSDNode>(Base))
if (auto *B = dyn_cast<ConstantPoolSDNode>(Other.Base)) {
bool IsMatch =
A->isMachineConstantPoolEntry() == B->isMachineConstantPoolEntry();
if (IsMatch) {
if (A->isMachineConstantPoolEntry())
IsMatch = A->getMachineCPVal() == B->getMachineCPVal();
else
IsMatch = A->getConstVal() == B->getConstVal();
}
if (IsMatch) {
Off += B->getOffset() - A->getOffset();
return true;
}
}
const MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
if (auto *A = dyn_cast<FrameIndexSDNode>(Base))
if (auto *B = dyn_cast<FrameIndexSDNode>(Other.Base))
if (MFI.isFixedObjectIndex(A->getIndex()) &&
MFI.isFixedObjectIndex(B->getIndex())) {
Off += MFI.getObjectOffset(B->getIndex()) -
MFI.getObjectOffset(A->getIndex());
return true;
}
}
return false;
}
BaseIndexOffset BaseIndexOffset::match(LSBaseSDNode *N,
const SelectionDAG &DAG) {
SDValue Ptr = N->getBasePtr();
SDValue Base = DAG.getTargetLoweringInfo().unwrapAddress(Ptr);
SDValue Index = SDValue();
int64_t Offset = 0;
bool IsIndexSignExt = false;
if (N->getAddressingMode() == ISD::PRE_INC) {
if (auto *C = dyn_cast<ConstantSDNode>(N->getOffset()))
Offset += C->getSExtValue();
else
return BaseIndexOffset(SDValue(), SDValue(), 0, false);
} else if (N->getAddressingMode() == ISD::PRE_DEC) {
if (auto *C = dyn_cast<ConstantSDNode>(N->getOffset()))
Offset -= C->getSExtValue();
else
return BaseIndexOffset(SDValue(), SDValue(), 0, false);
}
while (true) {
switch (Base->getOpcode()) {
case ISD::OR:
if (auto *C = dyn_cast<ConstantSDNode>(Base->getOperand(1)))
if (DAG.MaskedValueIsZero(Base->getOperand(0), C->getAPIntValue())) {
Offset += C->getSExtValue();
Base = Base->getOperand(0);
continue;
}
break;
case ISD::ADD:
if (auto *C = dyn_cast<ConstantSDNode>(Base->getOperand(1))) {
Offset += C->getSExtValue();
Base = Base->getOperand(0);
continue;
}
break;
case ISD::LOAD:
case ISD::STORE: {
auto *LSBase = cast<LSBaseSDNode>(Base.getNode());
unsigned int IndexResNo = (Base->getOpcode() == ISD::LOAD) ? 1 : 0;
if (LSBase->isIndexed() && Base.getResNo() == IndexResNo)
if (auto *C = dyn_cast<ConstantSDNode>(LSBase->getOffset())) {
auto Off = C->getSExtValue();
if (LSBase->getAddressingMode() == ISD::PRE_DEC ||
LSBase->getAddressingMode() == ISD::POST_DEC)
Offset -= Off;
else
Offset += Off;
Base = LSBase->getBasePtr();
continue;
}
break;
}
}
break;
}
if (Base->getOpcode() == ISD::ADD) {
if (Base->getOperand(1)->getOpcode() == ISD::MUL)
return BaseIndexOffset(Base, Index, Offset, IsIndexSignExt);
Index = Base->getOperand(1);
SDValue PotentialBase = Base->getOperand(0);
if (Index->getOpcode() == ISD::SIGN_EXTEND) {
Index = Index->getOperand(0);
IsIndexSignExt = true;
}
if (Index->getOpcode() != ISD::ADD ||
!isa<ConstantSDNode>(Index->getOperand(1)))
return BaseIndexOffset(PotentialBase, Index, Offset, IsIndexSignExt);
Offset += cast<ConstantSDNode>(Index->getOperand(1))->getSExtValue();
Index = Index->getOperand(0);
if (Index->getOpcode() == ISD::SIGN_EXTEND) {
Index = Index->getOperand(0);
IsIndexSignExt = true;
} else
IsIndexSignExt = false;
Base = PotentialBase;
}
return BaseIndexOffset(Base, Index, Offset, IsIndexSignExt);
}