Files
clang-p2996/llvm/test/Transforms/LowerConstantIntrinsics/builtin-object-size-phi.ll
serge-sans-paille 1dcb3db0ac [llvm] Fix behavior of llvm.objectsize in presence of negative / large offset (#115504)
The internal structure used to carry intermediate computations hold
signed values. If an object size happens to overflow signed values, we
can get invalid result, so make sure this situation never happens.
    
This is not very limitative as static allocation of such large values
should scarcely happen.
2024-11-18 07:39:04 +00:00

422 lines
16 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes=lower-constant-intrinsics -S < %s | FileCheck %s
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
declare dso_local noalias noundef ptr @malloc(i64 noundef) local_unnamed_addr allocsize(0)
declare i64 @llvm.objectsize.i64.p0(ptr, i1 immarg, i1 immarg, i1 immarg)
@buffer = dso_local global [4 x i8] zeroinitializer, align 1
define dso_local i64 @pick_max(i32 noundef %n) local_unnamed_addr {
; CHECK-LABEL: @pick_max(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[N:%.*]], 0
; CHECK-NEXT: br i1 [[COND]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
; CHECK: if.else:
; CHECK-NEXT: [[MALLOCED:%.*]] = call noalias dereferenceable_or_null(8) ptr @malloc(i64 noundef 8)
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[MALLOCED]], [[IF_ELSE]] ], [ @buffer, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i64 8
;
entry:
%cond = icmp eq i32 %n, 0
br i1 %cond, label %if.else, label %if.end
if.else:
%malloced = call noalias dereferenceable_or_null(8) ptr @malloc(i64 noundef 8)
br label %if.end
if.end:
%p = phi ptr [ %malloced, %if.else ], [ @buffer, %entry ]
%size = call i64 @llvm.objectsize.i64.p0(ptr %p, i1 false, i1 true, i1 false)
ret i64 %size
}
define dso_local i64 @pick_min(i32 noundef %n) local_unnamed_addr {
; CHECK-LABEL: @pick_min(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[N:%.*]], 0
; CHECK-NEXT: br i1 [[COND]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
; CHECK: if.else:
; CHECK-NEXT: [[MALLOCED:%.*]] = call noalias dereferenceable_or_null(8) ptr @malloc(i64 noundef 8)
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[MALLOCED]], [[IF_ELSE]] ], [ @buffer, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i64 4
;
entry:
%cond = icmp eq i32 %n, 0
br i1 %cond, label %if.else, label %if.end
if.else:
%malloced = call noalias dereferenceable_or_null(8) ptr @malloc(i64 noundef 8)
br label %if.end
if.end:
%p = phi ptr [ %malloced, %if.else ], [ @buffer, %entry ]
%size = call i64 @llvm.objectsize.i64.p0(ptr %p, i1 true, i1 true, i1 false)
ret i64 %size
}
define i64 @pick_max_same(i32 %n) {
; CHECK-LABEL: @pick_max_same(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BUFFER:%.*]] = alloca i8, i64 20, align 1
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[N:%.*]], 0
; CHECK-NEXT: br i1 [[COND]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
; CHECK: if.else:
; CHECK-NEXT: [[OFFSETED:%.*]] = getelementptr i8, ptr [[BUFFER]], i64 10
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[OFFSETED]], [[IF_ELSE]] ], [ [[BUFFER]], [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i64 20
;
entry:
%buffer = alloca i8, i64 20
%cond = icmp eq i32 %n, 0
br i1 %cond, label %if.else, label %if.end
if.else:
%offseted = getelementptr i8, ptr %buffer, i64 10
br label %if.end
if.end:
%p = phi ptr [ %offseted, %if.else ], [ %buffer, %entry ]
%size = call i64 @llvm.objectsize.i64.p0(ptr %p, i1 false, i1 true, i1 false)
ret i64 %size
}
define i64 @pick_min_same(i32 %n) {
; CHECK-LABEL: @pick_min_same(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BUFFER:%.*]] = alloca i8, i64 20, align 1
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[N:%.*]], 0
; CHECK-NEXT: br i1 [[COND]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
; CHECK: if.else:
; CHECK-NEXT: [[OFFSETED:%.*]] = getelementptr i8, ptr [[BUFFER]], i64 10
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[OFFSETED]], [[IF_ELSE]] ], [ [[BUFFER]], [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i64 10
;
entry:
%buffer = alloca i8, i64 20
%cond = icmp eq i32 %n, 0
br i1 %cond, label %if.else, label %if.end
if.else:
%offseted = getelementptr i8, ptr %buffer, i64 10
br label %if.end
if.end:
%p = phi ptr [ %offseted, %if.else ], [ %buffer, %entry ]
%size = call i64 @llvm.objectsize.i64.p0(ptr %p, i1 true, i1 true, i1 false)
ret i64 %size
}
define dso_local i64 @pick_max_large(i1 %c) local_unnamed_addr {
; CHECK-LABEL: @pick_max_large(
; CHECK-NEXT: [[BUFFER:%.*]] = alloca i8, i64 -7, align 1
; CHECK-NEXT: [[S:%.*]] = select i1 [[C:%.*]], ptr null, ptr [[BUFFER]]
; CHECK-NEXT: ret i64 -1
;
%buffer = alloca i8, i64 -7 ; Actually a very large positive integer
%s = select i1 %c, ptr null, ptr %buffer
%objsize = tail call i64 @llvm.objectsize.i64.p0(ptr %s, i1 false, i1 false, i1 false)
ret i64 %objsize
}
define dso_local i64 @pick_max_one_oob(i1 %c0, i1 %c1) {
; CHECK-LABEL: @pick_max_one_oob(
; CHECK-NEXT: [[P:%.*]] = alloca [2 x i8], align 1
; CHECK-NEXT: br i1 [[C0:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[P_THEN:%.*]] = getelementptr inbounds [2 x i8], ptr [[P]], i64 0, i64 1
; CHECK-NEXT: br label [[IF_END:%.*]]
; CHECK: if.else:
; CHECK-NEXT: [[P_ELSE:%.*]] = getelementptr inbounds [2 x i8], ptr [[P]], i64 0, i64 -1
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[P_END:%.*]] = phi ptr [ [[P_ELSE]], [[IF_ELSE]] ], [ [[P_THEN]], [[IF_THEN]] ]
; CHECK-NEXT: [[OBJSIZE:%.*]] = select i1 [[C1:%.*]], i64 1, i64 0
; CHECK-NEXT: ret i64 [[OBJSIZE]]
;
%p = alloca [2 x i8], align 1
br i1 %c0, label %if.then, label %if.else
if.then:
%p.then = getelementptr inbounds [2 x i8], ptr %p, i64 0, i64 1
br label %if.end
if.else:
%p.else = getelementptr inbounds [2 x i8], ptr %p, i64 0, i64 -1
br label %if.end
if.end:
%p.end = phi ptr [%p.else, %if.else], [%p.then, %if.then]
%objsize.max = call i64 @llvm.objectsize.i64.p0(ptr %p.end, i1 false, i1 true, i1 false)
%objsize.min = call i64 @llvm.objectsize.i64.p0(ptr %p.end, i1 true, i1 true, i1 false)
%objsize = select i1 %c1, i64 %objsize.max, i64 %objsize.min
ret i64 %objsize
}
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_different_width(i32 %n) {
; CHECK-LABEL: @pick_negative_offset_different_width(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BUFFER0:%.*]] = alloca i8, i64 4, align 1
; CHECK-NEXT: [[BUFFER1:%.*]] = alloca i8, i64 8, align 1
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[N:%.*]], 0
; CHECK-NEXT: br i1 [[COND]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[OFFSETED0:%.*]] = getelementptr i8, ptr [[BUFFER0]], i64 1
; CHECK-NEXT: br label [[IF_END1:%.*]]
; CHECK: if.else:
; CHECK-NEXT: [[OFFSETED1:%.*]] = getelementptr i8, ptr [[BUFFER1]], i64 6
; CHECK-NEXT: br label [[IF_END1]]
; CHECK: if.end:
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[OFFSETED0]], [[IF_ELSE]] ], [ [[OFFSETED1]], [[IF_END]] ]
; CHECK-NEXT: [[POFFSETED:%.*]] = getelementptr i8, ptr [[P]], i64 -2
; CHECK-NEXT: ret i64 5
;
entry:
%buffer0 = alloca i8, i64 4
%buffer1 = alloca i8, i64 8
%cond = icmp eq i32 %n, 0
br i1 %cond, label %if.then, label %if.else
if.then:
%offseted0 = getelementptr i8, ptr %buffer0, i64 1
br label %if.end
if.else:
%offseted1 = getelementptr i8, ptr %buffer1, i64 6
br label %if.end
if.end:
%p = phi ptr [ %offseted0, %if.then ], [ %offseted1, %if.else ]
%poffseted = getelementptr i8, ptr %p, i64 -2
%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: [[TMP0:%.*]] = phi i64 [ 16, [[IF_THEN]] ], [ 32, [[IF_ELSE]] ]
; CHECK-NEXT: [[TMP5:%.*]] = phi i64 [ 0, [[IF_THEN]] ], [ 16, [[IF_ELSE]] ]
; CHECK-NEXT: [[PTR:%.*]] = phi ptr [ [[ARRAY1]], [[IF_THEN]] ], [ [[ADD_PTR]], [[IF_ELSE]] ]
; CHECK-NEXT: [[ADD_PTR2_IDX:%.*]] = mul i64 [[I:%.*]], 4
; CHECK-NEXT: [[TMP6:%.*]] = add i64 [[TMP5]], [[ADD_PTR2_IDX]]
; CHECK-NEXT: [[ADD_PTR2:%.*]] = getelementptr inbounds i32, ptr [[PTR]], i64 [[I]]
; CHECK-NEXT: [[TMP1:%.*]] = sub i64 [[TMP0]], [[TMP6]]
; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i64 [[TMP0]], [[TMP6]]
; 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
}
define i64 @outofbound_offset_eval(i32 %x) {
; CHECK-LABEL: @outofbound_offset_eval(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ARRAY:%.*]] = alloca [4 x i8], 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: [[ADD_PTR0:%.*]] = getelementptr i8, ptr [[ARRAY]], i64 10
; CHECK-NEXT: br label [[IF_END:%.*]]
; CHECK: if.else:
; CHECK-NEXT: [[ADD_PTR1:%.*]] = getelementptr i8, ptr [[ARRAY]], i64 12
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[PTR:%.*]] = phi ptr [ [[ADD_PTR0]], [[IF_THEN]] ], [ [[ADD_PTR1]], [[IF_ELSE]] ]
; CHECK-NEXT: [[ADD_PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 -10
; CHECK-NEXT: ret i64 4
;
entry:
%array = alloca [4 x i8], align 16
%tobool.not = icmp eq i32 %x, 0
br i1 %tobool.not, label %if.else, label %if.then
if.then:
%add.ptr0 = getelementptr i8, ptr %array, i64 10
br label %if.end
if.else:
%add.ptr1 = getelementptr i8, ptr %array, i64 12
br label %if.end
if.end:
%ptr = phi ptr [ %add.ptr0, %if.then ], [ %add.ptr1, %if.else ]
%add.ptr2 = getelementptr i8, ptr %ptr, i64 -10
%objsize = call i64 @llvm.objectsize.i64.p0(ptr %add.ptr2, i1 false, i1 false, i1 false)
ret i64 %objsize
}