diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h --- a/llvm/include/llvm/Target/TargetMachine.h +++ b/llvm/include/llvm/Target/TargetMachine.h @@ -403,6 +403,22 @@ virtual unsigned getAddressSpaceForPseudoSourceKind(unsigned Kind) const { return 0; } + + /// 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. + /// + /// Offset, width and alignment are in bytes. + virtual bool areMemAccessesTriviallyDisjoint( + uint64_t BaseAddrA, uint64_t OffsetA, uint64_t WidthA, uint64_t AlignA, + unsigned AddrSpaceA, uint64_t BaseAddrB, uint64_t OffsetB, + uint64_t WidthB, uint64_t AlignB, unsigned AddrSpaceB) const; }; /// This class describes a target machine that is implemented with the LLVM 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,7 +1211,73 @@ return true; } -static bool MemOperandsHaveAlias(const MachineFrameInfo &MFI, AAResults *AA, +// 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)); + const APInt &Int = Op0->getUniqueInteger(); + if (Int.getActiveBits() <= 64) { + BaseAddr = Int.getZExtValue(); + return true; + } + } + } + + return false; +} + +/// Return true if two memory operands access different memory addresses and +/// false otherwise. +static bool areMemOperandsTriviallyDisjoint(const TargetMachine &TM, + const MachineMemOperand *MMOa, + const MachineMemOperand *MMOb) { + const unsigned AddrSpaceA = MMOa->getAddrSpace(); + const unsigned AddrSpaceB = MMOb->getAddrSpace(); + if (AddrSpaceA != AddrSpaceB && + !TM.mayAddressSpacesOverlap(AddrSpaceA, AddrSpaceB)) { + 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 TM.areMemAccessesTriviallyDisjoint( + BaseAddrA, OffsetA, WidthA, MMOa->getAlign().value(), AddrSpaceA, + BaseAddrB, OffsetB, WidthB, MMOb->getAlign().value(), AddrSpaceB); +} + +static bool MemOperandsHaveAlias(const TargetMachine &TM, + const MachineFrameInfo &MFI, AAResults *AA, bool UseTBAA, const MachineMemOperand *MMOa, const MachineMemOperand *MMOb) { // The following interface to AA is fashioned after DAGCombiner::isAlias and @@ -1227,6 +1293,10 @@ // can save compile time, and possibly catch some corner cases not currently // covered. + if (areMemOperandsTriviallyDisjoint(TM, MMOa, MMOb)) { + return false; + } + int64_t OffsetA = MMOa->getOffset(); int64_t OffsetB = MMOb->getOffset(); int64_t MinOffset = std::min(OffsetA, OffsetB); @@ -1283,6 +1353,7 @@ const MachineFunction *MF = getMF(); const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo(); const MachineFrameInfo &MFI = MF->getFrameInfo(); + const TargetMachine &TM = MF->getTarget(); // Exclude call instruction which may alter the memory but can not be handled // by this function. @@ -1316,7 +1387,7 @@ // alias only if all pairs won't alias. for (auto *MMOa : memoperands()) for (auto *MMOb : Other.memoperands()) - if (MemOperandsHaveAlias(MFI, AA, UseTBAA, MMOa, MMOb)) + if (MemOperandsHaveAlias(TM, MFI, AA, UseTBAA, MMOa, MMOb)) return true; return false; diff --git a/llvm/lib/Target/TargetMachine.cpp b/llvm/lib/Target/TargetMachine.cpp --- a/llvm/lib/Target/TargetMachine.cpp +++ b/llvm/lib/Target/TargetMachine.cpp @@ -231,3 +231,20 @@ Version.consumeInteger(10, Ret.second); return Ret; } + +bool TargetMachine::areMemAccessesTriviallyDisjoint( + uint64_t BaseAddrA, uint64_t OffsetA, uint64_t WidthA, uint64_t AlignA, + unsigned AddrSpaceA, uint64_t BaseAddrB, uint64_t OffsetB, uint64_t WidthB, + uint64_t AlignB, unsigned AddrSpaceB) const { + if (AddrSpaceA != AddrSpaceB) { + return false; + } + + // Check whether two memory accesses with the same address space overlap, + // ignoring alignment. + uint64_t StartAddrA = BaseAddrA + OffsetA; + uint64_t EndAddrA = StartAddrA + WidthA; + uint64_t StartAddrB = BaseAddrB + OffsetB; + uint64_t EndAddrB = StartAddrB + WidthB; + return std::max(StartAddrA, StartAddrB) >= std::min(EndAddrA, EndAddrB); +}