- Notifications
You must be signed in to change notification settings - Fork 15.3k
[Attributor] Change allocation size and load/store offsets using AAPointerInfo for Alloca instructions and keep track of instructions causing an Access #72029
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
| @llvm/pr-subscribers-llvm-transforms Author: Vidhush Singhal (vidsinghal) ChangesWork in progress a.) Need to fix some TODOs (if offsets need to be changed for Load and Store instructions) Patch is 295.62 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/72029.diff 46 Files Affected:
diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h index bd1bd8261123e51..8488568113d553c 100644 --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -103,6 +103,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetOperations.h" #include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/iterator.h" #include "llvm/Analysis/AssumeBundleQueries.h" #include "llvm/Analysis/CFG.h" @@ -132,6 +133,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ModRef.h" #include "llvm/Support/TimeProfiler.h" +#include "llvm/Support/TypeSize.h" #include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/Utils/CallGraphUpdater.h" @@ -6117,6 +6119,14 @@ struct AAPointerInfo : public AbstractAttribute { /// See AbstractAttribute::getIdAddr() const char *getIdAddr() const override { return &ID; } + using OffsetBinsTy = DenseMap<AA::RangeTy, SmallSet<unsigned, 4>>; + using const_bin_iterator = OffsetBinsTy::const_iterator; + virtual const_bin_iterator begin() const = 0; + virtual const_bin_iterator end() const = 0; + virtual int64_t numOffsetBins() const = 0; + virtual void dumpState(raw_ostream &O) const = 0; + virtual const Access &getBinAccess(unsigned Index) const = 0; + /// Call \p CB on all accesses that might interfere with \p Range and return /// true if all such accesses were known and the callback returned true for /// all of them, false otherwise. An access interferes with an offset-size @@ -6270,6 +6280,44 @@ struct AAAddressSpace : public StateWrapper<BooleanState, AbstractAttribute> { static const char ID; }; +struct AAAllocationInfo : public StateWrapper<BooleanState, AbstractAttribute> { + AAAllocationInfo(const IRPosition &IRP, Attributor &A) + : StateWrapper<BooleanState, AbstractAttribute>(IRP) {} + + /// See AbstractAttribute::isValidIRPositionForInit + static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) { + if (!IRP.getAssociatedType()->isPtrOrPtrVectorTy()) + return false; + return AbstractAttribute::isValidIRPositionForInit(A, IRP); + } + + /// Create an abstract attribute view for the position \p IRP. + static AAAllocationInfo &createForPosition(const IRPosition &IRP, + Attributor &A); + + virtual std::optional<TypeSize> getAllocatedSize() const = 0; + + using NewOffsetsTy = DenseMap<AA::RangeTy, AA::RangeTy>; + virtual const NewOffsetsTy &getNewOffsets() const = 0; + + /// See AbstractAttribute::getName() + const std::string getName() const override { return "AAAllocationInfo"; } + + /// See AbstractAttribute::getIdAddr() + const char *getIdAddr() const override { return &ID; } + + /// This function should return true if the type of the \p AA is + /// AAAllocationInfo + static bool classof(const AbstractAttribute *AA) { + return (AA->getIdAddr() == &ID); + } + + constexpr static const std::optional<TypeSize> HasNoAllocationSize = + std::optional<TypeSize>(TypeSize(-1, true)); + + static const char ID; +}; + /// An abstract interface for llvm::GlobalValue information interference. struct AAGlobalValueInfo : public StateWrapper<BooleanState, AbstractAttribute> { diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp index 49ced893d5c7340..f1a88bc564ced71 100644 --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -3611,14 +3611,13 @@ void Attributor::identifyDefaultAbstractAttributes(Function &F) { }; auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F); - bool Success; + [[maybe_unused]] bool Success; bool UsedAssumedInformation = false; Success = checkForAllInstructionsImpl( nullptr, OpcodeInstMap, CallSitePred, nullptr, nullptr, {(unsigned)Instruction::Invoke, (unsigned)Instruction::CallBr, (unsigned)Instruction::Call}, UsedAssumedInformation); - (void)Success; assert(Success && "Expected the check call to be successful!"); auto LoadStorePred = [&](Instruction &I) -> bool { @@ -3644,7 +3643,17 @@ void Attributor::identifyDefaultAbstractAttributes(Function &F) { nullptr, OpcodeInstMap, LoadStorePred, nullptr, nullptr, {(unsigned)Instruction::Load, (unsigned)Instruction::Store}, UsedAssumedInformation); - (void)Success; + assert(Success && "Expected the check call to be successful!"); + + // AllocaInstPredicate + auto AAAllocationInfoPred = [&](Instruction &I) -> bool { + getOrCreateAAFor<AAAllocationInfo>(IRPosition::value(I)); + return true; + }; + + Success = checkForAllInstructionsImpl( + nullptr, OpcodeInstMap, AAAllocationInfoPred, nullptr, nullptr, + {(unsigned)Instruction::Alloca}, UsedAssumedInformation); assert(Success && "Expected the check call to be successful!"); } diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp index bbb0cfa0eb05fe6..dea00c0039798b2 100644 --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -65,6 +65,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/GraphWriter.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/TypeSize.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/CallPromotionUtils.h" @@ -192,6 +193,7 @@ PIPE_OPERATOR(AAPointerInfo) PIPE_OPERATOR(AAAssumptionInfo) PIPE_OPERATOR(AAUnderlyingObjects) PIPE_OPERATOR(AAAddressSpace) +PIPE_OPERATOR(AAAllocationInfo) PIPE_OPERATOR(AAIndirectCallInfo) PIPE_OPERATOR(AAGlobalValueInfo) PIPE_OPERATOR(AADenormalFPMath) @@ -881,11 +883,9 @@ struct AA::PointerInfo::State : public AbstractState { AAPointerInfo::AccessKind Kind, Type *Ty, Instruction *RemoteI = nullptr); - using OffsetBinsTy = DenseMap<RangeTy, SmallSet<unsigned, 4>>; - - using const_bin_iterator = OffsetBinsTy::const_iterator; - const_bin_iterator begin() const { return OffsetBins.begin(); } - const_bin_iterator end() const { return OffsetBins.end(); } + AAPointerInfo::const_bin_iterator begin() const { return OffsetBins.begin(); } + AAPointerInfo::const_bin_iterator end() const { return OffsetBins.end(); } + int64_t numOffsetBins() const { return OffsetBins.size(); } const AAPointerInfo::Access &getAccess(unsigned Index) const { return AccessList[Index]; @@ -905,7 +905,7 @@ struct AA::PointerInfo::State : public AbstractState { // are all combined into a single Access object. This may result in loss of // information in RangeTy in the Access object. SmallVector<AAPointerInfo::Access> AccessList; - OffsetBinsTy OffsetBins; + AAPointerInfo::OffsetBinsTy OffsetBins; DenseMap<const Instruction *, SmallVector<unsigned>> RemoteIMap; /// See AAPointerInfo::forallInterferingAccesses. @@ -1109,6 +1109,16 @@ struct AAPointerInfoImpl return AAPointerInfo::manifest(A); } + virtual const_bin_iterator begin() const override { return State::begin(); } + virtual const_bin_iterator end() const override { return State::end(); } + virtual int64_t numOffsetBins() const override { + return State::numOffsetBins(); + } + + virtual const Access &getBinAccess(unsigned Index) const override { + return getAccess(Index); + } + bool forallInterferingAccesses( AA::RangeTy Range, function_ref<bool(const AAPointerInfo::Access &, bool)> CB) @@ -1455,7 +1465,7 @@ struct AAPointerInfoImpl void trackPointerInfoStatistics(const IRPosition &IRP) const {} /// Dump the state into \p O. - void dumpState(raw_ostream &O) { + virtual void dumpState(raw_ostream &O) const override { for (auto &It : OffsetBins) { O << "[" << It.first.Offset << "-" << It.first.Offset + It.first.Size << "] : " << It.getSecond().size() << "\n"; @@ -6521,7 +6531,7 @@ struct AAValueSimplifyCallSiteReturned : AAValueSimplifyImpl { /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { - return indicatePessimisticFixpoint(); + return indicatePessimisticFixpoint(); } void trackStatistics() const override { @@ -12688,6 +12698,330 @@ struct AAAddressSpaceCallSiteArgument final : AAAddressSpaceImpl { }; } // namespace +/// ----------- Allocation Info ---------- +namespace { +struct AAAllocationInfoImpl : public AAAllocationInfo { + AAAllocationInfoImpl(const IRPosition &IRP, Attributor &A) + : AAAllocationInfo(IRP, A) {} + + std::optional<TypeSize> getAllocatedSize() const override { + assert(isValidState() && "the AA is invalid"); + return AssumedAllocatedSize; + } + + const NewOffsetsTy &getNewOffsets() const override { + assert(isValidState() && "the AA is invalid"); + return NewComputedOffsets; + } + + std::optional<TypeSize> findInitialAllocationSize(Instruction *I, + const DataLayout &DL) { + + // TODO: implement case for malloc like instructions + switch (I->getOpcode()) { + case Instruction::Alloca: { + AllocaInst *AI = cast<AllocaInst>(I); + return AI->getAllocationSize(DL); + } + default: + return std::nullopt; + } + } + + ChangeStatus updateImpl(Attributor &A) override { + + const IRPosition &IRP = getIRPosition(); + Instruction *I = IRP.getCtxI(); + + // TODO: update check for malloc like calls + if (!isa<AllocaInst>(I)) + return indicatePessimisticFixpoint(); + + bool IsKnownNoCapture; + if (!AA::hasAssumedIRAttr<Attribute::NoCapture>( + A, this, IRP, DepClassTy::OPTIONAL, IsKnownNoCapture)) + return indicatePessimisticFixpoint(); + + const AAPointerInfo *PI = + A.getOrCreateAAFor<AAPointerInfo>(IRP, *this, DepClassTy::REQUIRED); + + if (!PI) + return indicatePessimisticFixpoint(); + + if (!PI->getState().isValidState()) + return indicatePessimisticFixpoint(); + + const DataLayout &DL = A.getDataLayout(); + const auto AllocationSize = findInitialAllocationSize(I, DL); + + // If allocation size is nullopt, we give up. + if (!AllocationSize) + return indicatePessimisticFixpoint(); + + // For zero sized allocations, we give up. + // Since we can't reduce further + if (*AllocationSize == 0) + return indicatePessimisticFixpoint(); + + int64_t NumBins = PI->numOffsetBins(); + + if (NumBins == 0) { + auto NewAllocationSize = std::optional<TypeSize>(TypeSize(0, false)); + if (!changeAllocationSize(NewAllocationSize)) + return ChangeStatus::UNCHANGED; + return ChangeStatus::CHANGED; + } + + // For each bin, compute its new start Offset and store the results. + int64_t PrevBinEndOffset = 0; + bool ChangedOffsets = false; + for (auto It = PI->begin(); It != PI->end(); It++) { + const AA::RangeTy &OldRange = It->getFirst(); + + int64_t NewStartOffset = PrevBinEndOffset; + int64_t NewEndOffset = NewStartOffset + OldRange.Size; + + PrevBinEndOffset = NewEndOffset; + ChangedOffsets |= + setOffets(OldRange, OldRange.Offset, NewStartOffset, OldRange.Size); + } + + // Set the new size of the allocation, the new size if the New End Offset of + // the last Bin. + auto NewAllocationSize = + std::optional<TypeSize>(TypeSize(PrevBinEndOffset * 8, false)); + if (!changeAllocationSize(NewAllocationSize)) + return ChangeStatus::UNCHANGED; + + if (!ChangedOffsets) + return ChangeStatus::UNCHANGED; + + return ChangeStatus::CHANGED; + } + + /// See AbstractAttribute::manifest(...). + ChangeStatus manifest(Attributor &A) override { + + assert(isValidState() && + "Manifest should only be called if the state is valid."); + + const IRPosition &IRP = getIRPosition(); + Instruction *I = IRP.getCtxI(); + + auto FixedAllocatedSizeInBits = getAllocatedSize()->getFixedValue(); + + unsigned long NumBytesToAllocate = (FixedAllocatedSizeInBits + 7) / 8; + bool Changed = false; + switch (I->getOpcode()) { + // TODO: add case for malloc like calls + case Instruction::Alloca: { + + AllocaInst *AI = cast<AllocaInst>(I); + + Type *CharType = Type::getInt8Ty(I->getContext()); + + auto *NumBytesToValue = + ConstantInt::get(I->getContext(), APInt(32, NumBytesToAllocate)); + + AllocaInst *NewAllocaInst = + new AllocaInst(CharType, AI->getAddressSpace(), NumBytesToValue, + AI->getAlign(), AI->getName(), AI->getNextNode()); + + Changed |= A.changeAfterManifest(IRPosition::inst(*AI), *NewAllocaInst); + + break; + } + default: + break; + } + + const AAPointerInfo *PI = + A.getOrCreateAAFor<AAPointerInfo>(IRP, *this, DepClassTy::REQUIRED); + + if (!PI) + return ChangeStatus::UNCHANGED; + + if (!PI->getState().isValidState()) + return ChangeStatus::UNCHANGED; + + const auto &NewOffsets = getNewOffsets(); + for (auto It = PI->begin(); It != PI->end(); It++) { + + const auto &OldOffset = It->getFirst(); + + // If the OldOffsets are not present as a key, they did not change + // Hence, we should just continue + if (!NewOffsets.contains(OldOffset)) + continue; + + const auto &NewOffset = NewOffsets.lookup(OldOffset); + for (auto AccIndex : It->getSecond()) { + + const auto &AccessInstruction = PI->getBinAccess(AccIndex); + const auto *LocalInst = AccessInstruction.getLocalInst(); + + auto UsePred = [&](const Use &U, bool &Follow) -> bool { + User *Usr = U.getUser(); + + auto NumOperands = LocalInst->getNumOperands(); + for (unsigned Index = 0; Index < NumOperands; Index++) { + auto *Operand = LocalInst->getOperand(Index); + if (Operand == Usr) { + Instruction *UsrI = cast<Instruction>(Operand); + switch (UsrI->getOpcode()) { + case Instruction::GetElementPtr: { + // find the new offsets from the New OffsetMap, Change the + // instruction to use the new Offsets. + auto OffsetStart = NewOffset.Offset; + GetElementPtrInst *GEP = cast<GetElementPtrInst>(UsrI); + Value *NewComputedByteIndex = + ConstantInt::get(I->getContext(), APInt(8, OffsetStart)); + SmallVector<Value *, 1> ArrayRefVector{NewComputedByteIndex}; + ArrayRef<Value *> AryRef = ArrayRef(ArrayRefVector); + GetElementPtrInst *NewGEP = GetElementPtrInst::Create( + GEP->getPointerOperandType(), GEP->getPointerOperand(), + AryRef, GEP->getName(), GEP->getNextNode()); + + Changed |= + A.changeAfterManifest(IRPosition::inst(*GEP), *NewGEP); + break; + } + // TODO: Implement to fix load and store too. + default: { + break; + } + } + } + } + return true; + }; + + Changed |= A.checkForAllUses(UsePred, *this, IRP.getAssociatedValue()); + } + } + + if (!Changed) + return ChangeStatus::UNCHANGED; + + return ChangeStatus::CHANGED; + } + + /// See AbstractAttribute::getAsStr(). + const std::string getAsStr(Attributor *A) const override { + if (!isValidState()) + return "allocationinfo(<invalid>)"; + return "allocationinfo(" + + (AssumedAllocatedSize == HasNoAllocationSize + ? "none" + : std::to_string(AssumedAllocatedSize->getFixedValue())) + + ")"; + } + + void dumpNewOffsetBins(raw_ostream &O) { + + const auto &NewOffsetBins = getNewOffsets(); + for (auto It = NewOffsetBins.begin(); It != NewOffsetBins.end(); It++) { + + const auto &OldRange = It->getFirst(); + const auto &NewRange = It->getSecond(); + + O << "[" << OldRange.Offset << "," << OldRange.Offset + OldRange.Size + << "] : "; + O << "[" << NewRange.Offset << "," << NewRange.Offset + NewRange.Size + << "]"; + O << "\n\n"; + } + } + +private: + std::optional<TypeSize> AssumedAllocatedSize = HasNoAllocationSize; + NewOffsetsTy NewComputedOffsets; + + // Maintain the computed allocation size of the object. + // Returns (bool) weather the size of the allocation was modified or not. + bool changeAllocationSize(std::optional<TypeSize> Size) { + if (AssumedAllocatedSize == HasNoAllocationSize || + AssumedAllocatedSize != Size) { + AssumedAllocatedSize = Size; + return true; + } + return false; + } + + // Function to update the OldRange to the new Range. + bool setOffets(const AA::RangeTy &OldRange, int64_t OldOffset, + int64_t NewComputedOffset, int64_t Size) { + + if (OldOffset == NewComputedOffset) + return false; + + AA::RangeTy &NewRange = NewComputedOffsets.getOrInsertDefault(OldRange); + NewRange.Offset = NewComputedOffset; + NewRange.Size = Size; + + return true; + } +}; + +struct AAAllocationInfoFloating : AAAllocationInfoImpl { + AAAllocationInfoFloating(const IRPosition &IRP, Attributor &A) + : AAAllocationInfoImpl(IRP, A) {} + + void trackStatistics() const override { + STATS_DECLTRACK_FLOATING_ATTR(allocationinfo); + } +}; + +struct AAAllocationInfoReturned : AAAllocationInfoImpl { + AAAllocationInfoReturned(const IRPosition &IRP, Attributor &A) + : AAAllocationInfoImpl(IRP, A) {} + + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + // TODO: we don't rewrite function argument for now because it will need to + // rewrite the function signature and all call sites + (void)indicatePessimisticFixpoint(); + } + + void trackStatistics() const override { + STATS_DECLTRACK_FNRET_ATTR(allocationinfo); + } +}; + +struct AAAllocationInfoCallSiteReturned : AAAllocationInfoImpl { + AAAllocationInfoCallSiteReturned(const IRPosition &IRP, Attributor &A) + : AAAllocationInfoImpl(IRP, A) {} + + void trackStatistics() const override { + STATS_DECLTRACK_CSRET_ATTR(allocationinfo); + } +}; + +struct AAAllocationInfoArgument : AAAllocationInfoImpl { + AAAllocationInfoArgument(const IRPosition &IRP, Attributor &A) + : AAAllocationInfoImpl(IRP, A) {} + + void trackStatistics() const override { + STATS_DECLTRACK_ARG_ATTR(allocationinfo); + } +}; + +struct AAAllocationInfoCallSiteArgument : AAAllocationInfoImpl { + AAAllocationInfoCallSiteArgument(const IRPosition &IRP, Attributor &A) + : AAAllocationInfoImpl(IRP, A) {} + + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + + (void)indicatePessimisticFixpoint(); + } + + void trackStatistics() const override { + STATS_DECLTRACK_CSARG_ATTR(allocationinfo); + } +}; +} // namespace + const char AANoUnwind::ID = 0; const char AANoSync::ID = 0; const char AANoFree::ID = 0; @@ -12721,6 +13055,7 @@ const char AAPointerInfo::ID = 0; const char AAAssumptionInfo::ID = 0; const char AAUnderlyingObjects::ID = 0; const char AAAddressSpace::ID = 0; +const char AAAllocationInfo::ID = 0; const char AAIndirectCallInfo::ID = 0; const char AAGlobalValueInfo::ID = 0; const char AADenormalFPMath::ID = 0; @@ -12854,6 +13189,7 @@ CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoUndef) CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoFPClass) CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAPointerInfo) CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAAddressSpace) +CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAAllocationInfo) CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAValueSimplify) CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAIsDead) diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-02-01-ReturnAttrs.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-02-01-ReturnAttrs.ll index 8254ab6230440f5..e6062da1d1457b9 100644 --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-02-01-ReturnAttrs.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-02-01-ReturnAttrs.ll @@ -9,8 +9,8 @@ define internal i32 @deref(ptr %x) nounwind { ; CG... [truncated] |
c036a1e to 29bf401 Compare | ✅ With the latest revision this PR passed the C/C++ code formatter. |
7f60962 to ae1d871 Compare ae1d871 to 04fdbe9 Compare 04fdbe9 to 83f44a8 Compare | Is this ready for review? The commit message states something about existing errors. |
nikic left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Just some drive-by notes)
llvm/test/Transforms/Attributor/ArgumentPromotion/2008-02-01-ReturnAttrs.ll Outdated Show resolved Hide resolved
Hello Johannes, these errors were supposed to be discussed for a potential fix. |
Hi Nikita, thanks for reviewing! |
f4bbc49 to 3ac2f16 Compare da7e567 to 83986bd Compare 194b53e to 46abfd1 Compare
shiltian left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took another round of look. The test changes look good now, except those that don't look related to this PR. The memory allocation needs to be changed; otherwise there would be memory leak. The use of auto needs to be checked as well, since LLVM generally discourages to use auto. The cast and iterator would be fine.
1cc8887 to a31bf92 Compare …ointerInfo for Alloca instructions
a31bf92 to 59d2bcf Compare
This PR updates the way
AAAllocationInfohandles alloca objects whose allocation size can be reduced. When the size of an Alloca instruction is modified, the associated load and store instructions may require adjusted offsets. This PR adds logic to recompute those offsets by inserting updated GEPs with the correct shifted indices.In addition to resizing the Alloca and updating all related memory accesses, this PR introduces the ability to track the complete chain of instructions responsible for each accessed byte (“bin”) in an Alloca as recorded by
AAPointerInfo. This richer origin information is useful for both future analyses and the offset-adjustment process introduced here.Summary of Changes
The internal data structure for offsets now includes Origins, allowing each byte/bin to retain information about the instructions that caused its access.
AAAllocationInfoAdded logic to eliminate dead bytes during allocation-size refinement.
Added support for rewriting address computations: whenever dead bytes are removed or the size changes, all GEPs derived from the affected alloca are updated to reflect the new layout and shifted offsets.