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,20 @@ void setExtraInfo(MachineFunction &MF, ArrayRef MMOs, MCSymbol *PreInstrSymbol, MCSymbol *PostInstrSymbol, MDNode *HeapAllocMarker); + + /// Check whether two instructions may alias without aliasing information. + /// This function expects one instruction will write to memory at least. + /// + /// Return true if two instructions access different memory addresses + /// and false otherwise. + bool + areMemOperandsTriviallyDisjoint(ArrayRef MMOpsA, + ArrayRef MMOpsB) 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 @@ -1312,6 +1312,9 @@ if (NumChecks > TII->getMemOperandAACheckLimit()) return true; + if (areMemOperandsTriviallyDisjoint(memoperands(), Other.memoperands())) + return false; + // Check each pair of memory operands from both instructions, which can't // alias only if all pairs won't alias. for (auto *MMOa : memoperands()) @@ -2331,3 +2334,89 @@ 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 two memory accesses whether 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()); +} + +bool MachineInstr::areMemOperandsTriviallyDisjoint( + ArrayRef MMOpsA, + ArrayRef MMOpsB) const { + assert(!MMOpsA.empty() && !MMOpsB.empty()); + + // Check each pair of memory operands from both instructions, which are + // disjoint only if all pairs won't access the same memory addresses. + for (auto MMOa : MMOpsA) { + for (auto MMOb : MMOpsB) { + if (!areMemOperandsTriviallyDisjoint(MMOa, MMOb)) { + return false; + } + } + } + + return true; +}