[llvm] [Attributor] Change allocation size and load/store offsets using AAPointerInfo for Alloca instructions (PR #72029)
Johannes Doerfert via llvm-commits
llvm-commits at lists.llvm.org
Sat Jun 22 11:51:53 PDT 2024
================
@@ -12752,39 +12732,284 @@ struct AAAllocationInfoImpl : public AAAllocationInfo {
assert(isValidState() &&
"Manifest should only be called if the state is valid.");
- Instruction *I = getIRPosition().getCtxI();
+ bool Changed = false;
+ const IRPosition &IRP = getIRPosition();
+ Instruction *I = IRP.getCtxI();
- auto FixedAllocatedSizeInBits = getAllocatedSize()->getFixedValue();
+ // check if simplified values exist
+ if (checkIfSimplifiedValuesExists(A, I))
+ return ChangeStatus::UNCHANGED;
- unsigned long NumBytesToAllocate = (FixedAllocatedSizeInBits + 7) / 8;
+ if (getAllocatedSize() == HasNoAllocationSize)
+ return ChangeStatus::UNCHANGED;
- switch (I->getOpcode()) {
- // TODO: add case for malloc like calls
- case Instruction::Alloca: {
+ const AAPointerInfo *PI =
+ A.getOrCreateAAFor<AAPointerInfo>(IRP, *this, DepClassTy::REQUIRED);
- AllocaInst *AI = cast<AllocaInst>(I);
+ if (!PI)
+ return ChangeStatus::UNCHANGED;
- Type *CharType = Type::getInt8Ty(I->getContext());
+ if (!PI->getState().isValidState())
+ return ChangeStatus::UNCHANGED;
- auto *NumBytesToValue =
- ConstantInt::get(I->getContext(), APInt(32, NumBytesToAllocate));
+ // Store a map where each instruction maps to a set of bins accessed by that
+ // instruction
+ DenseMap<Instruction *, DenseMap<AA::RangeTy, AA::RangeTy>>
+ AccessedInstructionsToBinsMap;
- BasicBlock::iterator insertPt = AI->getIterator();
- insertPt = std::next(insertPt);
- AllocaInst *NewAllocaInst =
- new AllocaInst(CharType, AI->getAddressSpace(), NumBytesToValue,
- AI->getAlign(), AI->getName(), insertPt);
+ auto AddBins =
+ [](DenseMap<Instruction *, DenseMap<AA::RangeTy, AA::RangeTy>> &Map,
+ Instruction *LocalInst, const AA::RangeTy &OldRange,
+ const AA::RangeTy &NewRange) {
+ DenseMap<AA::RangeTy, AA::RangeTy> &NewBinsForInstruction =
+ Map.getOrInsertDefault(LocalInst);
- if (A.changeAfterManifest(IRPosition::inst(*AI), *NewAllocaInst))
- return ChangeStatus::CHANGED;
+ NewBinsForInstruction.insert(std::make_pair(OldRange, NewRange));
+ };
+
+ const auto &NewOffsetsMap = getNewOffsets();
+ const auto &OffsetInfoMap = PI->getOffsetInfoMap();
+
+ // Map access causing instructions to tuple of (Old, New) bins.
+ // The access causing instruction contains the pointer operand
+ // which comes from the allocation
+ // We may want to backtrack that pointer operand, there are 2 cases that may
+ // arise:
+ // A) A GEP exists that calculates the pointer operand from the original
+ // allocation instruction: I
+ // B) A GEP does not exists
+ // in which case we need to insert a GEP just before the access causing
+ // instruction with the shift value from the original offset.
+ for (AAPointerInfo::OffsetBinsTy::const_iterator It = PI->begin();
+ It != PI->end(); It++) {
+ const auto &OldOffsetRange = It->getFirst();
+ // If the OldOffsetRange is not in the map, offsets for that bin did not
+ // change. We should just continue and skip changing the offsets in that
+ // case
+ if (!NewOffsetsMap.contains(OldOffsetRange))
+ continue;
+
+ const auto &NewOffsetRange = NewOffsetsMap.lookup(OldOffsetRange);
+ for (const auto AccIndex : It->getSecond()) {
+ const auto &AccessInstruction = PI->getBinAccess(AccIndex);
+ Instruction *LocalInst = AccessInstruction.getLocalInst();
+
+ if (checkIfSimplifiedValuesExists(A, LocalInst))
+ return ChangeStatus::UNCHANGED;
+
+ if (checkIfAccessChainUsesMultipleBins(A, LocalInst, OffsetInfoMap))
+ return ChangeStatus::UNCHANGED;
+
+ // check if we can backtrack the access causing instruction to a GEP
+ // from the original allocation, if yes, then we prefer to change the
+ // GEP rather than the access causing instruction
+ switch (LocalInst->getOpcode()) {
+ case Instruction::Load: {
+ LoadInst *Load = cast<LoadInst>(LocalInst);
+ Instruction *PointerOperand =
+ cast<Instruction>(Load->getPointerOperand());
+ Instruction *BackTrackedGEP =
+ backTrackPointerOperandToGepFromAllocation(PointerOperand, I);
+
+ if (!BackTrackedGEP) {
+ AddBins(AccessedInstructionsToBinsMap, LocalInst, OldOffsetRange,
+ NewOffsetRange);
+ break;
+ }
+
+ if (checkIfSimplifiedValuesExists(A, BackTrackedGEP))
+ return ChangeStatus::UNCHANGED;
+ AddBins(AccessedInstructionsToBinsMap, BackTrackedGEP, OldOffsetRange,
+ NewOffsetRange);
+ break;
+ }
+ case Instruction::Store: {
+ StoreInst *Store = cast<StoreInst>(LocalInst);
+ Instruction *PointerOperand =
+ cast<Instruction>(Store->getPointerOperand());
+ Instruction *BackTrackedGEP =
+ backTrackPointerOperandToGepFromAllocation(PointerOperand, I);
+
+ if (!BackTrackedGEP) {
+ AddBins(AccessedInstructionsToBinsMap, LocalInst, OldOffsetRange,
+ NewOffsetRange);
+ break;
+ }
+
+ if (checkIfSimplifiedValuesExists(A, BackTrackedGEP))
+ return ChangeStatus::UNCHANGED;
+
+ AddBins(AccessedInstructionsToBinsMap, BackTrackedGEP, OldOffsetRange,
+ NewOffsetRange);
+ break;
+ }
+ case Instruction::Call: {
+ CallInst *CallInstruction = cast<CallInst>(LocalInst);
+ for (auto *It = CallInstruction->op_begin();
+ It != CallInstruction->op_end(); It++) {
+ if (Instruction *OperandInstruction = dyn_cast<Instruction>(It)) {
+ // Operand does not have any accessed offsets
+ if (!OffsetInfoMap.contains(OperandInstruction))
+ continue;
+
+ // Find the old offset and the corresponding new offset for the
+ // call argument
+ auto OffsetsVecArg =
+ OffsetInfoMap.lookup(OperandInstruction).Offsets;
+ int64_t OldOffsetArg = OffsetsVecArg.front();
+ int NewOffsetArg = 0;
+ for (auto OldToNewRange : NewOffsetsMap) {
+ auto Old = OldToNewRange.getFirst();
+ if (Old.Offset == OldOffsetArg)
+ NewOffsetArg = OldToNewRange.getSecond().Offset;
+ }
+
+ // If the offsets did not change, no need to change the offsets.
+ if (NewOffsetArg == OldOffsetArg)
+ continue;
+
+ // We don't have access to the size of the offset here but its ok
+ // since we don't need it here.
+ AA::RangeTy CallArgOldRange = AA::RangeTy(OldOffsetArg, -1);
+ AA::RangeTy CallArgNewRange = AA::RangeTy(NewOffsetArg, -1);
+ Instruction *BackTrackedGEP =
+ backTrackPointerOperandToGepFromAllocation(OperandInstruction,
+ I);
+
+ if (!BackTrackedGEP) {
+ AddBins(AccessedInstructionsToBinsMap, OperandInstruction,
+ CallArgOldRange, CallArgNewRange);
+ continue;
+ }
+
+ if (checkIfSimplifiedValuesExists(A, BackTrackedGEP))
+ return ChangeStatus::UNCHANGED;
+
+ AddBins(AccessedInstructionsToBinsMap, BackTrackedGEP,
+ CallArgOldRange, CallArgNewRange);
+ }
+ }
+ break;
+ }
+ default: {
+ AddBins(AccessedInstructionsToBinsMap, LocalInst, OldOffsetRange,
+ NewOffsetRange);
+ break;
+ }
+ }
+ }
+ }
+
+ unsigned long FixedAllocatedSizeInBits =
+ getAllocatedSize()->getFixedValue();
+ unsigned long NumBytesToAllocate = (FixedAllocatedSizeInBits + 7) / 8;
+ Type *NewAllocationType = nullptr;
+ switch (I->getOpcode()) {
+ // TODO: add case for malloc like calls
+ case Instruction::Alloca: {
+ AllocaInst *OldAllocaInst = cast<AllocaInst>(I);
+ const DataLayout &DL = A.getDataLayout();
+ auto OriginalAllocationSize = OldAllocaInst->getAllocationSizeInBits(DL);
+
+ if (*OriginalAllocationSize <= FixedAllocatedSizeInBits)
+ return ChangeStatus::UNCHANGED;
+
+ Type *CharType = Type::getInt8Ty(I->getContext());
+ Type *CharArrayType = ArrayType::get(CharType, NumBytesToAllocate);
+ NewAllocationType = CharArrayType;
+ BasicBlock::iterator InsertPt = OldAllocaInst->getIterator();
+ InsertPt = std::next(InsertPt);
+ Instruction *NewAllocationInstruction =
+ new AllocaInst(CharArrayType, OldAllocaInst->getAddressSpace(),
+ OldAllocaInst->getName(), InsertPt);
+
+ Changed |= A.changeAfterManifest(IRPosition::inst(*I),
+ *NewAllocationInstruction);
+ A.deleteAfterManifest(*I);
break;
}
default:
break;
}
- return ChangeStatus::UNCHANGED;
+ for (auto &It : AccessedInstructionsToBinsMap) {
+ Instruction *LocalInst = It.first;
+ // Get a hold of a map, mapping old to new bins
+ DenseMap<AA::RangeTy, AA::RangeTy> &OldToNewBins = It.second;
+ IntegerType *Int64TyInteger =
+ IntegerType::get(LocalInst->getContext(), 64);
+ switch (LocalInst->getOpcode()) {
+ case Instruction::Load: {
+ // The number of bytes to shift the load/store by
+ int64_t OffsetOld = OldToNewBins.begin()->getFirst().Offset;
+ int64_t OffsetNew = OldToNewBins.begin()->getSecond().Offset;
+ LoadInst *OldLoadInst = cast<LoadInst>(LocalInst);
+ Instruction *PointerOperand =
+ cast<Instruction>(OldLoadInst->getPointerOperand());
+ Type *PointeeTy = OldLoadInst->getPointerOperandType();
+ int64_t ShiftValue = OffsetNew - OffsetOld;
+ Value *IndexList[1] = {ConstantInt::get(Int64TyInteger, ShiftValue)};
+ Value *GepToNewAddress = GetElementPtrInst::Create(
+ PointeeTy, PointerOperand, IndexList, "NewGep", OldLoadInst);
+
+ LoadInst *NewLoadInst = new LoadInst(
+ OldLoadInst->getType(), GepToNewAddress, OldLoadInst->getName(),
+ false, OldLoadInst->getAlign(), OldLoadInst);
+
+ Changed |=
+ A.changeAfterManifest(IRPosition::inst(*OldLoadInst), *NewLoadInst);
+
+ A.deleteAfterManifest(*OldLoadInst);
+ break;
+ }
+ case Instruction::Store: {
+ // The number of bytes to shift the load/store by
+ int64_t OffsetOld = OldToNewBins.begin()->getFirst().Offset;
+ int64_t OffsetNew = OldToNewBins.begin()->getSecond().Offset;
+ int64_t ShiftValue = OffsetNew - OffsetOld;
+ StoreInst *OldStoreInst = cast<StoreInst>(LocalInst);
+ Instruction *PointerOperand =
+ cast<Instruction>(OldStoreInst->getPointerOperand());
+ Type *PointeeTy = OldStoreInst->getPointerOperandType();
+ Value *IndexList[1] = {ConstantInt::get(Int64TyInteger, ShiftValue)};
+ Value *GepToNewAddress = GetElementPtrInst::Create(
+ PointeeTy, PointerOperand, IndexList, "NewGep", OldStoreInst);
+
+ StoreInst *NewStoreInst =
+ new StoreInst(OldStoreInst->getValueOperand(), GepToNewAddress,
+ false, OldStoreInst->getAlign(), OldStoreInst);
+
+ Changed |= A.changeAfterManifest(IRPosition::inst(*OldStoreInst),
+ *NewStoreInst);
+
+ A.deleteAfterManifest(*OldStoreInst);
+ break;
+ }
+ case Instruction::GetElementPtr: {
+ GetElementPtrInst *OldGEP = cast<GetElementPtrInst>(LocalInst);
+ int64_t OffsetNew = OldToNewBins.begin()->getSecond().Offset;
+ Value *IndexList[1] = {ConstantInt::get(Int64TyInteger, OffsetNew)};
+ Value *OldPointerOperand = OldGEP->getPointerOperand();
+ Value *GepToNewAddress = GetElementPtrInst::Create(
+ NewAllocationType, OldPointerOperand, IndexList, "NewGep", OldGEP);
+
+ Changed |=
+ A.changeAfterManifest(IRPosition::inst(*OldGEP), *GepToNewAddress);
+
+ A.deleteAfterManifest(*OldGEP);
+ break;
+ }
+ default:
+ static_assert(true, "[AAallocationInfo]: Changing offsets not "
+ "implemented for instruction!");
----------------
jdoerfert wrote:
What's this?
https://github.com/llvm/llvm-project/pull/72029
More information about the llvm-commits
mailing list