Changes the size of allocations automatically. For now, implements the case when a single range from start of the allocation is alive and the allocation can be reduced.
519 lines
23 KiB
LLVM
519 lines
23 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals --version 2
|
|
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
|
|
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
|
|
|
|
%struct.Foo = type { i32, i32, i8 }
|
|
|
|
@.str = private unnamed_addr constant [17 x i8] c"The value is %d\0A\00", align 1
|
|
|
|
;.
|
|
; CHECK: @[[_STR:[a-zA-Z0-9_$"\\.-]+]] = private unnamed_addr constant [17 x i8] c"The value is %d\0A\00", align 1
|
|
;.
|
|
define dso_local void @positive_alloca_1(i32 noundef %val) #0 {
|
|
; CHECK-LABEL: define dso_local void @positive_alloca_1
|
|
; CHECK-SAME: (i32 noundef [[VAL:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[VAL_ADDR1:%.*]] = alloca i8, i32 4, align 4
|
|
; CHECK-NEXT: [[F2:%.*]] = alloca i8, i32 4, align 4
|
|
; CHECK-NEXT: store i32 [[VAL]], ptr [[VAL_ADDR1]], align 4
|
|
; CHECK-NEXT: store i32 10, ptr [[F2]], align 4
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[F2]], align 4
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], 1
|
|
; CHECK-NEXT: store i32 [[ADD]], ptr [[F2]], align 4
|
|
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[F2]], align 4
|
|
; CHECK-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP1]], [[VAL]]
|
|
; CHECK-NEXT: [[CALL:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(17) @.str, i32 noundef [[ADD3]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%val.addr = alloca i64, align 4
|
|
%f = alloca %struct.Foo, align 4
|
|
store i32 %val, ptr %val.addr, align 4
|
|
%field1 = getelementptr inbounds %struct.Foo, ptr %f, i32 0, i32 0
|
|
store i32 10, ptr %field1, align 4
|
|
%field11 = getelementptr inbounds %struct.Foo, ptr %f, i32 0, i32 0
|
|
%0 = load i32, ptr %field11, align 4
|
|
%add = add nsw i32 %0, 1
|
|
store i32 %add, ptr %field11, align 4
|
|
%field12 = getelementptr inbounds %struct.Foo, ptr %f, i32 0, i32 0
|
|
%1 = load i32, ptr %field12, align 4
|
|
%2 = load i32, ptr %val.addr, align 4
|
|
%add3 = add nsw i32 %1, %2
|
|
%call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %add3)
|
|
ret void
|
|
}
|
|
|
|
; TODO: change malloc like call
|
|
; Function Attrs: noinline nounwind uwtable
|
|
define dso_local void @positive_malloc_1(ptr noundef %val) #0 {
|
|
; CHECK-LABEL: define dso_local void @positive_malloc_1
|
|
; CHECK-SAME: (ptr nocapture nofree noundef readonly [[VAL:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[VAL_ADDR:%.*]] = alloca ptr, align 8
|
|
; CHECK-NEXT: [[F:%.*]] = alloca ptr, align 8
|
|
; CHECK-NEXT: store ptr [[VAL]], ptr [[VAL_ADDR]], align 8
|
|
; CHECK-NEXT: [[CALL:%.*]] = call noalias ptr @malloc(i64 noundef 12)
|
|
; CHECK-NEXT: store ptr [[CALL]], ptr [[F]], align 8
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[VAL]], align 4
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], 10
|
|
; CHECK-NEXT: store i32 [[ADD]], ptr [[CALL]], align 4
|
|
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[CALL]], align 4
|
|
; CHECK-NEXT: [[CALL2:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(17) @.str, i32 noundef [[TMP1]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%val.addr = alloca ptr, align 8
|
|
%f = alloca ptr, align 8
|
|
store ptr %val, ptr %val.addr, align 8
|
|
%call = call noalias ptr @malloc(i64 noundef 12) #3
|
|
store ptr %call, ptr %f, align 8
|
|
%0 = load ptr, ptr %val.addr, align 8
|
|
%1 = load i32, ptr %0, align 4
|
|
%add = add nsw i32 %1, 10
|
|
%2 = load ptr, ptr %f, align 8
|
|
%a = getelementptr inbounds %struct.Foo, ptr %2, i32 0, i32 0
|
|
store i32 %add, ptr %a, align 4
|
|
%3 = load ptr, ptr %f, align 8
|
|
%a1 = getelementptr inbounds %struct.Foo, ptr %3, i32 0, i32 0
|
|
%4 = load i32, ptr %a1, align 4
|
|
%call2 = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %4)
|
|
ret void
|
|
}
|
|
|
|
; TODO: change malloc like call
|
|
; Function Attrs: noinline nounwind uwtable
|
|
define dso_local void @positive_malloc_2(ptr noundef %val) #0 {
|
|
; CHECK-LABEL: define dso_local void @positive_malloc_2
|
|
; CHECK-SAME: (ptr nocapture nofree noundef readonly [[VAL:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[VAL_ADDR:%.*]] = alloca ptr, align 8
|
|
; CHECK-NEXT: [[F:%.*]] = alloca ptr, align 8
|
|
; CHECK-NEXT: store ptr [[VAL]], ptr [[VAL_ADDR]], align 8
|
|
; CHECK-NEXT: [[CALL:%.*]] = call noalias ptr @malloc(i64 noundef 60)
|
|
; CHECK-NEXT: store ptr [[CALL]], ptr [[F]], align 8
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[VAL]], align 4
|
|
; CHECK-NEXT: store i32 [[TMP0]], ptr [[CALL]], align 4
|
|
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[CALL]], align 4
|
|
; CHECK-NEXT: [[CALL2:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(17) @.str, i32 noundef [[TMP1]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%val.addr = alloca ptr, align 8
|
|
%x = alloca i32, align 4
|
|
%f = alloca ptr, align 8
|
|
store ptr %val, ptr %val.addr, align 8
|
|
store i32 15, ptr %x, align 4
|
|
%0 = load i32, ptr %x, align 4
|
|
%conv = sext i32 %0 to i64
|
|
%mul = mul i64 4, %conv
|
|
%call = call noalias ptr @malloc(i64 noundef %mul)
|
|
store ptr %call, ptr %f, align 8
|
|
%1 = load ptr, ptr %val.addr, align 8
|
|
%2 = load i32, ptr %1, align 4
|
|
%3 = load ptr, ptr %f, align 8
|
|
%arrayidx = getelementptr inbounds i32, ptr %3, i64 0
|
|
store i32 %2, ptr %arrayidx, align 4
|
|
%4 = load ptr, ptr %f, align 8
|
|
%arrayidx1 = getelementptr inbounds i32, ptr %4, i64 0
|
|
%5 = load i32, ptr %arrayidx1, align 4
|
|
%call2 = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %5)
|
|
ret void
|
|
}
|
|
|
|
; Function Attrs: noinline nounwind uwtable
|
|
define dso_local ptr @negative_test_escaping_pointer(i32 noundef %val) #0 {
|
|
; CHECK-LABEL: define dso_local ptr @negative_test_escaping_pointer
|
|
; CHECK-SAME: (i32 noundef [[VAL:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[VAL_ADDR:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: [[F:%.*]] = alloca ptr, align 8
|
|
; CHECK-NEXT: store i32 [[VAL]], ptr [[VAL_ADDR]], align 4
|
|
; CHECK-NEXT: [[CALL:%.*]] = call noalias ptr @malloc(i64 noundef 16)
|
|
; CHECK-NEXT: store ptr [[CALL]], ptr [[F]], align 8
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[F]], align 8
|
|
; CHECK-NEXT: store i32 2, ptr [[TMP0]], align 8
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 10, [[VAL]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[F]], align 8
|
|
; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[TMP1]], align 8
|
|
; CHECK-NEXT: [[ADD2:%.*]] = add nsw i32 [[TMP2]], [[ADD]]
|
|
; CHECK-NEXT: store i32 [[ADD2]], ptr [[TMP1]], align 8
|
|
; CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[F]], align 8
|
|
; CHECK-NEXT: ret ptr [[TMP3]]
|
|
;
|
|
entry:
|
|
%val.addr = alloca i32, align 4
|
|
%f = alloca ptr, align 8
|
|
store i32 %val, ptr %val.addr, align 4
|
|
%call = call noalias ptr @malloc(i64 noundef 16) #2
|
|
store ptr %call, ptr %f, align 8
|
|
%0 = load ptr, ptr %f, align 8
|
|
%field1 = getelementptr inbounds %struct.Foo, ptr %0, i32 0, i32 0
|
|
store i32 2, ptr %field1, align 8
|
|
%1 = load i32, ptr %val.addr, align 4
|
|
%add = add nsw i32 10, %1
|
|
%2 = load ptr, ptr %f, align 8
|
|
%field11 = getelementptr inbounds %struct.Foo, ptr %2, i32 0, i32 0
|
|
%3 = load i32, ptr %field11, align 8
|
|
%add2 = add nsw i32 %3, %add
|
|
store i32 %add2, ptr %field11, align 8
|
|
%4 = load ptr, ptr %f, align 8
|
|
ret ptr %4
|
|
}
|
|
|
|
|
|
;TODO: The allocation can be reduced here.
|
|
;However, the offsets (load/store etc.) Need to be changed.
|
|
; Function Attrs: noinline nounwind uwtable
|
|
define dso_local { i64, ptr } @positive_test_not_a_single_start_offset(i32 noundef %val) #0 {
|
|
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define dso_local { i64, ptr } @positive_test_not_a_single_start_offset
|
|
; CHECK-SAME: (i32 noundef [[VAL:%.*]]) #[[ATTR0:[0-9]+]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_FOO:%.*]], align 8
|
|
; CHECK-NEXT: [[VAL_ADDR:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: store i32 [[VAL]], ptr [[VAL_ADDR]], align 4
|
|
; CHECK-NEXT: store i32 2, ptr [[RETVAL]], align 8
|
|
; CHECK-NEXT: [[FIELD3:%.*]] = getelementptr inbounds [[STRUCT_FOO]], ptr [[RETVAL]], i32 0, i32 2
|
|
; CHECK-NEXT: store ptr [[VAL_ADDR]], ptr [[FIELD3]], align 8
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load { i64, ptr }, ptr [[RETVAL]], align 8
|
|
; CHECK-NEXT: ret { i64, ptr } [[TMP0]]
|
|
;
|
|
entry:
|
|
%retval = alloca %struct.Foo, align 8
|
|
%val.addr = alloca i32, align 4
|
|
store i32 %val, ptr %val.addr, align 4
|
|
%field1 = getelementptr inbounds %struct.Foo, ptr %retval, i32 0, i32 0
|
|
store i32 2, ptr %field1, align 8
|
|
%field3 = getelementptr inbounds %struct.Foo, ptr %retval, i32 0, i32 2
|
|
store ptr %val.addr, ptr %field3, align 8
|
|
%0 = load { i64, ptr }, ptr %retval, align 8
|
|
ret { i64, ptr } %0
|
|
}
|
|
|
|
; Function Attrs: noinline nounwind uwtable
|
|
define dso_local void @positive_test_reduce_array_allocation_1() {
|
|
; CHECK-LABEL: define dso_local void @positive_test_reduce_array_allocation_1() {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ARRAY1:%.*]] = alloca i8, i32 4, align 8
|
|
; CHECK-NEXT: store i32 0, ptr [[ARRAY1]], align 8
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAY1]], align 8
|
|
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[TMP0]], 2
|
|
; CHECK-NEXT: store i32 [[TMP1]], ptr [[ARRAY1]], align 8
|
|
; CHECK-NEXT: [[TMP2:%.*]] = add i32 1, 2
|
|
; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[ARRAY1]], align 8
|
|
; CHECK-NEXT: [[TMP4:%.*]] = add i32 [[TMP2]], [[TMP3]]
|
|
; CHECK-NEXT: store i32 [[TMP4]], ptr [[ARRAY1]], align 8
|
|
; CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[ARRAY1]], align 8
|
|
; CHECK-NEXT: [[CALL:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(17) @.str, i32 noundef [[TMP5]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%array = alloca ptr, i32 10
|
|
store i32 0, ptr %array
|
|
%0 = load i32, ptr %array
|
|
%1 = add i32 %0, 2
|
|
store i32 %1, ptr %array
|
|
%2 = add i32 1, 2
|
|
%3 = load i32, ptr %array
|
|
%4 = add i32 %2, %3
|
|
store i32 %4, ptr %array
|
|
%5 = load i32, ptr %array
|
|
%call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %5)
|
|
ret void
|
|
}
|
|
|
|
|
|
; Function Attrs: noinline nounwind uwtable
|
|
; TODO: Here the array size is not known at compile time.
|
|
; However the array does not escape and is only partially used.
|
|
; Should the optimization reduce the allocation size regardless? Based on AAPointerInfo.
|
|
define dso_local void @baz(ptr noundef %val, i32 noundef %arrayLength) #0 {
|
|
; CHECK-LABEL: define dso_local void @baz
|
|
; CHECK-SAME: (ptr nocapture nofree noundef readonly [[VAL:%.*]], i32 noundef [[ARRAYLENGTH:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[VAL_ADDR:%.*]] = alloca ptr, align 8
|
|
; CHECK-NEXT: [[ARRAYLENGTH_ADDR:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: [[F:%.*]] = alloca ptr, align 8
|
|
; CHECK-NEXT: store ptr [[VAL]], ptr [[VAL_ADDR]], align 8
|
|
; CHECK-NEXT: store i32 [[ARRAYLENGTH]], ptr [[ARRAYLENGTH_ADDR]], align 4
|
|
; CHECK-NEXT: [[CONV:%.*]] = sext i32 [[ARRAYLENGTH]] to i64
|
|
; CHECK-NEXT: [[MUL:%.*]] = mul i64 4, [[CONV]]
|
|
; CHECK-NEXT: [[CALL:%.*]] = call noalias ptr @malloc(i64 noundef [[MUL]])
|
|
; CHECK-NEXT: store ptr [[CALL]], ptr [[F]], align 8
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[VAL]], align 4
|
|
; CHECK-NEXT: store i32 [[TMP0]], ptr [[CALL]], align 4
|
|
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[CALL]], align 4
|
|
; CHECK-NEXT: [[CALL2:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(17) @.str, i32 noundef [[TMP1]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%val.addr = alloca ptr, align 8
|
|
%arrayLength.addr = alloca i32, align 4
|
|
%f = alloca ptr, align 8
|
|
store ptr %val, ptr %val.addr, align 8
|
|
store i32 %arrayLength, ptr %arrayLength.addr, align 4
|
|
%0 = load i32, ptr %arrayLength.addr, align 4
|
|
%conv = sext i32 %0 to i64
|
|
%mul = mul i64 4, %conv
|
|
%call = call noalias ptr @malloc(i64 noundef %mul) #3
|
|
store ptr %call, ptr %f, align 8
|
|
%1 = load ptr, ptr %val.addr, align 8
|
|
%2 = load i32, ptr %1, align 4
|
|
%3 = load ptr, ptr %f, align 8
|
|
%arrayidx = getelementptr inbounds i32, ptr %3, i64 0
|
|
store i32 %2, ptr %arrayidx, align 4
|
|
%4 = load ptr, ptr %f, align 8
|
|
%arrayidx1 = getelementptr inbounds i32, ptr %4, i64 0
|
|
%5 = load i32, ptr %arrayidx1, align 4
|
|
%call2 = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %5)
|
|
ret void
|
|
}
|
|
|
|
;TODO: Here since only even indexes of the array are part of the output
|
|
;We can reduce the allocation by half and make an array that's accessed contiguously
|
|
; Function Attrs: noinline nounwind uwtable
|
|
define dso_local void @positive_test_reduce_array_allocation_2() #0 {
|
|
; CHECK-LABEL: define dso_local void @positive_test_reduce_array_allocation_2() {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ARRAY:%.*]] = alloca ptr, align 8
|
|
; CHECK-NEXT: [[I:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: [[CALL:%.*]] = call noalias ptr @malloc(i64 noundef 40000)
|
|
; CHECK-NEXT: store ptr [[CALL]], ptr [[ARRAY]], align 8
|
|
; CHECK-NEXT: store i32 0, ptr [[I]], align 4
|
|
; CHECK-NEXT: br label [[FOR_COND:%.*]]
|
|
; CHECK: for.cond:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[I]], align 4
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP0]], 10000
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
|
|
; CHECK: for.body:
|
|
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[I]], align 4
|
|
; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[I]], align 4
|
|
; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP2]] to i64
|
|
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[CALL]], i64 [[IDXPROM]]
|
|
; CHECK-NEXT: store i32 [[TMP1]], ptr [[ARRAYIDX]], align 4
|
|
; CHECK-NEXT: br label [[FOR_INC:%.*]]
|
|
; CHECK: for.inc:
|
|
; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[I]], align 4
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP3]], 2
|
|
; CHECK-NEXT: store i32 [[ADD]], ptr [[I]], align 4
|
|
; CHECK-NEXT: br label [[FOR_COND]]
|
|
; CHECK: for.end:
|
|
; CHECK-NEXT: store i32 0, ptr [[I]], align 4
|
|
; CHECK-NEXT: br label [[FOR_COND1:%.*]]
|
|
; CHECK: for.cond1:
|
|
; CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[I]], align 4
|
|
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[TMP4]], 10000
|
|
; CHECK-NEXT: br i1 [[CMP2]], label [[FOR_BODY3:%.*]], label [[FOR_END9:%.*]]
|
|
; CHECK: for.body3:
|
|
; CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[I]], align 4
|
|
; CHECK-NEXT: [[IDXPROM4:%.*]] = sext i32 [[TMP5]] to i64
|
|
; CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds i32, ptr [[CALL]], i64 [[IDXPROM4]]
|
|
; CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr [[ARRAYIDX5]], align 4
|
|
; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP6]], 1
|
|
; CHECK-NEXT: store i32 [[ADD6]], ptr [[ARRAYIDX5]], align 4
|
|
; CHECK-NEXT: br label [[FOR_INC7:%.*]]
|
|
; CHECK: for.inc7:
|
|
; CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[I]], align 4
|
|
; CHECK-NEXT: [[ADD8:%.*]] = add nsw i32 [[TMP7]], 2
|
|
; CHECK-NEXT: store i32 [[ADD8]], ptr [[I]], align 4
|
|
; CHECK-NEXT: br label [[FOR_COND1]]
|
|
; CHECK: for.end9:
|
|
; CHECK-NEXT: store i32 0, ptr [[I]], align 4
|
|
; CHECK-NEXT: br label [[FOR_COND10:%.*]]
|
|
; CHECK: for.cond10:
|
|
; CHECK-NEXT: [[TMP8:%.*]] = load i32, ptr [[I]], align 4
|
|
; CHECK-NEXT: [[CMP11:%.*]] = icmp slt i32 [[TMP8]], 10000
|
|
; CHECK-NEXT: br i1 [[CMP11]], label [[FOR_BODY12:%.*]], label [[FOR_END18:%.*]]
|
|
; CHECK: for.body12:
|
|
; CHECK-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
|
|
; CHECK-NEXT: [[IDXPROM13:%.*]] = sext i32 [[TMP9]] to i64
|
|
; CHECK-NEXT: [[ARRAYIDX14:%.*]] = getelementptr inbounds i32, ptr [[CALL]], i64 [[IDXPROM13]]
|
|
; CHECK-NEXT: [[TMP10:%.*]] = load i32, ptr [[ARRAYIDX14]], align 4
|
|
; CHECK-NEXT: [[CALL15:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(17) @.str, i32 noundef [[TMP10]])
|
|
; CHECK-NEXT: br label [[FOR_INC16:%.*]]
|
|
; CHECK: for.inc16:
|
|
; CHECK-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
|
|
; CHECK-NEXT: [[ADD17:%.*]] = add nsw i32 [[TMP11]], 2
|
|
; CHECK-NEXT: store i32 [[ADD17]], ptr [[I]], align 4
|
|
; CHECK-NEXT: br label [[FOR_COND10]]
|
|
; CHECK: for.end18:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%array = alloca ptr, align 8
|
|
%i = alloca i32, align 4
|
|
%call = call noalias ptr @malloc(i64 noundef 40000) #3
|
|
store ptr %call, ptr %array, align 8
|
|
store i32 0, ptr %i, align 4
|
|
br label %for.cond
|
|
|
|
for.cond:
|
|
%0 = load i32, ptr %i, align 4
|
|
%cmp = icmp slt i32 %0, 10000
|
|
br i1 %cmp, label %for.body, label %for.end
|
|
|
|
for.body:
|
|
%1 = load i32, ptr %i, align 4
|
|
%2 = load ptr, ptr %array, align 8
|
|
%3 = load i32, ptr %i, align 4
|
|
%idxprom = sext i32 %3 to i64
|
|
%arrayidx = getelementptr inbounds i32, ptr %2, i64 %idxprom
|
|
store i32 %1, ptr %arrayidx, align 4
|
|
br label %for.inc
|
|
|
|
for.inc:
|
|
%4 = load i32, ptr %i, align 4
|
|
%add = add nsw i32 %4, 2
|
|
store i32 %add, ptr %i, align 4
|
|
br label %for.cond
|
|
|
|
for.end:
|
|
store i32 0, ptr %i, align 4
|
|
br label %for.cond1
|
|
|
|
for.cond1:
|
|
%5 = load i32, ptr %i, align 4
|
|
%cmp2 = icmp slt i32 %5, 10000
|
|
br i1 %cmp2, label %for.body3, label %for.end9
|
|
|
|
for.body3:
|
|
%6 = load ptr, ptr %array, align 8
|
|
%7 = load i32, ptr %i, align 4
|
|
%idxprom4 = sext i32 %7 to i64
|
|
%arrayidx5 = getelementptr inbounds i32, ptr %6, i64 %idxprom4
|
|
%8 = load i32, ptr %arrayidx5, align 4
|
|
%add6 = add nsw i32 %8, 1
|
|
store i32 %add6, ptr %arrayidx5, align 4
|
|
br label %for.inc7
|
|
|
|
for.inc7:
|
|
%9 = load i32, ptr %i, align 4
|
|
%add8 = add nsw i32 %9, 2
|
|
store i32 %add8, ptr %i, align 4
|
|
br label %for.cond1
|
|
|
|
for.end9:
|
|
store i32 0, ptr %i, align 4
|
|
br label %for.cond10
|
|
|
|
for.cond10:
|
|
%10 = load i32, ptr %i, align 4
|
|
%cmp11 = icmp slt i32 %10, 10000
|
|
br i1 %cmp11, label %for.body12, label %for.end18
|
|
|
|
for.body12:
|
|
%11 = load ptr, ptr %array, align 8
|
|
%12 = load i32, ptr %i, align 4
|
|
%idxprom13 = sext i32 %12 to i64
|
|
%arrayidx14 = getelementptr inbounds i32, ptr %11, i64 %idxprom13
|
|
%13 = load i32, ptr %arrayidx14, align 4
|
|
%call15 = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %13)
|
|
br label %for.inc16
|
|
|
|
for.inc16:
|
|
%14 = load i32, ptr %i, align 4
|
|
%add17 = add nsw i32 %14, 2
|
|
store i32 %add17, ptr %i, align 4
|
|
br label %for.cond10
|
|
|
|
for.end18:
|
|
ret void
|
|
}
|
|
|
|
|
|
define dso_local void @pthread_test(){
|
|
; TUNIT-LABEL: define dso_local void @pthread_test() {
|
|
; TUNIT-NEXT: [[ARG1:%.*]] = alloca i8, align 8
|
|
; TUNIT-NEXT: [[THREAD:%.*]] = alloca i64, align 8
|
|
; TUNIT-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @pthread_allocation_should_remain_same, ptr noundef nonnull align 8 dereferenceable(1) [[ARG1]])
|
|
; TUNIT-NEXT: [[F1:%.*]] = alloca i8, i32 4, align 4
|
|
; TUNIT-NEXT: [[CALL2:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @pthread_allocation_should_be_reduced, ptr noalias nocapture nofree nonnull readnone align 4 dereferenceable(12) undef)
|
|
; TUNIT-NEXT: [[F2:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
|
|
; TUNIT-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @pthread_check_captured_pointer, ptr noundef nonnull align 4 dereferenceable(12) [[F2]])
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC-LABEL: define dso_local void @pthread_test() {
|
|
; CGSCC-NEXT: [[ARG1:%.*]] = alloca i8, align 8
|
|
; CGSCC-NEXT: [[THREAD:%.*]] = alloca i64, align 8
|
|
; CGSCC-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @pthread_allocation_should_remain_same, ptr noundef nonnull align 8 dereferenceable(1) [[ARG1]])
|
|
; CGSCC-NEXT: [[F:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
|
|
; CGSCC-NEXT: [[CALL2:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @pthread_allocation_should_be_reduced, ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(12) [[F]])
|
|
; CGSCC-NEXT: [[F2:%.*]] = alloca [[STRUCT_FOO]], align 4
|
|
; CGSCC-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @pthread_check_captured_pointer, ptr noundef nonnull align 4 dereferenceable(12) [[F2]])
|
|
; CGSCC-NEXT: ret void
|
|
;
|
|
%arg1 = alloca i8, align 8
|
|
%thread = alloca i64, align 8
|
|
%call1 = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @pthread_allocation_should_remain_same, ptr %arg1)
|
|
%f = alloca %struct.Foo, align 4
|
|
%call2 = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @pthread_allocation_should_be_reduced, ptr %f)
|
|
%f2 = alloca %struct.Foo, align 4
|
|
%call3 = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @pthread_check_captured_pointer, ptr %f2)
|
|
ret void
|
|
}
|
|
|
|
define internal ptr @pthread_allocation_should_remain_same(ptr %arg) {
|
|
; CHECK-LABEL: define internal noundef nonnull align 8 dereferenceable(1) ptr @pthread_allocation_should_remain_same
|
|
; CHECK-SAME: (ptr noundef nonnull returned align 8 dereferenceable(1) [[ARG:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CALL:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(17) @.str, ptr noundef nonnull align 8 dereferenceable(1) [[ARG]])
|
|
; CHECK-NEXT: ret ptr [[ARG]]
|
|
;
|
|
entry:
|
|
%call = call i32 (ptr, ...) @printf(ptr noundef @.str, ptr noundef %arg)
|
|
ret ptr %arg
|
|
}
|
|
|
|
define internal void @pthread_allocation_should_be_reduced(ptr %arg) {
|
|
;
|
|
; TUNIT-LABEL: define internal void @pthread_allocation_should_be_reduced
|
|
; TUNIT-SAME: (ptr noalias nocapture nofree nonnull readnone align 4 dereferenceable(12) [[ARG:%.*]]) {
|
|
; TUNIT-NEXT: entry:
|
|
; TUNIT-NEXT: [[CALL:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(17) @.str, i32 undef)
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC-LABEL: define internal void @pthread_allocation_should_be_reduced
|
|
; CGSCC-SAME: (ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(12) [[ARG:%.*]]) {
|
|
; CGSCC-NEXT: entry:
|
|
; CGSCC-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARG]], align 4
|
|
; CGSCC-NEXT: [[CALL:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(17) @.str, i32 noundef [[TMP0]])
|
|
; CGSCC-NEXT: ret void
|
|
;
|
|
entry:
|
|
%field1 = getelementptr inbounds %struct.Foo, ptr %arg, i32 0, i32 0
|
|
%0 = load i32, ptr %field1, align 4
|
|
%call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %0)
|
|
ret void
|
|
}
|
|
|
|
define internal void @pthread_check_captured_pointer(ptr %arg){
|
|
; CHECK-LABEL: define internal void @pthread_check_captured_pointer
|
|
; CHECK-SAME: (ptr noundef nonnull align 4 dereferenceable(12) [[ARG:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: call void @external_call(ptr noundef nonnull align 4 dereferenceable(12) [[ARG]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%field1 = getelementptr inbounds %struct.Foo, ptr %arg, i32 0, i32 0
|
|
call void @external_call(ptr %field1)
|
|
ret void
|
|
}
|
|
|
|
|
|
declare external void @external_call(ptr)
|
|
|
|
declare !callback !0 dso_local i32 @pthread_create(ptr, ptr, ptr, ptr)
|
|
!1 = !{i64 2, i64 3, i1 false}
|
|
!0 = !{!1}
|
|
|
|
declare i32 @printf(ptr noundef, ...) #1
|
|
|
|
; Function Attrs: nounwind allocsize(0)
|
|
declare noalias ptr @malloc(i64 noundef) #1
|
|
;.
|
|
; CHECK: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
|
|
;.
|
|
; CHECK: [[META0:![0-9]+]] = !{!1}
|
|
; CHECK: [[META1:![0-9]+]] = !{i64 2, i64 3, i1 false}
|
|
;.
|