Skip to content

Commit 0e49da7

Browse files
[llvm] Fix __builtin_object_size interaction between Negative Offset and Select/Phi
Change ObjectSizeOffsetVisitor internal data structure to represent the allocated memory space from (size, offset) to (before, after), i.e. memory available before and after the considered point. This is an internal change that doesn't impact current interface that still returns (Size, Offset), as we can switch between one representation to another, but when picking the Span before/after representation, we can make more fine-grain decision when computing max/min. Also change ObjectSizeOffsetEvaluator to always call ObjectSizeOffsetVisitor in Mode::ExactUnderlyingSizeAndOffset to correctly handle negative dynamic offset that are incompatible with Mode::ExactSizeFromOffset. Fix #111709 (and the many test cases which appeared in that thread).
1 parent ed6ddff commit 0e49da7

File tree

4 files changed

+405
-89
lines changed

4 files changed

+405
-89
lines changed

llvm/include/llvm/Analysis/MemoryBuiltins.h

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -221,21 +221,43 @@ struct SizeOffsetAPInt : public SizeOffsetType<APInt, SizeOffsetAPInt> {
221221
static bool known(const APInt &V) { return V.getBitWidth() > 1; }
222222
};
223223

224+
/// OffsetSpan - Used internally by \p ObjectSizeOffsetVisitor. Represents a
225+
/// point in memory as a pair of allocated bytes before and after it.
226+
struct OffsetSpan {
227+
APInt Before; /// Number of allocated bytes before this point.
228+
APInt After; /// Number of allocated bytes after this point.
229+
230+
OffsetSpan() = default;
231+
OffsetSpan(APInt Before, APInt After) : Before(Before), After(After) {}
232+
233+
bool knownBefore() const { return known(Before); }
234+
bool knownAfter() const { return known(After); }
235+
bool anyKnown() const { return knownBefore() || knownAfter(); }
236+
bool bothKnown() const { return knownBefore() && knownAfter(); }
237+
238+
bool operator==(const OffsetSpan &RHS) const {
239+
return Before == RHS.Before && After == RHS.After;
240+
}
241+
bool operator!=(const OffsetSpan &RHS) const { return !(*this == RHS); }
242+
243+
static bool known(const APInt &V) { return V.getBitWidth() > 1; }
244+
};
245+
224246
/// Evaluate the size and offset of an object pointed to by a Value*
225247
/// statically. Fails if size or offset are not known at compile time.
226248
class ObjectSizeOffsetVisitor
227-
: public InstVisitor<ObjectSizeOffsetVisitor, SizeOffsetAPInt> {
249+
: public InstVisitor<ObjectSizeOffsetVisitor, OffsetSpan> {
228250
const DataLayout &DL;
229251
const TargetLibraryInfo *TLI;
230252
ObjectSizeOpts Options;
231253
unsigned IntTyBits;
232254
APInt Zero;
233-
SmallDenseMap<Instruction *, SizeOffsetAPInt, 8> SeenInsts;
255+
SmallDenseMap<Instruction *, OffsetSpan, 8> SeenInsts;
234256
unsigned InstructionsVisited;
235257

236258
APInt align(APInt Size, MaybeAlign Align);
237259

238-
static SizeOffsetAPInt unknown() { return SizeOffsetAPInt(); }
260+
static OffsetSpan unknown() { return OffsetSpan(); }
239261

240262
public:
241263
ObjectSizeOffsetVisitor(const DataLayout &DL, const TargetLibraryInfo *TLI,
@@ -245,29 +267,30 @@ class ObjectSizeOffsetVisitor
245267

246268
// These are "private", except they can't actually be made private. Only
247269
// compute() should be used by external users.
248-
SizeOffsetAPInt visitAllocaInst(AllocaInst &I);
249-
SizeOffsetAPInt visitArgument(Argument &A);
250-
SizeOffsetAPInt visitCallBase(CallBase &CB);
251-
SizeOffsetAPInt visitConstantPointerNull(ConstantPointerNull &);
252-
SizeOffsetAPInt visitExtractElementInst(ExtractElementInst &I);
253-
SizeOffsetAPInt visitExtractValueInst(ExtractValueInst &I);
254-
SizeOffsetAPInt visitGlobalAlias(GlobalAlias &GA);
255-
SizeOffsetAPInt visitGlobalVariable(GlobalVariable &GV);
256-
SizeOffsetAPInt visitIntToPtrInst(IntToPtrInst &);
257-
SizeOffsetAPInt visitLoadInst(LoadInst &I);
258-
SizeOffsetAPInt visitPHINode(PHINode &);
259-
SizeOffsetAPInt visitSelectInst(SelectInst &I);
260-
SizeOffsetAPInt visitUndefValue(UndefValue &);
261-
SizeOffsetAPInt visitInstruction(Instruction &I);
270+
OffsetSpan visitAllocaInst(AllocaInst &I);
271+
OffsetSpan visitArgument(Argument &A);
272+
OffsetSpan visitCallBase(CallBase &CB);
273+
OffsetSpan visitConstantPointerNull(ConstantPointerNull &);
274+
OffsetSpan visitExtractElementInst(ExtractElementInst &I);
275+
OffsetSpan visitExtractValueInst(ExtractValueInst &I);
276+
OffsetSpan visitGlobalAlias(GlobalAlias &GA);
277+
OffsetSpan visitGlobalVariable(GlobalVariable &GV);
278+
OffsetSpan visitIntToPtrInst(IntToPtrInst &);
279+
OffsetSpan visitLoadInst(LoadInst &I);
280+
OffsetSpan visitPHINode(PHINode &);
281+
OffsetSpan visitSelectInst(SelectInst &I);
282+
OffsetSpan visitUndefValue(UndefValue &);
283+
OffsetSpan visitInstruction(Instruction &I);
262284

263285
private:
264-
SizeOffsetAPInt findLoadSizeOffset(
265-
LoadInst &LoadFrom, BasicBlock &BB, BasicBlock::iterator From,
266-
SmallDenseMap<BasicBlock *, SizeOffsetAPInt, 8> &VisitedBlocks,
267-
unsigned &ScannedInstCount);
268-
SizeOffsetAPInt combineSizeOffset(SizeOffsetAPInt LHS, SizeOffsetAPInt RHS);
269-
SizeOffsetAPInt computeImpl(Value *V);
270-
SizeOffsetAPInt computeValue(Value *V);
286+
OffsetSpan
287+
findLoadOffsetRange(LoadInst &LoadFrom, BasicBlock &BB,
288+
BasicBlock::iterator From,
289+
SmallDenseMap<BasicBlock *, OffsetSpan, 8> &VisitedBlocks,
290+
unsigned &ScannedInstCount);
291+
OffsetSpan combineOffsetRange(OffsetSpan LHS, OffsetSpan RHS);
292+
OffsetSpan computeImpl(Value *V);
293+
OffsetSpan computeValue(Value *V);
271294
bool CheckedZextOrTrunc(APInt &I);
272295
};
273296

0 commit comments

Comments
 (0)