#include "llvm/CodeGen/SelectionDAGAddressAnalysis.h"
#include "llvm/Analysis/MemoryLocation.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/IR/GlobalAlias.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
#include <cstdint>
using namespace llvm;
bool BaseIndexOffset::equalBaseIndex(const BaseIndexOffset &Other,
const SelectionDAG &DAG,
int64_t &Off) const {
if (!Base.getNode() || !Other.Base.getNode())
return false;
if (!hasValidOffset() || !Other.hasValidOffset())
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 (A->getIndex() == B->getIndex())
return true;
if (MFI.isFixedObjectIndex(A->getIndex()) &&
MFI.isFixedObjectIndex(B->getIndex())) {
Off += MFI.getObjectOffset(B->getIndex()) -
MFI.getObjectOffset(A->getIndex());
return true;
}
}
}
return false;
}
bool BaseIndexOffset::computeAliasing(const SDNode *Op0,
const Optional<int64_t> NumBytes0,
const SDNode *Op1,
const Optional<int64_t> NumBytes1,
const SelectionDAG &DAG, bool &IsAlias) {
BaseIndexOffset BasePtr0 = match(Op0, DAG);
BaseIndexOffset BasePtr1 = match(Op1, DAG);
if (!(BasePtr0.getBase().getNode() && BasePtr1.getBase().getNode()))
return false;
int64_t PtrDiff;
if (NumBytes0 && NumBytes1 &&
BasePtr0.equalBaseIndex(BasePtr1, DAG, PtrDiff)) {
if (PtrDiff >= 0 &&
*NumBytes0 != static_cast<int64_t>(MemoryLocation::UnknownSize)) {
IsAlias = !(*NumBytes0 <= PtrDiff);
return true;
}
if (PtrDiff < 0 &&
*NumBytes1 != static_cast<int64_t>(MemoryLocation::UnknownSize)) {
IsAlias = !((PtrDiff + *NumBytes1) <= 0);
return true;
}
return false;
}
if (auto *A = dyn_cast<FrameIndexSDNode>(BasePtr0.getBase()))
if (auto *B = dyn_cast<FrameIndexSDNode>(BasePtr1.getBase())) {
MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
if (A != B && (!MFI.isFixedObjectIndex(A->getIndex()) ||
!MFI.isFixedObjectIndex(B->getIndex()))) {
IsAlias = false;
return true;
}
}
bool IsFI0 = isa<FrameIndexSDNode>(BasePtr0.getBase());
bool IsFI1 = isa<FrameIndexSDNode>(BasePtr1.getBase());
bool IsGV0 = isa<GlobalAddressSDNode>(BasePtr0.getBase());
bool IsGV1 = isa<GlobalAddressSDNode>(BasePtr1.getBase());
bool IsCV0 = isa<ConstantPoolSDNode>(BasePtr0.getBase());
bool IsCV1 = isa<ConstantPoolSDNode>(BasePtr1.getBase());
if ((IsFI0 || IsGV0 || IsCV0) && (IsFI1 || IsGV1 || IsCV1)) {
if (IsFI0 != IsFI1 || IsGV0 != IsGV1 || IsCV0 != IsCV1) {
IsAlias = false;
return true;
}
if (IsGV0 && IsGV1) {
auto *GV0 = cast<GlobalAddressSDNode>(BasePtr0.getBase())->getGlobal();
auto *GV1 = cast<GlobalAddressSDNode>(BasePtr1.getBase())->getGlobal();
if (GV0 != GV1 && !isa<GlobalAlias>(GV0) && !isa<GlobalAlias>(GV1)) {
IsAlias = false;
return true;
}
}
}
return false; }
bool BaseIndexOffset::contains(const SelectionDAG &DAG, int64_t BitSize,
const BaseIndexOffset &Other,
int64_t OtherBitSize, int64_t &BitOffset) const {
int64_t Offset;
if (!equalBaseIndex(Other, DAG, Offset))
return false;
if (Offset >= 0) {
BitOffset = 8 * Offset;
return BitOffset + OtherBitSize <= BitSize;
}
return false;
}
static BaseIndexOffset matchLSNode(const 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 = DAG.getTargetLoweringInfo().unwrapAddress(Base->getOperand(0));
continue;
}
break;
case ISD::ADD:
if (auto *C = dyn_cast<ConstantSDNode>(Base->getOperand(1))) {
Offset += C->getSExtValue();
Base = DAG.getTargetLoweringInfo().unwrapAddress(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 = DAG.getTargetLoweringInfo().unwrapAddress(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);
}
BaseIndexOffset BaseIndexOffset::match(const SDNode *N,
const SelectionDAG &DAG) {
if (const auto *LS0 = dyn_cast<LSBaseSDNode>(N))
return matchLSNode(LS0, DAG);
if (const auto *LN = dyn_cast<LifetimeSDNode>(N)) {
if (LN->hasOffset())
return BaseIndexOffset(LN->getOperand(1), SDValue(), LN->getOffset(),
false);
return BaseIndexOffset(LN->getOperand(1), SDValue(), false);
}
return BaseIndexOffset();
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void BaseIndexOffset::dump() const {
print(dbgs());
}
void BaseIndexOffset::print(raw_ostream& OS) const {
OS << "BaseIndexOffset base=[";
Base->print(OS);
OS << "] index=[";
if (Index)
Index->print(OS);
OS << "] offset=" << Offset;
}
#endif