Skip to content

Commit da7e567

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 3df7cb9 commit da7e567

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

+1195
-835
lines changed

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

Lines changed: 8 additions & 9 deletions
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

Lines changed: 163 additions & 37 deletions
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";
@@ -6969,10 +6974,9 @@ ChangeStatus AAHeapToStackFunction::updateImpl(Attributor &A) {
69696974
if (AI.LibraryFunctionId != LibFunc___kmpc_alloc_shared) {
69706975
Instruction *CtxI = isa<InvokeInst>(AI.CB) ? AI.CB : AI.CB->getNextNode();
69716976
if (!Explorer || !Explorer->findInContextOf(UniqueFree, CtxI)) {
6972-
LLVM_DEBUG(
6973-
dbgs()
6974-
<< "[H2S] unique free call might not be executed with the allocation "
6975-
<< *UniqueFree << "\n");
6977+
LLVM_DEBUG(dbgs() << "[H2S] unique free call might not be executed "
6978+
"with the allocation "
6979+
<< *UniqueFree << "\n");
69766980
return false;
69776981
}
69786982
}
@@ -10425,11 +10429,12 @@ struct AANoFPClassFloating : public AANoFPClassImpl {
1042510429

1042610430
struct AANoFPClassReturned final
1042710431
: AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10428-
AANoFPClassImpl::StateType, false, Attribute::None, false> {
10432+
AANoFPClassImpl::StateType, false,
10433+
Attribute::None, false> {
1042910434
AANoFPClassReturned(const IRPosition &IRP, Attributor &A)
1043010435
: AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,
10431-
AANoFPClassImpl::StateType, false, Attribute::None, false>(
10432-
IRP, A) {}
10436+
AANoFPClassImpl::StateType, false,
10437+
Attribute::None, false>(IRP, A) {}
1043310438

1043410439
/// See AbstractAttribute::trackStatistics()
1043510440
void trackStatistics() const override {
@@ -12686,6 +12691,11 @@ struct AAAllocationInfoImpl : public AAAllocationInfo {
1268612691
return AssumedAllocatedSize;
1268712692
}
1268812693

12694+
const NewOffsetsTy &getNewOffsets() const override {
12695+
assert(isValidState() && "the AA is invalid");
12696+
return NewComputedOffsets;
12697+
}
12698+
1268912699
std::optional<TypeSize> findInitialAllocationSize(Instruction *I,
1269012700
const DataLayout &DL) {
1269112701

@@ -12735,37 +12745,42 @@ struct AAAllocationInfoImpl : public AAAllocationInfo {
1273512745
if (*AllocationSize == 0)
1273612746
return indicatePessimisticFixpoint();
1273712747

12738-
int64_t BinSize = PI->numOffsetBins();
12739-
12740-
// TODO: implement for multiple bins
12741-
if (BinSize > 1)
12742-
return indicatePessimisticFixpoint();
12748+
int64_t NumBins = PI->numOffsetBins();
1274312749

12744-
if (BinSize == 0) {
12750+
if (NumBins == 0) {
1274512751
auto NewAllocationSize = std::optional<TypeSize>(TypeSize(0, false));
1274612752
if (!changeAllocationSize(NewAllocationSize))
1274712753
return ChangeStatus::UNCHANGED;
1274812754
return ChangeStatus::CHANGED;
1274912755
}
1275012756

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

12754-
// TODO: handle if Offset is not zero
12755-
if (It->first.Offset != 0)
12756-
return indicatePessimisticFixpoint();
12757-
12758-
uint64_t SizeOfBin = It->first.Offset + It->first.Size;
12759-
12760-
if (SizeOfBin >= *AllocationSize)
12761-
return indicatePessimisticFixpoint();
12769+
ChangedOffsets |= setNewOffsets(OldRange, OldRange.Offset, NewStartOffset,
12770+
OldRange.Size);
12771+
}
1276212772

12773+
// Set the new size of the allocation, the new size of the Allocation should
12774+
// be the size of NewEndOffset * 8, in bits.
1276312775
auto NewAllocationSize =
12764-
std::optional<TypeSize>(TypeSize(SizeOfBin * 8, false));
12776+
std::optional<TypeSize>(TypeSize(PrevBinEndOffset * 8, false));
1276512777

1276612778
if (!changeAllocationSize(NewAllocationSize))
1276712779
return ChangeStatus::UNCHANGED;
1276812780

12781+
if (!ChangedOffsets)
12782+
return ChangeStatus::UNCHANGED;
12783+
1276912784
return ChangeStatus::CHANGED;
1277012785
}
1277112786

@@ -12775,12 +12790,13 @@ struct AAAllocationInfoImpl : public AAAllocationInfo {
1277512790
assert(isValidState() &&
1277612791
"Manifest should only be called if the state is valid.");
1277712792

12778-
Instruction *I = getIRPosition().getCtxI();
12793+
bool Changed = false;
12794+
const IRPosition &IRP = getIRPosition();
12795+
Instruction *I = IRP.getCtxI();
1277912796

1278012797
auto FixedAllocatedSizeInBits = getAllocatedSize()->getFixedValue();
1278112798

1278212799
unsigned long NumBytesToAllocate = (FixedAllocatedSizeInBits + 7) / 8;
12783-
1278412800
switch (I->getOpcode()) {
1278512801
// TODO: add case for malloc like calls
1278612802
case Instruction::Alloca: {
@@ -12789,25 +12805,100 @@ struct AAAllocationInfoImpl : public AAAllocationInfo {
1278912805

1279012806
Type *CharType = Type::getInt8Ty(I->getContext());
1279112807

12792-
auto *NumBytesToValue =
12793-
ConstantInt::get(I->getContext(), APInt(32, NumBytesToAllocate));
12808+
Type *CharArrayType = ArrayType::get(CharType, NumBytesToAllocate);
1279412809

1279512810
BasicBlock::iterator insertPt = AI->getIterator();
1279612811
insertPt = std::next(insertPt);
12797-
AllocaInst *NewAllocaInst =
12798-
new AllocaInst(CharType, AI->getAddressSpace(), NumBytesToValue,
12799-
AI->getAlign(), AI->getName(), insertPt);
12800-
12801-
if (A.changeAfterManifest(IRPosition::inst(*AI), *NewAllocaInst))
12802-
return ChangeStatus::CHANGED;
12812+
AllocaInst *NewAllocaInst = new AllocaInst(
12813+
CharArrayType, AI->getAddressSpace(), AI->getName(), insertPt);
1280312814

12815+
Changed |= A.changeAfterManifest(IRPosition::inst(*AI), *NewAllocaInst);
1280412816
break;
1280512817
}
1280612818
default:
1280712819
break;
1280812820
}
1280912821

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

1281312904
/// See AbstractAttribute::getAsStr().
@@ -12821,8 +12912,28 @@ struct AAAllocationInfoImpl : public AAAllocationInfo {
1282112912
")";
1282212913
}
1282312914

12915+
void dumpNewOffsetBins(raw_ostream &O) {
12916+
12917+
O << "Printing Map from [OldOffsetsRange] : [NewOffsetsRange] if the "
12918+
"offsets changed."
12919+
<< "\n";
12920+
const auto &NewOffsetsMap = getNewOffsets();
12921+
for (auto It = NewOffsetsMap.begin(); It != NewOffsetsMap.end(); It++) {
12922+
12923+
const auto &OldRange = It->getFirst();
12924+
const auto &NewRange = It->getSecond();
12925+
12926+
O << "[" << OldRange.Offset << "," << OldRange.Offset + OldRange.Size
12927+
<< "] : ";
12928+
O << "[" << NewRange.Offset << "," << NewRange.Offset + NewRange.Size
12929+
<< "]";
12930+
O << "\n";
12931+
}
12932+
}
12933+
1282412934
private:
1282512935
std::optional<TypeSize> AssumedAllocatedSize = HasNoAllocationSize;
12936+
NewOffsetsTy NewComputedOffsets;
1282612937

1282712938
// Maintain the computed allocation size of the object.
1282812939
// Returns (bool) weather the size of the allocation was modified or not.
@@ -12834,6 +12945,21 @@ struct AAAllocationInfoImpl : public AAAllocationInfo {
1283412945
}
1283512946
return false;
1283612947
}
12948+
12949+
// Maps an old byte range to its new Offset range in the new allocation.
12950+
// Returns (bool) weather the old byte range's offsets changed or not.
12951+
bool setNewOffsets(const AA::RangeTy &OldRange, int64_t OldOffset,
12952+
int64_t NewComputedOffset, int64_t Size) {
12953+
12954+
if (OldOffset == NewComputedOffset)
12955+
return false;
12956+
12957+
AA::RangeTy &NewRange = NewComputedOffsets.getOrInsertDefault(OldRange);
12958+
NewRange.Offset = NewComputedOffset;
12959+
NewRange.Size = Size;
12960+
12961+
return true;
12962+
}
1283712963
};
1283812964

1283912965
struct AAAllocationInfoFloating : AAAllocationInfoImpl {

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

Lines changed: 1 addition & 0 deletions
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.
Lines changed: 7 additions & 6 deletions
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)