[llvm] [llvm] Fix __builtin_object_size interaction between Negative Offset … (PR #111827)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Oct 21 04:32:27 PDT 2024
https://github.com/serge-sans-paille updated https://github.com/llvm/llvm-project/pull/111827
>From ca870da938ce164f4e346dd2ff79b5838c9c18fa Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Thu, 10 Oct 2024 13:59:22 +0200
Subject: [PATCH] [llvm] Fix __builtin_object_size interaction between Negative
Offset and Select/Phi
When picking a SizeOffsetAPInt through combineSizeOffset, we sometime
have to choose between two arguments that have the same (Size - Offset)
value. In that case pick the one with the largest offset so that
negative indexing actually makes sense.
Fix #111709
---
llvm/lib/Analysis/MemoryBuiltins.cpp | 47 ++++-
.../builtin-object-size-phi.ll | 176 ++++++++++++++++++
2 files changed, 215 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp
index e1abf5e4d885ec..bb9bd23534be59 100644
--- a/llvm/lib/Analysis/MemoryBuiltins.cpp
+++ b/llvm/lib/Analysis/MemoryBuiltins.cpp
@@ -982,17 +982,48 @@ ObjectSizeOffsetVisitor::combineSizeOffset(SizeOffsetAPInt LHS,
if (!LHS.bothKnown() || !RHS.bothKnown())
return ObjectSizeOffsetVisitor::unknown();
+ // When combining SizeOffset of the same size, instead of a draw, we pick the
+ // one with the largest offset, in case of further indexing with negative
+ // offset.
switch (Options.EvalMode) {
- case ObjectSizeOpts::Mode::Min:
- return (getSizeWithOverflow(LHS).slt(getSizeWithOverflow(RHS))) ? LHS : RHS;
- case ObjectSizeOpts::Mode::Max:
- return (getSizeWithOverflow(LHS).sgt(getSizeWithOverflow(RHS))) ? LHS : RHS;
+ case ObjectSizeOpts::Mode::Min: {
+ APInt LHSSize = getSizeWithOverflow(LHS),
+ RHSSize = getSizeWithOverflow(RHS);
+ if (LHSSize.slt(RHSSize)) {
+ return LHS;
+ } else if (LHSSize.sgt(RHSSize)) {
+ return RHS;
+ } else if (LHS.Offset.ugt(RHS.Offset)) {
+ return LHS;
+ } else {
+ return RHS;
+ }
+ }
+ case ObjectSizeOpts::Mode::Max: {
+ APInt LHSSize = getSizeWithOverflow(LHS),
+ RHSSize = getSizeWithOverflow(RHS);
+ if (LHSSize.sgt(RHSSize)) {
+ return LHS;
+ } else if (LHSSize.slt(RHSSize)) {
+ return RHS;
+ } else if (LHS.Offset.ugt(RHS.Offset)) {
+ return LHS;
+ } else {
+ return RHS;
+ }
+ }
case ObjectSizeOpts::Mode::ExactSizeFromOffset:
- return (getSizeWithOverflow(LHS).eq(getSizeWithOverflow(RHS)))
- ? LHS
- : ObjectSizeOffsetVisitor::unknown();
+ if (getSizeWithOverflow(LHS).eq(getSizeWithOverflow(RHS))) {
+ return LHS.Offset.ugt(RHS.Offset) ? LHS : RHS;
+ } else {
+ return ObjectSizeOffsetVisitor::unknown();
+ }
case ObjectSizeOpts::Mode::ExactUnderlyingSizeAndOffset:
- return LHS == RHS ? LHS : ObjectSizeOffsetVisitor::unknown();
+ if (LHS == RHS) {
+ return LHS.Offset.ugt(RHS.Offset) ? LHS : RHS;
+ } else {
+ return ObjectSizeOffsetVisitor::unknown();
+ }
}
llvm_unreachable("missing an eval mode");
}
diff --git a/llvm/test/Transforms/LowerConstantIntrinsics/builtin-object-size-phi.ll b/llvm/test/Transforms/LowerConstantIntrinsics/builtin-object-size-phi.ll
index 4f4d6a88e1693b..126d81d0e04d7d 100644
--- a/llvm/test/Transforms/LowerConstantIntrinsics/builtin-object-size-phi.ll
+++ b/llvm/test/Transforms/LowerConstantIntrinsics/builtin-object-size-phi.ll
@@ -117,3 +117,179 @@ if.end:
%size = call i64 @llvm.objectsize.i64.p0(ptr %p, i1 true, i1 true, i1 false)
ret i64 %size
}
+
+define i64 @pick_negative_offset(i32 %n) {
+; CHECK-LABEL: @pick_negative_offset(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[BUFFER0:%.*]] = alloca i8, i64 20, align 1
+; CHECK-NEXT: [[OFFSETED0:%.*]] = getelementptr i8, ptr [[BUFFER0]], i64 20
+; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[N:%.*]], 0
+; CHECK-NEXT: br i1 [[COND]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: [[BUFFER1:%.*]] = alloca i8, i64 20, align 1
+; CHECK-NEXT: [[OFFSETED1:%.*]] = getelementptr i8, ptr [[BUFFER1]], i64 20
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[OFFSETED1]], [[IF_ELSE]] ], [ [[OFFSETED0]], [[ENTRY:%.*]] ]
+; CHECK-NEXT: [[POFFSETED:%.*]] = getelementptr i8, ptr [[P]], i64 -4
+; CHECK-NEXT: ret i64 4
+;
+entry:
+ %buffer0 = alloca i8, i64 20
+ %offseted0 = getelementptr i8, ptr %buffer0, i64 20
+ %cond = icmp eq i32 %n, 0
+ br i1 %cond, label %if.else, label %if.end
+
+if.else:
+ %buffer1 = alloca i8, i64 20
+ %offseted1 = getelementptr i8, ptr %buffer1, i64 20
+ br label %if.end
+
+if.end:
+ %p = phi ptr [ %offseted1, %if.else ], [ %offseted0, %entry ]
+ %poffseted = getelementptr i8, ptr %p, i64 -4
+ %size = call i64 @llvm.objectsize.i64.p0(ptr %poffseted, i1 false, i1 false, i1 false)
+ ret i64 %size
+}
+
+define i64 @pick_negative_offset_with_nullptr(i32 %n) {
+; CHECK-LABEL: @pick_negative_offset_with_nullptr(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[BUFFER0:%.*]] = alloca i8, i64 20, align 1
+; CHECK-NEXT: [[OFFSETED0:%.*]] = getelementptr i8, ptr [[BUFFER0]], i64 20
+; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[N:%.*]], 0
+; CHECK-NEXT: br i1 [[COND]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[P0:%.*]] = phi ptr [ [[OFFSETED0]], [[ENTRY:%.*]] ], [ null, [[IF_ELSE]] ]
+; CHECK-NEXT: [[P1:%.*]] = phi ptr [ null, [[IF_ELSE]] ], [ [[OFFSETED0]], [[ENTRY]] ]
+; CHECK-NEXT: [[P0OFFSETED:%.*]] = getelementptr i8, ptr [[P0]], i64 -4
+; CHECK-NEXT: [[P1OFFSETED:%.*]] = getelementptr i8, ptr [[P1]], i64 -4
+; CHECK-NEXT: ret i64 4
+;
+entry:
+ %buffer0 = alloca i8, i64 20
+ %offseted0 = getelementptr i8, ptr %buffer0, i64 20
+ %cond = icmp eq i32 %n, 0
+ br i1 %cond, label %if.else, label %if.end
+
+if.else:
+ br label %if.end
+
+if.end:
+ %p0 = phi ptr [ %offseted0, %entry ], [ null, %if.else ]
+ %p1 = phi ptr [ null, %if.else ], [ %offseted0, %entry ]
+ %p0offseted = getelementptr i8, ptr %p0, i64 -4
+ %p1offseted = getelementptr i8, ptr %p1, i64 -4
+ %size0 = call i64 @llvm.objectsize.i64.p0(ptr %p0offseted, i1 false, i1 false, i1 false)
+ %size1 = call i64 @llvm.objectsize.i64.p0(ptr %p1offseted, i1 false, i1 false, i1 false)
+ %size = select i1 %cond, i64 %size0, i64 %size1
+ ret i64 %size
+}
+
+define i64 @pick_negative_offset_with_unsized_nullptr(i32 %n) {
+; CHECK-LABEL: @pick_negative_offset_with_unsized_nullptr(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[BUFFER0:%.*]] = alloca i8, i64 20, align 1
+; CHECK-NEXT: [[OFFSETED0:%.*]] = getelementptr i8, ptr [[BUFFER0]], i64 20
+; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[N:%.*]], 0
+; CHECK-NEXT: br i1 [[COND]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[P0:%.*]] = phi ptr [ [[OFFSETED0]], [[ENTRY:%.*]] ], [ null, [[IF_ELSE]] ]
+; CHECK-NEXT: [[P1:%.*]] = phi ptr [ null, [[IF_ELSE]] ], [ [[OFFSETED0]], [[ENTRY]] ]
+; CHECK-NEXT: [[P0OFFSETED:%.*]] = getelementptr i8, ptr [[P0]], i64 -4
+; CHECK-NEXT: [[P1OFFSETED:%.*]] = getelementptr i8, ptr [[P1]], i64 -4
+; CHECK-NEXT: ret i64 -1
+;
+entry:
+ %buffer0 = alloca i8, i64 20
+ %offseted0 = getelementptr i8, ptr %buffer0, i64 20
+ %cond = icmp eq i32 %n, 0
+ br i1 %cond, label %if.else, label %if.end
+
+if.else:
+ br label %if.end
+
+if.end:
+ %p0 = phi ptr [ %offseted0, %entry ], [ null, %if.else ]
+ %p1 = phi ptr [ null, %if.else ], [ %offseted0, %entry ]
+ %p0offseted = getelementptr i8, ptr %p0, i64 -4
+ %p1offseted = getelementptr i8, ptr %p1, i64 -4
+ %size0 = call i64 @llvm.objectsize.i64.p0(ptr %p0offseted, i1 false, i1 true, i1 false)
+ %size1 = call i64 @llvm.objectsize.i64.p0(ptr %p1offseted, i1 false, i1 true, i1 false)
+ %size = select i1 %cond, i64 %size0, i64 %size1
+ ret i64 %size
+}
+
+define i64 @chain_pick_negative_offset_with_nullptr(i32 %x) {
+; CHECK-LABEL: @chain_pick_negative_offset_with_nullptr(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[ARRAY:%.*]] = alloca [4 x i32], align 4
+; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT: [[P:%.*]] = getelementptr i8, ptr [[ARRAY]], i64 8
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[C]], ptr [[P]], ptr null
+; CHECK-NEXT: [[P4:%.*]] = getelementptr i8, ptr [[COND]], i64 8
+; CHECK-NEXT: [[COND6:%.*]] = select i1 [[C]], ptr [[P4]], ptr null
+; CHECK-NEXT: [[P7:%.*]] = getelementptr i8, ptr [[COND6]], i64 -4
+; CHECK-NEXT: ret i64 4
+;
+entry:
+ %array = alloca [4 x i32]
+ %c = icmp eq i32 %x, 0
+ %p = getelementptr i8, ptr %array, i64 8
+ %cond = select i1 %c, ptr %p, ptr null
+ %p4 = getelementptr i8, ptr %cond, i64 8
+ %cond6 = select i1 %c, ptr %p4, ptr null
+ %p7 = getelementptr i8, ptr %cond6, i64 -4
+ %size = call i64 @llvm.objectsize.i64.p0(ptr %p7, i1 false, i1 false, i1 false)
+ ret i64 %size
+}
+
+
+define i64 @negative_offset_dynamic_eval(i32 %x, i64 %i) {
+; CHECK-LABEL: @negative_offset_dynamic_eval(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[ARRAY1:%.*]] = alloca [4 x i32], align 16
+; CHECK-NEXT: [[ARRAY2:%.*]] = alloca [8 x i32], align 16
+; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: br label [[IF_END:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, ptr [[ARRAY2]], i64 16
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[PTR:%.*]] = phi ptr [ [[ARRAY1]], [[IF_THEN]] ], [ [[ADD_PTR]], [[IF_ELSE]] ]
+; CHECK-NEXT: [[ADD_PTR2_IDX:%.*]] = mul i64 [[I:%.*]], 4
+; CHECK-NEXT: [[TMP0:%.*]] = add i64 16, [[ADD_PTR2_IDX]]
+; CHECK-NEXT: [[ADD_PTR2:%.*]] = getelementptr inbounds i32, ptr [[PTR]], i64 [[I]]
+; CHECK-NEXT: [[TMP1:%.*]] = sub i64 32, [[TMP0]]
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i64 32, [[TMP0]]
+; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i64 0, i64 [[TMP1]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i64 [[TMP3]], -1
+; CHECK-NEXT: call void @llvm.assume(i1 [[TMP4]])
+; CHECK-NEXT: ret i64 [[TMP3]]
+;
+entry:
+ %array1 = alloca [4 x i32], align 16
+ %array2 = alloca [8 x i32], align 16
+ %tobool.not = icmp eq i32 %x, 0
+ br i1 %tobool.not, label %if.else, label %if.then
+
+if.then:
+ br label %if.end
+
+if.else:
+ %add.ptr = getelementptr inbounds i8, ptr %array2, i64 16
+ br label %if.end
+
+if.end:
+ %ptr = phi ptr [ %array1, %if.then ], [ %add.ptr, %if.else ]
+ %add.ptr2 = getelementptr inbounds i32, ptr %ptr, i64 %i
+ %objsize = call i64 @llvm.objectsize.i64.p0(ptr %add.ptr2, i1 false, i1 true, i1 true)
+ ret i64 %objsize
+}
+
More information about the llvm-commits
mailing list