; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -aa-pipeline=basic-aa,globals-aa -S -passes='require<globals-aa>,function(loop-mssa(licm))' | FileCheck %s
;Reference C code:
;struct str {
; void **p;
;};
;static struct str obj;
;extern void nocapture_nocallback_func(struct str *);
;void test(void *p) {
; nocapture_nocallback_func(&obj);
; for (int i = 0; i < 1000; ++i) {
; unknown_call(); // optional
; obj.p[i] = p;
; }
;}
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
%struct.str = type { ptr }
@obj0 = internal global %struct.str zeroinitializer, align 8
@obj1 = internal global %struct.str zeroinitializer, align 8
@obj2 = internal global %struct.str zeroinitializer, align 8
@obj3 = internal global %struct.str zeroinitializer, align 8
@obj4 = internal global %struct.str zeroinitializer, align 8
@obj5 = internal global %struct.str zeroinitializer, align 8
define dso_local void @test0(ptr %p) {
; Check that load from @obj0 is hoisted from the loop, meaning
; that it does not conflict with the store inside the loop:
; CHECK-LABEL: @test0(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @nocapture_nocallback_func(ptr @obj0)
; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @obj0, align 8
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 1000
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_0]] to i64
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i64 [[IDXPROM]]
; CHECK-NEXT: store ptr [[P:%.*]], ptr [[ARRAYIDX]], align 8
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INC]] = add nsw i32 [[I_0]], 1
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
entry:
call void @nocapture_nocallback_func(ptr @obj0)
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
%cmp = icmp slt i32 %i.0, 1000
br i1 %cmp, label %for.body, label %for.end
for.body: ; preds = %for.cond
%0 = load ptr, ptr @obj0, align 8
%idxprom = sext i32 %i.0 to i64
%arrayidx = getelementptr inbounds ptr, ptr %0, i64 %idxprom
store ptr %p, ptr %arrayidx, align 8
br label %for.inc
for.inc: ; preds = %for.body
%inc = add nsw i32 %i.0, 1
br label %for.cond
for.end: ; preds = %for.cond
ret void
}
define dso_local void @test1(ptr %p) {
; Check that load from @obj1 is not hoisted from the loop,
; because 'nocallback' is missing:
; CHECK-LABEL: @test1(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @nocapture_func(ptr @obj1)
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 1000
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @obj1, align 8
; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_0]] to i64
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i64 [[IDXPROM]]
; CHECK-NEXT: store ptr [[P:%.*]], ptr [[ARRAYIDX]], align 8
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INC]] = add nsw i32 [[I_0]], 1
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
entry:
call void @nocapture_func(ptr @obj1)
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
%cmp = icmp slt i32 %i.0, 1000
br i1 %cmp, label %for.body, label %for.end
for.body: ; preds = %for.cond
%0 = load ptr, ptr @obj1, align 8
%idxprom = sext i32 %i.0 to i64
%arrayidx = getelementptr inbounds ptr, ptr %0, i64 %idxprom
store ptr %p, ptr %arrayidx, align 8
br label %for.inc
for.inc: ; preds = %for.body
%inc = add nsw i32 %i.0, 1
br label %for.cond
for.end: ; preds = %for.cond
ret void
}
define dso_local void @test2(ptr %p) {
; Check that load from @obj2 is not hoisted from the loop,
; because 'nocapture' is missing:
; CHECK-LABEL: @test2(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @nocallback_func(ptr @obj2)
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 1000
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @obj2, align 8
; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_0]] to i64
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i64 [[IDXPROM]]
; CHECK-NEXT: store ptr [[P:%.*]], ptr [[ARRAYIDX]], align 8
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INC]] = add nsw i32 [[I_0]], 1
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
entry:
call void @nocallback_func(ptr @obj2)
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
%cmp = icmp slt i32 %i.0, 1000
br i1 %cmp, label %for.body, label %for.end
for.body: ; preds = %for.cond
%0 = load ptr, ptr @obj2, align 8
%idxprom = sext i32 %i.0 to i64
%arrayidx = getelementptr inbounds ptr, ptr %0, i64 %idxprom
store ptr %p, ptr %arrayidx, align 8
br label %for.inc
for.inc: ; preds = %for.body
%inc = add nsw i32 %i.0, 1
br label %for.cond
for.end: ; preds = %for.cond
ret void
}
define dso_local void @test3(ptr %p) {
; Check that load from @obj3 is hoisted from the loop, even though
; there is unknown call in the loop.
; CHECK-LABEL: @test3(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @nocapture_nocallback_func(ptr @obj3)
; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @obj3, align 8
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 1000
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
; CHECK: for.body:
; CHECK-NEXT: call void @unknown_call()
; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_0]] to i64
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i64 [[IDXPROM]]
; CHECK-NEXT: store ptr [[P:%.*]], ptr [[ARRAYIDX]], align 8
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INC]] = add nsw i32 [[I_0]], 1
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
entry:
call void @nocapture_nocallback_func(ptr @obj3)
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
%cmp = icmp slt i32 %i.0, 1000
br i1 %cmp, label %for.body, label %for.end
for.body: ; preds = %for.cond
%0 = load ptr, ptr @obj3, align 8
call void @unknown_call()
%idxprom = sext i32 %i.0 to i64
%arrayidx = getelementptr inbounds ptr, ptr %0, i64 %idxprom
store ptr %p, ptr %arrayidx, align 8
br label %for.inc
for.inc: ; preds = %for.body
%inc = add nsw i32 %i.0, 1
br label %for.cond
for.end: ; preds = %for.cond
ret void
}
define dso_local void @test4(ptr %p) {
; Check that load from @obj4 is not hoisted from the loop,
; because 'nocallback' is missing:
; CHECK-LABEL: @test4(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @nocapture_func(ptr @obj4)
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 1000
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @obj4, align 8
; CHECK-NEXT: call void @unknown_call()
; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_0]] to i64
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i64 [[IDXPROM]]
; CHECK-NEXT: store ptr [[P:%.*]], ptr [[ARRAYIDX]], align 8
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INC]] = add nsw i32 [[I_0]], 1
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
entry:
call void @nocapture_func(ptr @obj4)
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
%cmp = icmp slt i32 %i.0, 1000
br i1 %cmp, label %for.body, label %for.end
for.body: ; preds = %for.cond
%0 = load ptr, ptr @obj4, align 8
call void @unknown_call()
%idxprom = sext i32 %i.0 to i64
%arrayidx = getelementptr inbounds ptr, ptr %0, i64 %idxprom
store ptr %p, ptr %arrayidx, align 8
br label %for.inc
for.inc: ; preds = %for.body
%inc = add nsw i32 %i.0, 1
br label %for.cond
for.end: ; preds = %for.cond
ret void
}
define dso_local void @test5(ptr %p) {
; Check that load from @obj5 is not hoisted from the loop,
; because 'nocapture' is missing:
; CHECK-LABEL: @test5(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @nocallback_func(ptr @obj5)
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 1000
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @obj5, align 8
; CHECK-NEXT: call void @unknown_call()
; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_0]] to i64
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP0]], i64 [[IDXPROM]]
; CHECK-NEXT: store ptr [[P:%.*]], ptr [[ARRAYIDX]], align 8
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INC]] = add nsw i32 [[I_0]], 1
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
entry:
call void @nocallback_func(ptr @obj5)
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
%cmp = icmp slt i32 %i.0, 1000
br i1 %cmp, label %for.body, label %for.end
for.body: ; preds = %for.cond
%0 = load ptr, ptr @obj5, align 8
call void @unknown_call()
%idxprom = sext i32 %i.0 to i64
%arrayidx = getelementptr inbounds ptr, ptr %0, i64 %idxprom
store ptr %p, ptr %arrayidx, align 8
br label %for.inc
for.inc: ; preds = %for.body
%inc = add nsw i32 %i.0, 1
br label %for.cond
for.end: ; preds = %for.cond
ret void
}
declare void @nocapture_nocallback_func(ptr nocapture) nocallback
declare void @nocapture_func(ptr nocapture)
declare void @nocallback_func(ptr) nocallback
; nosync and nocallback are required, otherwise the call
; will by ModRef for any global:
declare void @unknown_call() nosync nocallback