328 lines
12 KiB
LLVM
328 lines
12 KiB
LLVM
; 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
|