Skip to content

Commit ca870da

Browse files
[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
1 parent 6af2f22 commit ca870da

File tree

2 files changed

+215
-8
lines changed

2 files changed

+215
-8
lines changed

llvm/lib/Analysis/MemoryBuiltins.cpp

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -982,17 +982,48 @@ ObjectSizeOffsetVisitor::combineSizeOffset(SizeOffsetAPInt LHS,
982982
if (!LHS.bothKnown() || !RHS.bothKnown())
983983
return ObjectSizeOffsetVisitor::unknown();
984984

985+
// When combining SizeOffset of the same size, instead of a draw, we pick the
986+
// one with the largest offset, in case of further indexing with negative
987+
// offset.
985988
switch (Options.EvalMode) {
986-
case ObjectSizeOpts::Mode::Min:
987-
return (getSizeWithOverflow(LHS).slt(getSizeWithOverflow(RHS))) ? LHS : RHS;
988-
case ObjectSizeOpts::Mode::Max:
989-
return (getSizeWithOverflow(LHS).sgt(getSizeWithOverflow(RHS))) ? LHS : RHS;
989+
case ObjectSizeOpts::Mode::Min: {
990+
APInt LHSSize = getSizeWithOverflow(LHS),
991+
RHSSize = getSizeWithOverflow(RHS);
992+
if (LHSSize.slt(RHSSize)) {
993+
return LHS;
994+
} else if (LHSSize.sgt(RHSSize)) {
995+
return RHS;
996+
} else if (LHS.Offset.ugt(RHS.Offset)) {
997+
return LHS;
998+
} else {
999+
return RHS;
1000+
}
1001+
}
1002+
case ObjectSizeOpts::Mode::Max: {
1003+
APInt LHSSize = getSizeWithOverflow(LHS),
1004+
RHSSize = getSizeWithOverflow(RHS);
1005+
if (LHSSize.sgt(RHSSize)) {
1006+
return LHS;
1007+
} else if (LHSSize.slt(RHSSize)) {
1008+
return RHS;
1009+
} else if (LHS.Offset.ugt(RHS.Offset)) {
1010+
return LHS;
1011+
} else {
1012+
return RHS;
1013+
}
1014+
}
9901015
case ObjectSizeOpts::Mode::ExactSizeFromOffset:
991-
return (getSizeWithOverflow(LHS).eq(getSizeWithOverflow(RHS)))
992-
? LHS
993-
: ObjectSizeOffsetVisitor::unknown();
1016+
if (getSizeWithOverflow(LHS).eq(getSizeWithOverflow(RHS))) {
1017+
return LHS.Offset.ugt(RHS.Offset) ? LHS : RHS;
1018+
} else {
1019+
return ObjectSizeOffsetVisitor::unknown();
1020+
}
9941021
case ObjectSizeOpts::Mode::ExactUnderlyingSizeAndOffset:
995-
return LHS == RHS ? LHS : ObjectSizeOffsetVisitor::unknown();
1022+
if (LHS == RHS) {
1023+
return LHS.Offset.ugt(RHS.Offset) ? LHS : RHS;
1024+
} else {
1025+
return ObjectSizeOffsetVisitor::unknown();
1026+
}
9961027
}
9971028
llvm_unreachable("missing an eval mode");
9981029
}

llvm/test/Transforms/LowerConstantIntrinsics/builtin-object-size-phi.ll

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,179 @@ if.end:
117117
%size = call i64 @llvm.objectsize.i64.p0(ptr %p, i1 true, i1 true, i1 false)
118118
ret i64 %size
119119
}
120+
121+
define i64 @pick_negative_offset(i32 %n) {
122+
; CHECK-LABEL: @pick_negative_offset(
123+
; CHECK-NEXT: entry:
124+
; CHECK-NEXT: [[BUFFER0:%.*]] = alloca i8, i64 20, align 1
125+
; CHECK-NEXT: [[OFFSETED0:%.*]] = getelementptr i8, ptr [[BUFFER0]], i64 20
126+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[N:%.*]], 0
127+
; CHECK-NEXT: br i1 [[COND]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
128+
; CHECK: if.else:
129+
; CHECK-NEXT: [[BUFFER1:%.*]] = alloca i8, i64 20, align 1
130+
; CHECK-NEXT: [[OFFSETED1:%.*]] = getelementptr i8, ptr [[BUFFER1]], i64 20
131+
; CHECK-NEXT: br label [[IF_END]]
132+
; CHECK: if.end:
133+
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[OFFSETED1]], [[IF_ELSE]] ], [ [[OFFSETED0]], [[ENTRY:%.*]] ]
134+
; CHECK-NEXT: [[POFFSETED:%.*]] = getelementptr i8, ptr [[P]], i64 -4
135+
; CHECK-NEXT: ret i64 4
136+
;
137+
entry:
138+
%buffer0 = alloca i8, i64 20
139+
%offseted0 = getelementptr i8, ptr %buffer0, i64 20
140+
%cond = icmp eq i32 %n, 0
141+
br i1 %cond, label %if.else, label %if.end
142+
143+
if.else:
144+
%buffer1 = alloca i8, i64 20
145+
%offseted1 = getelementptr i8, ptr %buffer1, i64 20
146+
br label %if.end
147+
148+
if.end:
149+
%p = phi ptr [ %offseted1, %if.else ], [ %offseted0, %entry ]
150+
%poffseted = getelementptr i8, ptr %p, i64 -4
151+
%size = call i64 @llvm.objectsize.i64.p0(ptr %poffseted, i1 false, i1 false, i1 false)
152+
ret i64 %size
153+
}
154+
155+
define i64 @pick_negative_offset_with_nullptr(i32 %n) {
156+
; CHECK-LABEL: @pick_negative_offset_with_nullptr(
157+
; CHECK-NEXT: entry:
158+
; CHECK-NEXT: [[BUFFER0:%.*]] = alloca i8, i64 20, align 1
159+
; CHECK-NEXT: [[OFFSETED0:%.*]] = getelementptr i8, ptr [[BUFFER0]], i64 20
160+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[N:%.*]], 0
161+
; CHECK-NEXT: br i1 [[COND]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
162+
; CHECK: if.else:
163+
; CHECK-NEXT: br label [[IF_END]]
164+
; CHECK: if.end:
165+
; CHECK-NEXT: [[P0:%.*]] = phi ptr [ [[OFFSETED0]], [[ENTRY:%.*]] ], [ null, [[IF_ELSE]] ]
166+
; CHECK-NEXT: [[P1:%.*]] = phi ptr [ null, [[IF_ELSE]] ], [ [[OFFSETED0]], [[ENTRY]] ]
167+
; CHECK-NEXT: [[P0OFFSETED:%.*]] = getelementptr i8, ptr [[P0]], i64 -4
168+
; CHECK-NEXT: [[P1OFFSETED:%.*]] = getelementptr i8, ptr [[P1]], i64 -4
169+
; CHECK-NEXT: ret i64 4
170+
;
171+
entry:
172+
%buffer0 = alloca i8, i64 20
173+
%offseted0 = getelementptr i8, ptr %buffer0, i64 20
174+
%cond = icmp eq i32 %n, 0
175+
br i1 %cond, label %if.else, label %if.end
176+
177+
if.else:
178+
br label %if.end
179+
180+
if.end:
181+
%p0 = phi ptr [ %offseted0, %entry ], [ null, %if.else ]
182+
%p1 = phi ptr [ null, %if.else ], [ %offseted0, %entry ]
183+
%p0offseted = getelementptr i8, ptr %p0, i64 -4
184+
%p1offseted = getelementptr i8, ptr %p1, i64 -4
185+
%size0 = call i64 @llvm.objectsize.i64.p0(ptr %p0offseted, i1 false, i1 false, i1 false)
186+
%size1 = call i64 @llvm.objectsize.i64.p0(ptr %p1offseted, i1 false, i1 false, i1 false)
187+
%size = select i1 %cond, i64 %size0, i64 %size1
188+
ret i64 %size
189+
}
190+
191+
define i64 @pick_negative_offset_with_unsized_nullptr(i32 %n) {
192+
; CHECK-LABEL: @pick_negative_offset_with_unsized_nullptr(
193+
; CHECK-NEXT: entry:
194+
; CHECK-NEXT: [[BUFFER0:%.*]] = alloca i8, i64 20, align 1
195+
; CHECK-NEXT: [[OFFSETED0:%.*]] = getelementptr i8, ptr [[BUFFER0]], i64 20
196+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[N:%.*]], 0
197+
; CHECK-NEXT: br i1 [[COND]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
198+
; CHECK: if.else:
199+
; CHECK-NEXT: br label [[IF_END]]
200+
; CHECK: if.end:
201+
; CHECK-NEXT: [[P0:%.*]] = phi ptr [ [[OFFSETED0]], [[ENTRY:%.*]] ], [ null, [[IF_ELSE]] ]
202+
; CHECK-NEXT: [[P1:%.*]] = phi ptr [ null, [[IF_ELSE]] ], [ [[OFFSETED0]], [[ENTRY]] ]
203+
; CHECK-NEXT: [[P0OFFSETED:%.*]] = getelementptr i8, ptr [[P0]], i64 -4
204+
; CHECK-NEXT: [[P1OFFSETED:%.*]] = getelementptr i8, ptr [[P1]], i64 -4
205+
; CHECK-NEXT: ret i64 -1
206+
;
207+
entry:
208+
%buffer0 = alloca i8, i64 20
209+
%offseted0 = getelementptr i8, ptr %buffer0, i64 20
210+
%cond = icmp eq i32 %n, 0
211+
br i1 %cond, label %if.else, label %if.end
212+
213+
if.else:
214+
br label %if.end
215+
216+
if.end:
217+
%p0 = phi ptr [ %offseted0, %entry ], [ null, %if.else ]
218+
%p1 = phi ptr [ null, %if.else ], [ %offseted0, %entry ]
219+
%p0offseted = getelementptr i8, ptr %p0, i64 -4
220+
%p1offseted = getelementptr i8, ptr %p1, i64 -4
221+
%size0 = call i64 @llvm.objectsize.i64.p0(ptr %p0offseted, i1 false, i1 true, i1 false)
222+
%size1 = call i64 @llvm.objectsize.i64.p0(ptr %p1offseted, i1 false, i1 true, i1 false)
223+
%size = select i1 %cond, i64 %size0, i64 %size1
224+
ret i64 %size
225+
}
226+
227+
define i64 @chain_pick_negative_offset_with_nullptr(i32 %x) {
228+
; CHECK-LABEL: @chain_pick_negative_offset_with_nullptr(
229+
; CHECK-NEXT: entry:
230+
; CHECK-NEXT: [[ARRAY:%.*]] = alloca [4 x i32], align 4
231+
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], 0
232+
; CHECK-NEXT: [[P:%.*]] = getelementptr i8, ptr [[ARRAY]], i64 8
233+
; CHECK-NEXT: [[COND:%.*]] = select i1 [[C]], ptr [[P]], ptr null
234+
; CHECK-NEXT: [[P4:%.*]] = getelementptr i8, ptr [[COND]], i64 8
235+
; CHECK-NEXT: [[COND6:%.*]] = select i1 [[C]], ptr [[P4]], ptr null
236+
; CHECK-NEXT: [[P7:%.*]] = getelementptr i8, ptr [[COND6]], i64 -4
237+
; CHECK-NEXT: ret i64 4
238+
;
239+
entry:
240+
%array = alloca [4 x i32]
241+
%c = icmp eq i32 %x, 0
242+
%p = getelementptr i8, ptr %array, i64 8
243+
%cond = select i1 %c, ptr %p, ptr null
244+
%p4 = getelementptr i8, ptr %cond, i64 8
245+
%cond6 = select i1 %c, ptr %p4, ptr null
246+
%p7 = getelementptr i8, ptr %cond6, i64 -4
247+
%size = call i64 @llvm.objectsize.i64.p0(ptr %p7, i1 false, i1 false, i1 false)
248+
ret i64 %size
249+
}
250+
251+
252+
define i64 @negative_offset_dynamic_eval(i32 %x, i64 %i) {
253+
; CHECK-LABEL: @negative_offset_dynamic_eval(
254+
; CHECK-NEXT: entry:
255+
; CHECK-NEXT: [[ARRAY1:%.*]] = alloca [4 x i32], align 16
256+
; CHECK-NEXT: [[ARRAY2:%.*]] = alloca [8 x i32], align 16
257+
; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[X:%.*]], 0
258+
; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
259+
; CHECK: if.then:
260+
; CHECK-NEXT: br label [[IF_END:%.*]]
261+
; CHECK: if.else:
262+
; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, ptr [[ARRAY2]], i64 16
263+
; CHECK-NEXT: br label [[IF_END]]
264+
; CHECK: if.end:
265+
; CHECK-NEXT: [[PTR:%.*]] = phi ptr [ [[ARRAY1]], [[IF_THEN]] ], [ [[ADD_PTR]], [[IF_ELSE]] ]
266+
; CHECK-NEXT: [[ADD_PTR2_IDX:%.*]] = mul i64 [[I:%.*]], 4
267+
; CHECK-NEXT: [[TMP0:%.*]] = add i64 16, [[ADD_PTR2_IDX]]
268+
; CHECK-NEXT: [[ADD_PTR2:%.*]] = getelementptr inbounds i32, ptr [[PTR]], i64 [[I]]
269+
; CHECK-NEXT: [[TMP1:%.*]] = sub i64 32, [[TMP0]]
270+
; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i64 32, [[TMP0]]
271+
; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i64 0, i64 [[TMP1]]
272+
; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i64 [[TMP3]], -1
273+
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP4]])
274+
; CHECK-NEXT: ret i64 [[TMP3]]
275+
;
276+
entry:
277+
%array1 = alloca [4 x i32], align 16
278+
%array2 = alloca [8 x i32], align 16
279+
%tobool.not = icmp eq i32 %x, 0
280+
br i1 %tobool.not, label %if.else, label %if.then
281+
282+
if.then:
283+
br label %if.end
284+
285+
if.else:
286+
%add.ptr = getelementptr inbounds i8, ptr %array2, i64 16
287+
br label %if.end
288+
289+
if.end:
290+
%ptr = phi ptr [ %array1, %if.then ], [ %add.ptr, %if.else ]
291+
%add.ptr2 = getelementptr inbounds i32, ptr %ptr, i64 %i
292+
%objsize = call i64 @llvm.objectsize.i64.p0(ptr %add.ptr2, i1 false, i1 true, i1 true)
293+
ret i64 %objsize
294+
}
295+

0 commit comments

Comments
 (0)