diff --git a/llvm/include/llvm/CodeGen/MachineInstr.h b/llvm/include/llvm/CodeGen/MachineInstr.h --- a/llvm/include/llvm/CodeGen/MachineInstr.h +++ b/llvm/include/llvm/CodeGen/MachineInstr.h @@ -1838,6 +1838,23 @@ } } + /// Return true if two memory address spaces may overlap and false otherwise. + virtual bool mayAddressSpacesOverlap(unsigned AddrSpaceA, + unsigned AddrSpaceB) const { + // Conservatively assume that any two memory address spaces may overlap. + return true; + } + + /// Return true if two memory accesses are disjoint for your target and false + /// otherwise. + /// + /// Both offset and width are in bytes. + virtual bool + areMemAccessesTriviallyDisjoint(uint64_t BaseAddrA, uint64_t OffsetA, + uint64_t WidthA, const Align &AlignA, + uint64_t BaseAddrB, uint64_t OffsetB, + uint64_t WidthB, const Align &AlignB) const; + private: /// If this instruction is embedded into a MachineFunction, return the /// MachineRegisterInfo object for the current function, otherwise @@ -1869,6 +1886,16 @@ void setExtraInfo(MachineFunction &MF, ArrayRef MMOs, MCSymbol *PreInstrSymbol, MCSymbol *PostInstrSymbol, MDNode *HeapAllocMarker); + + /// Return true if two memory operands do alias and false otherwise. + bool MemOperandsHaveAlias(const MachineFrameInfo &MFI, AAResults *AA, + bool UseTBAA, const MachineMemOperand *MMOa, + const MachineMemOperand *MMOb) const; + + /// Return true if two memory operands access different memory addresses and + /// false otherwise. + bool areMemOperandsTriviallyDisjoint(const MachineMemOperand *MMOa, + const MachineMemOperand *MMOb) const; }; /// Special DenseMapInfo traits to compare MachineInstr* by *value* of the diff --git a/llvm/lib/CodeGen/MachineInstr.cpp b/llvm/lib/CodeGen/MachineInstr.cpp --- a/llvm/lib/CodeGen/MachineInstr.cpp +++ b/llvm/lib/CodeGen/MachineInstr.cpp @@ -1211,9 +1211,10 @@ return true; } -static bool MemOperandsHaveAlias(const MachineFrameInfo &MFI, AAResults *AA, - bool UseTBAA, const MachineMemOperand *MMOa, - const MachineMemOperand *MMOb) { +bool MachineInstr::MemOperandsHaveAlias(const MachineFrameInfo &MFI, + AAResults *AA, bool UseTBAA, + const MachineMemOperand *MMOa, + const MachineMemOperand *MMOb) const { // The following interface to AA is fashioned after DAGCombiner::isAlias and // operates with MachineMemOperand offset with some important assumptions: // - LLVM fundamentally assumes flat address spaces. @@ -1227,6 +1228,10 @@ // can save compile time, and possibly catch some corner cases not currently // covered. + if (areMemOperandsTriviallyDisjoint(MMOa, MMOb)) { + return false; + } + int64_t OffsetA = MMOa->getOffset(); int64_t OffsetB = MMOb->getOffset(); int64_t MinOffset = std::min(OffsetA, OffsetB); @@ -2331,3 +2336,71 @@ DebugInstrNum = MF.getNewDebugInstrNum(); return DebugInstrNum; } + +// If the value of base address contained in this memory operand is constant, +// update it to `BaseAddr` and return true. Otherwise, return false. +static bool getConstantBaseAddress(const MachineMemOperand *MMO, + uint64_t &BaseAddr) { + const Value *Val = MMO->getValue(); + + if (!Val) { + return false; + } + + if (auto *CE = dyn_cast(Val)) { + if (CE->getOpcode() == Instruction::IntToPtr && + isa(CE->getOperand(0))) { + auto Op0 = dyn_cast(CE->getOperand(0)); + BaseAddr = Op0->getUniqueInteger().getZExtValue(); + return true; + } + } + + return false; +} + +bool MachineInstr::areMemAccessesTriviallyDisjoint( + uint64_t BaseAddrA, uint64_t OffsetA, uint64_t WidthA, const Align &AlignA, + uint64_t BaseAddrB, uint64_t OffsetB, uint64_t WidthB, + const Align &AlignB) const { + // Check whether two memory accesses overlap, ignoring alignment. + const auto StartAddrA = BaseAddrA + OffsetA; + const auto EndAddrA = StartAddrA + WidthA; + const auto StartAddrB = BaseAddrB + OffsetB; + const auto EndAddrB = StartAddrB + WidthB; + return std::max(StartAddrA, StartAddrB) >= std::min(EndAddrA, EndAddrB); +} + +bool MachineInstr::areMemOperandsTriviallyDisjoint( + const MachineMemOperand *MMOa, const MachineMemOperand *MMOb) const { + if (!mayAddressSpacesOverlap(MMOa->getAddrSpace(), MMOb->getAddrSpace())) { + return true; + } + + // Skip if the base address is not constant. + uint64_t BaseAddrA = 0; + uint64_t BaseAddrB = 0; + if (!getConstantBaseAddress(MMOa, BaseAddrA) || + !getConstantBaseAddress(MMOb, BaseAddrB)) { + return false; + } + + // Skip if the offset from the base address is negative. + const int64_t OffsetA = MMOa->getOffset(); + const int64_t OffsetB = MMOb->getOffset(); + if (OffsetA < 0 || OffsetB < 0) { + return false; + } + + // Skip if the size of the memory reference is unknown. + const uint64_t WidthA = MMOa->getSize(); + const uint64_t WidthB = MMOb->getSize(); + if (WidthA == MemoryLocation::UnknownSize || + WidthB == MemoryLocation::UnknownSize) { + return false; + } + + return areMemAccessesTriviallyDisjoint(BaseAddrA, OffsetA, WidthA, + MMOa->getAlign(), BaseAddrB, OffsetB, + WidthB, MMOb->getAlign()); +}