Skip to content

Commit 83986bd

Browse files
vidsinghalVidush Singhal
authored and
Vidush Singhal
committed
[Attributor] Fix Load/Store Offsets if multiple bins are present for a pointer allocation.
1 parent 8e3be5c commit 83986bd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1196
-836
lines changed

llvm/include/llvm/Transforms/IPO/Attributor.h

+8-9
Original file line numberDiff line numberDiff line change
@@ -5143,9 +5143,7 @@ struct DenormalFPMathState : public AbstractState {
51435143
return Mode != Other.Mode || ModeF32 != Other.ModeF32;
51445144
}
51455145

5146-
bool isValid() const {
5147-
return Mode.isValid() && ModeF32.isValid();
5148-
}
5146+
bool isValid() const { return Mode.isValid() && ModeF32.isValid(); }
51495147

51505148
static DenormalMode::DenormalModeKind
51515149
unionDenormalKind(DenormalMode::DenormalModeKind Callee,
@@ -5185,9 +5183,7 @@ struct DenormalFPMathState : public AbstractState {
51855183
// state.
51865184
DenormalState getAssumed() const { return Known; }
51875185

5188-
bool isValidState() const override {
5189-
return Known.isValid();
5190-
}
5186+
bool isValidState() const override { return Known.isValid(); }
51915187

51925188
/// Return true if there are no dynamic components to the denormal mode worth
51935189
/// specializing.
@@ -5198,9 +5194,7 @@ struct DenormalFPMathState : public AbstractState {
51985194
Known.ModeF32.Output != DenormalMode::Dynamic;
51995195
}
52005196

5201-
bool isAtFixpoint() const override {
5202-
return IsAtFixedpoint;
5203-
}
5197+
bool isAtFixpoint() const override { return IsAtFixedpoint; }
52045198

52055199
ChangeStatus indicateFixpoint() {
52065200
bool Changed = !IsAtFixedpoint;
@@ -6122,6 +6116,8 @@ struct AAPointerInfo : public AbstractAttribute {
61226116
virtual const_bin_iterator begin() const = 0;
61236117
virtual const_bin_iterator end() const = 0;
61246118
virtual int64_t numOffsetBins() const = 0;
6119+
virtual void dumpState(raw_ostream &O) const = 0;
6120+
virtual const Access &getBinAccess(unsigned Index) const = 0;
61256121

61266122
/// Call \p CB on all accesses that might interfere with \p Range and return
61276123
/// true if all such accesses were known and the callback returned true for
@@ -6293,6 +6289,9 @@ struct AAAllocationInfo : public StateWrapper<BooleanState, AbstractAttribute> {
62936289

62946290
virtual std::optional<TypeSize> getAllocatedSize() const = 0;
62956291

6292+
using NewOffsetsTy = DenseMap<AA::RangeTy, AA::RangeTy>;
6293+
virtual const NewOffsetsTy &getNewOffsets() const = 0;
6294+
62966295
/// See AbstractAttribute::getName()
62976296
const std::string getName() const override { return "AAAllocationInfo"; }
62986297

llvm/lib/Transforms/IPO/AttributorAttributes.cpp

+164-38
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,8 @@ struct AAReturnedFromReturnedValues : public BaseType {
419419
/// See AbstractAttribute::updateImpl(...).
420420
ChangeStatus updateImpl(Attributor &A) override {
421421
StateType S(StateType::getBestState(this->getState()));
422-
clampReturnedValueStates<AAType, StateType, IRAttributeKind, RecurseForSelectAndPHI>(
422+
clampReturnedValueStates<AAType, StateType, IRAttributeKind,
423+
RecurseForSelectAndPHI>(
423424
A, *this, S,
424425
PropagateCallBaseContext ? this->getCallBaseContext() : nullptr);
425426
// TODO: If we know we visited all returned values, thus no are assumed
@@ -1083,6 +1084,10 @@ struct AAPointerInfoImpl
10831084
return State::numOffsetBins();
10841085
}
10851086

1087+
virtual const Access &getBinAccess(unsigned Index) const override {
1088+
return getAccess(Index);
1089+
}
1090+
10861091
bool forallInterferingAccesses(
10871092
AA::RangeTy Range,
10881093
function_ref<bool(const AAPointerInfo::Access &, bool)> CB)
@@ -1429,7 +1434,7 @@ struct AAPointerInfoImpl
14291434
void trackPointerInfoStatistics(const IRPosition &IRP) const {}
14301435

14311436
/// Dump the state into \p O.
1432-
void dumpState(raw_ostream &O) {
1437+
virtual void dumpState(raw_ostream &O) const override {
14331438
for (auto &It : OffsetBins) {
14341439
O << "[" << It.first.Offset << "-" << It.first.Offset + It.first.Size
14351440
<< "] : " << It.getSecond().size() << "\n";
@@ -6975,10 +6980,9 @@ ChangeStatus AAHeapToStackFunction::updateImpl(Attributor &A) {
69756980
if (AI.LibraryFunctionId != LibFunc___kmpc_alloc_shared) {
69766981
Instruction *CtxI = isa<InvokeInst>(AI.CB) ? AI.CB : AI.CB->getNextNode();
69776982
if (!Explorer || !Explorer->findInContextOf(UniqueFree, CtxI)) {
6978-
LLVM_DEBUG(
6979-
dbgs()
6980-
<< "[H2S] unique free call might not be executed with the allocation "
6981-
<< *UniqueFree << "\n");
6983+
LLVM_DEBUG(dbgs() << "[H2S] unique free call might not be executed "
6984+
"with the allocation "
6985+
<< *UniqueFree << "\n");
69826986
return false;
69836987
}
69846988
}
@@ -10431,11 +10435,12 @@ struct AANoFPClassFloating : public AANoFPClassImpl {
1043110435

1043210436
struct AANoFPClassReturned final
1043310437
: AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10434-
AANoFPClassImpl::StateType, false, Attribute::None, false> {
10438+
AANoFPClassImpl::StateType, false,
10439+
Attribute::None, false> {
1043510440
AANoFPClassReturned(const IRPosition &IRP, Attributor &A)
1043610441
: AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10437-
AANoFPClassImpl::StateType, false, Attribute::None, false>(
10438-
IRP, A) {}
10442+
AANoFPClassImpl::StateType, false,
10443+
Attribute::None, false>(IRP, A) {}
1043910444

1044010445
/// See AbstractAttribute::trackStatistics()
1044110446
void trackStatistics() const override {
@@ -12692,6 +12697,11 @@ struct AAAllocationInfoImpl : public AAAllocationInfo {
1269212697
return AssumedAllocatedSize;
1269312698
}
1269412699

12700+
const NewOffsetsTy &getNewOffsets() const override {
12701+
assert(isValidState() && "the AA is invalid");
12702+
return NewComputedOffsets;
12703+
}
12704+
1269512705
std::optional<TypeSize> findInitialAllocationSize(Instruction *I,
1269612706
const DataLayout &DL) {
1269712707

@@ -12741,37 +12751,42 @@ struct AAAllocationInfoImpl : public AAAllocationInfo {
1274112751
if (*AllocationSize == 0)
1274212752
return indicatePessimisticFixpoint();
1274312753

12744-
int64_t BinSize = PI->numOffsetBins();
12745-
12746-
// TODO: implement for multiple bins
12747-
if (BinSize > 1)
12748-
return indicatePessimisticFixpoint();
12754+
int64_t NumBins = PI->numOffsetBins();
1274912755

12750-
if (BinSize == 0) {
12756+
if (NumBins == 0) {
1275112757
auto NewAllocationSize = std::optional<TypeSize>(TypeSize(0, false));
1275212758
if (!changeAllocationSize(NewAllocationSize))
1275312759
return ChangeStatus::UNCHANGED;
1275412760
return ChangeStatus::CHANGED;
1275512761
}
1275612762

12757-
// TODO: refactor this to be part of multiple bin case
12758-
const auto &It = PI->begin();
12763+
// For each access bin
12764+
// Compute its new start Offset and store the results in a new map
12765+
// (NewOffsetBins).
12766+
int64_t PrevBinEndOffset = 0;
12767+
bool ChangedOffsets = false;
12768+
for (AAPointerInfo::OffsetBinsTy::const_iterator It = PI->begin();
12769+
It != PI->end(); It++) {
12770+
const AA::RangeTy &OldRange = It->getFirst();
12771+
int64_t NewStartOffset = PrevBinEndOffset;
12772+
int64_t NewEndOffset = NewStartOffset + OldRange.Size;
12773+
PrevBinEndOffset = NewEndOffset;
1275912774

12760-
// TODO: handle if Offset is not zero
12761-
if (It->first.Offset != 0)
12762-
return indicatePessimisticFixpoint();
12763-
12764-
uint64_t SizeOfBin = It->first.Offset + It->first.Size;
12765-
12766-
if (SizeOfBin >= *AllocationSize)
12767-
return indicatePessimisticFixpoint();
12775+
ChangedOffsets |= setNewOffsets(OldRange, OldRange.Offset, NewStartOffset,
12776+
OldRange.Size);
12777+
}
1276812778

12779+
// Set the new size of the allocation, the new size of the Allocation should
12780+
// be the size of NewEndOffset * 8, in bits.
1276912781
auto NewAllocationSize =
12770-
std::optional<TypeSize>(TypeSize(SizeOfBin * 8, false));
12782+
std::optional<TypeSize>(TypeSize(PrevBinEndOffset * 8, false));
1277112783

1277212784
if (!changeAllocationSize(NewAllocationSize))
1277312785
return ChangeStatus::UNCHANGED;
1277412786

12787+
if (!ChangedOffsets)
12788+
return ChangeStatus::UNCHANGED;
12789+
1277512790
return ChangeStatus::CHANGED;
1277612791
}
1277712792

@@ -12781,12 +12796,13 @@ struct AAAllocationInfoImpl : public AAAllocationInfo {
1278112796
assert(isValidState() &&
1278212797
"Manifest should only be called if the state is valid.");
1278312798

12784-
Instruction *I = getIRPosition().getCtxI();
12799+
bool Changed = false;
12800+
const IRPosition &IRP = getIRPosition();
12801+
Instruction *I = IRP.getCtxI();
1278512802

1278612803
auto FixedAllocatedSizeInBits = getAllocatedSize()->getFixedValue();
1278712804

12788-
unsigned long NumBytesToAllocate = (FixedAllocatedSizeInBits + 7) / 8;
12789-
12805+
long NumBytesToAllocate = (FixedAllocatedSizeInBits + 7) / 8;
1279012806
switch (I->getOpcode()) {
1279112807
// TODO: add case for malloc like calls
1279212808
case Instruction::Alloca: {
@@ -12795,25 +12811,100 @@ struct AAAllocationInfoImpl : public AAAllocationInfo {
1279512811

1279612812
Type *CharType = Type::getInt8Ty(I->getContext());
1279712813

12798-
auto *NumBytesToValue =
12799-
ConstantInt::get(I->getContext(), APInt(32, NumBytesToAllocate));
12814+
Type *CharArrayType = ArrayType::get(CharType, NumBytesToAllocate);
1280012815

1280112816
BasicBlock::iterator insertPt = AI->getIterator();
1280212817
insertPt = std::next(insertPt);
12803-
AllocaInst *NewAllocaInst =
12804-
new AllocaInst(CharType, AI->getAddressSpace(), NumBytesToValue,
12805-
AI->getAlign(), AI->getName(), insertPt);
12806-
12807-
if (A.changeAfterManifest(IRPosition::inst(*AI), *NewAllocaInst))
12808-
return ChangeStatus::CHANGED;
12818+
AllocaInst *NewAllocaInst = new AllocaInst(
12819+
CharArrayType, AI->getAddressSpace(), AI->getName(), insertPt);
1280912820

12821+
Changed |= A.changeAfterManifest(IRPosition::inst(*AI), *NewAllocaInst);
1281012822
break;
1281112823
}
1281212824
default:
1281312825
break;
1281412826
}
1281512827

12816-
return ChangeStatus::UNCHANGED;
12828+
const AAPointerInfo *PI =
12829+
A.getOrCreateAAFor<AAPointerInfo>(IRP, *this, DepClassTy::REQUIRED);
12830+
12831+
if (!PI)
12832+
return ChangeStatus::UNCHANGED;
12833+
12834+
if (!PI->getState().isValidState())
12835+
return ChangeStatus::UNCHANGED;
12836+
12837+
const auto &NewOffsetsMap = getNewOffsets();
12838+
for (AAPointerInfo::OffsetBinsTy::const_iterator It = PI->begin();
12839+
It != PI->end(); It++) {
12840+
12841+
const auto &OldOffsetRange = It->getFirst();
12842+
12843+
// If the OldOffsetRange is not in the map, offsets for that bin did not
12844+
// change We should just continue and skip changing the offsets in that
12845+
// case
12846+
if (!NewOffsetsMap.contains(OldOffsetRange))
12847+
continue;
12848+
12849+
const auto &NewOffsetRange = NewOffsetsMap.lookup(OldOffsetRange);
12850+
int64_t ShiftValue = NewOffsetRange.Offset - OldOffsetRange.Offset;
12851+
for (const auto AccIndex : It->getSecond()) {
12852+
12853+
const auto &AccessInstruction = PI->getBinAccess(AccIndex);
12854+
auto *LocalInst = AccessInstruction.getLocalInst();
12855+
12856+
switch (LocalInst->getOpcode()) {
12857+
case Instruction::Load: {
12858+
LoadInst *OldLoadInst = cast<LoadInst>(LocalInst);
12859+
Value *PointerOperand = OldLoadInst->getPointerOperand();
12860+
Type *PointeeTy = OldLoadInst->getPointerOperandType();
12861+
12862+
IntegerType *Int64TyInteger =
12863+
IntegerType::get(LocalInst->getContext(), 64);
12864+
12865+
Value *IndexList[1] = {ConstantInt::get(Int64TyInteger, ShiftValue)};
12866+
Value *GepToNewAddress = GetElementPtrInst::Create(
12867+
PointeeTy, PointerOperand, IndexList, "NewGep", OldLoadInst);
12868+
12869+
LoadInst *NewLoadInst = new LoadInst(
12870+
OldLoadInst->getType(), GepToNewAddress, OldLoadInst->getName(),
12871+
false, OldLoadInst->getAlign(), OldLoadInst);
12872+
12873+
Changed |= A.changeAfterManifest(IRPosition::inst(*OldLoadInst),
12874+
*NewLoadInst);
12875+
12876+
A.deleteAfterManifest(*OldLoadInst);
12877+
break;
12878+
}
12879+
case Instruction::Store: {
12880+
StoreInst *OldStoreInst = cast<StoreInst>(LocalInst);
12881+
Value *PointerOperand = OldStoreInst->getPointerOperand();
12882+
Type *PointeeTy = OldStoreInst->getPointerOperandType();
12883+
12884+
IntegerType *Int64TyInteger =
12885+
IntegerType::get(LocalInst->getContext(), 64);
12886+
12887+
Value *IndexList[1] = {ConstantInt::get(Int64TyInteger, ShiftValue)};
12888+
Value *GepToNewAddress = GetElementPtrInst::Create(
12889+
PointeeTy, PointerOperand, IndexList, "NewGep", OldStoreInst);
12890+
12891+
StoreInst *NewStoreInst =
12892+
new StoreInst(OldStoreInst->getValueOperand(), GepToNewAddress,
12893+
false, OldStoreInst->getAlign(), OldStoreInst);
12894+
12895+
Changed |= A.changeAfterManifest(IRPosition::inst(*OldStoreInst),
12896+
*NewStoreInst);
12897+
12898+
A.deleteAfterManifest(*OldStoreInst);
12899+
break;
12900+
}
12901+
}
12902+
}
12903+
}
12904+
12905+
if (!Changed)
12906+
return ChangeStatus::UNCHANGED;
12907+
return ChangeStatus::CHANGED;
1281712908
}
1281812909

1281912910
/// See AbstractAttribute::getAsStr().
@@ -12827,8 +12918,28 @@ struct AAAllocationInfoImpl : public AAAllocationInfo {
1282712918
")";
1282812919
}
1282912920

12921+
void dumpNewOffsetBins(raw_ostream &O) {
12922+
12923+
O << "Printing Map from [OldOffsetsRange] : [NewOffsetsRange] if the "
12924+
"offsets changed."
12925+
<< "\n";
12926+
const auto &NewOffsetsMap = getNewOffsets();
12927+
for (auto It = NewOffsetsMap.begin(); It != NewOffsetsMap.end(); It++) {
12928+
12929+
const auto &OldRange = It->getFirst();
12930+
const auto &NewRange = It->getSecond();
12931+
12932+
O << "[" << OldRange.Offset << "," << OldRange.Offset + OldRange.Size
12933+
<< "] : ";
12934+
O << "[" << NewRange.Offset << "," << NewRange.Offset + NewRange.Size
12935+
<< "]";
12936+
O << "\n";
12937+
}
12938+
}
12939+
1283012940
private:
1283112941
std::optional<TypeSize> AssumedAllocatedSize = HasNoAllocationSize;
12942+
NewOffsetsTy NewComputedOffsets;
1283212943

1283312944
// Maintain the computed allocation size of the object.
1283412945
// Returns (bool) weather the size of the allocation was modified or not.
@@ -12840,6 +12951,21 @@ struct AAAllocationInfoImpl : public AAAllocationInfo {
1284012951
}
1284112952
return false;
1284212953
}
12954+
12955+
// Maps an old byte range to its new Offset range in the new allocation.
12956+
// Returns (bool) weather the old byte range's offsets changed or not.
12957+
bool setNewOffsets(const AA::RangeTy &OldRange, int64_t OldOffset,
12958+
int64_t NewComputedOffset, int64_t Size) {
12959+
12960+
if (OldOffset == NewComputedOffset)
12961+
return false;
12962+
12963+
AA::RangeTy &NewRange = NewComputedOffsets.getOrInsertDefault(OldRange);
12964+
NewRange.Offset = NewComputedOffset;
12965+
NewRange.Size = Size;
12966+
12967+
return true;
12968+
}
1284312969
};
1284412970

1284512971
struct AAAllocationInfoFloating : AAAllocationInfoImpl {

llvm/test/Other/ChangePrinters/DotCfg/print-changed-dot-cfg.ll

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
12
; Simple checks of -print-changed=dot-cfg
23
;
34
; Note that (mostly) only the banners are checked.
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
12
# REQUIRES: x86-registered-target
23
# Simple functionality check.
34
# RUN: rm -rf %t && mkdir -p %t
@@ -8,17 +9,17 @@
89
name: g
910
body: |
1011
bb.0.entry:
11-
%0:gr32 = MOV32ri 5
12-
$eax = COPY %0
13-
RET 0, $eax
12+
%0:gr32 = MOV32ri 5
13+
$eax = COPY %0
14+
RET 0, $eax
1415
1516
...
1617
---
1718
name: f
1819
body: |
1920
bb.0.entry:
20-
%0:gr32 = MOV32ri 7
21-
$eax = COPY %0
22-
RET 0, $eax
21+
%0:gr32 = MOV32ri 7
22+
$eax = COPY %0
23+
RET 0, $eax
2324
2425
...

0 commit comments

Comments
 (0)