diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:41:05 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:41:05 +0000 |
| commit | 01095a5d43bbfde13731688ddcf6048ebb8b7721 (patch) | |
| tree | 4def12e759965de927d963ac65840d663ef9d1ea /test/Transforms/LICM | |
| parent | f0f4822ed4b66e3579e92a89f368f8fb860e218e (diff) | |
Notes
Diffstat (limited to 'test/Transforms/LICM')
29 files changed, 745 insertions, 19 deletions
diff --git a/test/Transforms/LICM/AliasSetMemSet.ll b/test/Transforms/LICM/AliasSetMemSet.ll new file mode 100644 index 000000000000..d60b321e278e --- /dev/null +++ b/test/Transforms/LICM/AliasSetMemSet.ll @@ -0,0 +1,51 @@ +; RUN: opt < %s -loop-deletion -licm -loop-idiom -disable-output +; Check no assertion when loop-idiom deletes the MemSet already analyzed by licm +define void @set_array() { + br i1 false, label %bb3.preheader.lr.ph, label %bb9 + +bb3.preheader.lr.ph: ; preds = %0 + br label %bb3.preheader + +bb4: ; preds = %bb4.lr.ph, %bb7 + %j.3.06 = phi i8 [ %j.3.17, %bb4.lr.ph ], [ %_tmp13, %bb7 ] + br label %bb6 + +bb6: ; preds = %bb4, %bb6 + %k.4.04 = phi i8 [ 0, %bb4 ], [ %_tmp9, %bb6 ] + %_tmp31 = sext i8 %j.3.06 to i64 + %_tmp4 = mul i64 %_tmp31, 10 + %_tmp5 = getelementptr i8, i8* undef, i64 %_tmp4 + %_tmp7 = getelementptr i8, i8* %_tmp5, i8 %k.4.04 + store i8 42, i8* %_tmp7 + %_tmp9 = add i8 %k.4.04, 1 + %_tmp11 = icmp slt i8 %_tmp9, 10 + br i1 %_tmp11, label %bb6, label %bb7 + +bb7: ; preds = %bb6 + %_tmp13 = add i8 %j.3.06, 1 + %_tmp15 = icmp slt i8 %_tmp13, 2 + br i1 %_tmp15, label %bb4, label %bb3.bb1.loopexit_crit_edge + +bb3.bb1.loopexit_crit_edge: ; preds = %bb7 + %split = phi i8 [ %_tmp13, %bb7 ] + br label %bb1.loopexit + +bb1.loopexit: ; preds = %bb3.bb1.loopexit_crit_edge, %bb3.preheader + %j.3.0.lcssa = phi i8 [ %split, %bb3.bb1.loopexit_crit_edge ], [ %j.3.17, %bb3.preheader ] + br i1 false, label %bb3.preheader, label %bb1.bb9_crit_edge + +bb3.preheader: ; preds = %bb3.preheader.lr.ph, %bb1.loopexit + %j.3.17 = phi i8 [ undef, %bb3.preheader.lr.ph ], [ %j.3.0.lcssa, %bb1.loopexit ] + %_tmp155 = icmp slt i8 %j.3.17, 2 + br i1 %_tmp155, label %bb4.lr.ph, label %bb1.loopexit + +bb4.lr.ph: ; preds = %bb3.preheader + br label %bb4 + +bb1.bb9_crit_edge: ; preds = %bb1.loopexit + br label %bb9 + +bb9: ; preds = %bb1.bb9_crit_edge, %0 + ret void +} + diff --git a/test/Transforms/LICM/alias-set-tracker-loss.ll b/test/Transforms/LICM/alias-set-tracker-loss.ll new file mode 100644 index 000000000000..378d908f6987 --- /dev/null +++ b/test/Transforms/LICM/alias-set-tracker-loss.ll @@ -0,0 +1,39 @@ +; RUN: opt -S -licm -loop-unroll < %s +; +; This test contains a carefully rotated set of three nested loops. The middle +; loop can be unrolled leaving one copy of the inner loop inside the outer +; loop. Because of how LICM works, when this middle loop is unrolled and +; removed, its alias set tracker is destroyed and no longer available when LICM +; runs on the outer loop. + +define void @f() { +entry: + br label %l1 + +l2.l1.loopexit_crit_edge: + br label %l1.loopexit + +l1.loopexit: + br label %l1.backedge + +l1: + br i1 undef, label %l1.backedge, label %l2.preheader + +l1.backedge: + br label %l1 + +l2.preheader: + br i1 true, label %l1.loopexit, label %l3.preheader.lr.ph + +l3.preheader.lr.ph: + br label %l3.preheader + +l2.loopexit: + br i1 true, label %l2.l1.loopexit_crit_edge, label %l3.preheader + +l3.preheader: + br label %l3 + +l3: + br i1 true, label %l3, label %l2.loopexit +} diff --git a/test/Transforms/LICM/argmemonly-call.ll b/test/Transforms/LICM/argmemonly-call.ll index e2640a1c8deb..18d7f8351dca 100644 --- a/test/Transforms/LICM/argmemonly-call.ll +++ b/test/Transforms/LICM/argmemonly-call.ll @@ -1,4 +1,5 @@ ; RUN: opt -S -basicaa -licm %s | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' < %s -S | FileCheck %s declare i32 @foo() readonly argmemonly nounwind declare i32 @foo2() readonly nounwind declare i32 @bar(i32* %loc2) readonly argmemonly nounwind diff --git a/test/Transforms/LICM/assume.ll b/test/Transforms/LICM/assume.ll new file mode 100644 index 000000000000..f6369ac659f0 --- /dev/null +++ b/test/Transforms/LICM/assume.ll @@ -0,0 +1,52 @@ +; RUN: opt -licm -basicaa < %s -S | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' < %s -S | FileCheck %s + +define void @f_0(i1 %p) nounwind ssp { +; CHECK-LABEL: @f_0( +entry: + br label %for.body + +for.body: + br i1 undef, label %if.then, label %for.cond.backedge + +for.cond.backedge: + br i1 undef, label %for.end104, label %for.body + +if.then: + br i1 undef, label %if.then27, label %if.end.if.end.split_crit_edge.critedge + +if.then27: +; CHECK: tail call void @llvm.assume + tail call void @llvm.assume(i1 %p) + br label %for.body61.us + +if.end.if.end.split_crit_edge.critedge: + br label %for.body61 + +for.body61.us: + br i1 undef, label %for.cond.backedge, label %for.body61.us + +for.body61: + br i1 undef, label %for.cond.backedge, label %for.body61 + +for.end104: + ret void +} + +define void @f_1(i1 %cond, i32* %ptr) { +; CHECK-LABEL: @f_1( +; CHECK: %val = load i32, i32* %ptr +; CHECK-NEXT: br label %loop + +entry: + br label %loop + +loop: + %x = phi i32 [ 0, %entry ], [ %x.inc, %loop ] + call void @llvm.assume(i1 %cond) + %val = load i32, i32* %ptr + %x.inc = add i32 %x, %val + br label %loop +} + +declare void @llvm.assume(i1) diff --git a/test/Transforms/LICM/atomics.ll b/test/Transforms/LICM/atomics.ll index 4fe197abf5d3..5dcd4bb8c05a 100644 --- a/test/Transforms/LICM/atomics.ll +++ b/test/Transforms/LICM/atomics.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -S -basicaa -licm | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='lcssa,require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' < %s -S | FileCheck %s ; Check that we can hoist unordered loads define i32 @test1(i32* nocapture %y) nounwind uwtable ssp { diff --git a/test/Transforms/LICM/basictest.ll b/test/Transforms/LICM/basictest.ll index 1dbb4dc6b499..570e226d2372 100644 --- a/test/Transforms/LICM/basictest.ll +++ b/test/Transforms/LICM/basictest.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -licm | llvm-dis +; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' < %s | llvm-dis define void @testfunc(i32 %i) { ; <label>:0 diff --git a/test/Transforms/LICM/constexpr.ll b/test/Transforms/LICM/constexpr.ll index 506721f25f8f..726246776dc6 100644 --- a/test/Transforms/LICM/constexpr.ll +++ b/test/Transforms/LICM/constexpr.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -S -basicaa -licm | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='lcssa,require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' < %s -S | FileCheck %s ; This fixes PR22460 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/test/Transforms/LICM/crash.ll b/test/Transforms/LICM/crash.ll index 7fa41157338d..75c27b8def0c 100644 --- a/test/Transforms/LICM/crash.ll +++ b/test/Transforms/LICM/crash.ll @@ -1,4 +1,5 @@ ; RUN: opt -licm -disable-output < %s +; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' -disable-output < %s target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" target triple = "x86_64-apple-darwin10.0.0" diff --git a/test/Transforms/LICM/debug-value.ll b/test/Transforms/LICM/debug-value.ll index d8ae5e576641..ab77caa2bae0 100644 --- a/test/Transforms/LICM/debug-value.ll +++ b/test/Transforms/LICM/debug-value.ll @@ -1,4 +1,5 @@ ; RUN: opt -licm -basicaa < %s -S | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' < %s -S | FileCheck %s define void @dgefa() nounwind ssp { entry: @@ -34,19 +35,18 @@ for.end104: ; preds = %for.cond.backedge declare void @llvm.dbg.value(metadata, i64, metadata, metadata) nounwind readnone !llvm.module.flags = !{!26} -!llvm.dbg.sp = !{!0, !6, !9, !10} +!llvm.dbg.cu = !{!2} -!0 = distinct !DISubprogram(name: "idamax", line: 112, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, file: !25, scope: !1, type: !3) +!0 = distinct !DISubprogram(name: "idamax", line: 112, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !2, file: !25, scope: !1, type: !3) !1 = !DIFile(filename: "/Volumes/Lalgate/work/llvm/projects/llvm-test/SingleSource/Benchmarks/CoyoteBench/lpbench.c", directory: "/private/tmp") -!2 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 2.9 (trunk 127169)", isOptimized: true, emissionKind: 0, file: !25, enums: !8, retainedTypes: !8, subprograms: !8) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 2.9 (trunk 127169)", isOptimized: true, emissionKind: FullDebug, file: !25) !3 = !DISubroutineType(types: !4) !4 = !{!5} !5 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed) -!6 = distinct !DISubprogram(name: "dscal", line: 206, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, file: !25, scope: !1, type: !7) -!7 = !DISubroutineType(types: !8) -!8 = !{null} -!9 = distinct !DISubprogram(name: "daxpy", line: 230, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, file: !25, scope: !1, type: !7) -!10 = distinct !DISubprogram(name: "dgefa", line: 267, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, file: !25, scope: !1, type: !7) +!6 = distinct !DISubprogram(name: "dscal", line: 206, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !2, file: !25, scope: !1, type: !7) +!7 = !DISubroutineType(types: !{null}) +!9 = distinct !DISubprogram(name: "daxpy", line: 230, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !2, file: !25, scope: !1, type: !7) +!10 = distinct !DISubprogram(name: "dgefa", line: 267, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !2, file: !25, scope: !1, type: !7) !11 = !DILocation(line: 281, column: 9, scope: !12) !12 = distinct !DILexicalBlock(line: 272, column: 5, file: !25, scope: !13) !13 = distinct !DILexicalBlock(line: 271, column: 5, file: !25, scope: !14) diff --git a/test/Transforms/LICM/extra-copies.ll b/test/Transforms/LICM/extra-copies.ll index ef52f9f404c1..84a3bc9ec6a6 100644 --- a/test/Transforms/LICM/extra-copies.ll +++ b/test/Transforms/LICM/extra-copies.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -licm -S | FileCheck %s +; RUN: opt -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' < %s -S | FileCheck %s ; PR19835 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/test/Transforms/LICM/funclet.ll b/test/Transforms/LICM/funclet.ll index ef4be2969151..9bdc6dbcde88 100644 --- a/test/Transforms/LICM/funclet.ll +++ b/test/Transforms/LICM/funclet.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -licm -S | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' < %s -S | FileCheck %s target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" target triple = "i386-pc-windows-msvc18.0.0" diff --git a/test/Transforms/LICM/hoist-bitcast-load.ll b/test/Transforms/LICM/hoist-bitcast-load.ll index 47c474c17dde..5752aecde387 100644 --- a/test/Transforms/LICM/hoist-bitcast-load.ll +++ b/test/Transforms/LICM/hoist-bitcast-load.ll @@ -1,4 +1,5 @@ ; RUN: opt -S -basicaa -licm < %s | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='loop-simplify,require<aa>,require<targetir>,require<scalar-evolution>,loop(simplify-cfg,licm)' -S < %s | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/test/Transforms/LICM/hoist-deref-load.ll b/test/Transforms/LICM/hoist-deref-load.ll index fd10c5d7503d..ed6ec7694d3c 100644 --- a/test/Transforms/LICM/hoist-deref-load.ll +++ b/test/Transforms/LICM/hoist-deref-load.ll @@ -1,4 +1,5 @@ ; RUN: opt -S -basicaa -licm < %s | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='loop-simplify,require<aa>,require<targetir>,require<scalar-evolution>,loop(simplify-cfg,licm)' -S < %s | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" @@ -432,5 +433,127 @@ for.end: ; preds = %for.inc, %entry ret void } +define void @test11(i32* noalias %a, i32* %b, i32** dereferenceable(8) %cptr, i32 %n) #0 { +; CHECK-LABEL: @test11( +entry: + %cmp11 = icmp sgt i32 %n, 0 + br i1 %cmp11, label %for.body, label %for.end + +; CHECK: for.body.preheader: +; CHECK: %c = load i32*, i32** %cptr, !dereferenceable !0 +; CHECK: %d = load i32, i32* %c, align 4 + + +for.body: ; preds = %entry, %for.inc + %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ] + %arrayidx = getelementptr inbounds i32, i32* %a, i64 %indvars.iv + %0 = load i32, i32* %arrayidx, align 4 + %cmp1 = icmp sgt i32 %0, 0 + %c = load i32*, i32** %cptr, !dereferenceable !0 + br i1 %cmp1, label %if.then, label %for.inc + +if.then: ; preds = %for.body + %d = load i32, i32* %c, align 4 + %arrayidx3 = getelementptr inbounds i32, i32* %b, i64 %indvars.iv + %e = load i32, i32* %arrayidx3, align 4 + %mul = mul nsw i32 %e, %d + store i32 %mul, i32* %arrayidx, align 4 + br label %for.inc + +for.inc: ; preds = %for.body, %if.then + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %lftr.wideiv = trunc i64 %indvars.iv.next to i32 + %exitcond = icmp eq i32 %lftr.wideiv, %n + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.inc, %entry + ret void +} + +declare void @llvm.experimental.guard(i1, ...) + +define void @test12(i32* noalias %a, i32* %b, i32* dereferenceable_or_null(4) %c, i32 %n) #0 { +; Prove non-null ness of %c via a guard, not a branch. + +; CHECK-LABEL: @test12( +entry: + %not_null = icmp ne i32* %c, null + call void(i1, ...) @llvm.experimental.guard(i1 %not_null) [ "deopt"() ] + %cmp11 = icmp sgt i32 %n, 0 + br i1 %cmp11, label %for.body, label %for.end + +; CHECK: for.body.preheader: +; CHECK-NEXT: [[VAL:%[^ ]]] = load i32, i32* %c, align 4 +; CHECK-NEXT: br label %for.body + + +for.body: ; preds = %entry, %for.inc + %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ] + %arrayidx = getelementptr inbounds i32, i32* %a, i64 %indvars.iv + %0 = load i32, i32* %arrayidx, align 4 + %cmp1 = icmp sgt i32 %0, 0 + br i1 %cmp1, label %if.then, label %for.inc + +if.then: ; preds = %for.body + %1 = load i32, i32* %c, align 4 + %arrayidx3 = getelementptr inbounds i32, i32* %b, i64 %indvars.iv + %2 = load i32, i32* %arrayidx3, align 4 + %mul = mul nsw i32 %2, %1 + store i32 %mul, i32* %arrayidx, align 4 + br label %for.inc + +for.inc: ; preds = %for.body, %if.then + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %lftr.wideiv = trunc i64 %indvars.iv.next to i32 + %exitcond = icmp eq i32 %lftr.wideiv, %n + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.inc, %entry, %entry + ret void +} + +define void @test13(i32* noalias %a, i32* %b, i32* dereferenceable_or_null(4) %c, i32 %n) #0 { +; Like @test12, but has a post-dominating guard, which cannot be used +; to prove %c is nonnull at the point of the load. + +; CHECK-LABEL: @test13( +entry: + %not_null = icmp ne i32* %c, null + %cmp11 = icmp sgt i32 %n, 0 + br i1 %cmp11, label %for.body, label %for.end + +; CHECK: for.body.preheader: +; CHECK-NOT: load i32, i32* %c +; CHECK: br label %for.body + +for.body: ; preds = %entry, %for.inc + %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ] + %arrayidx = getelementptr inbounds i32, i32* %a, i64 %indvars.iv + %0 = load i32, i32* %arrayidx, align 4 + %cmp1 = icmp sgt i32 %0, 0 + br i1 %cmp1, label %if.then, label %for.inc + +if.then: ; preds = %for.body +; CHECK: if.then: +; CHECK: load i32, i32* %c +; CHECK: br label %for.inc + %1 = load i32, i32* %c, align 4 + %arrayidx3 = getelementptr inbounds i32, i32* %b, i64 %indvars.iv + %2 = load i32, i32* %arrayidx3, align 4 + %mul = mul nsw i32 %2, %1 + store i32 %mul, i32* %arrayidx, align 4 + br label %for.inc + +for.inc: ; preds = %for.body, %if.then + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %lftr.wideiv = trunc i64 %indvars.iv.next to i32 + %exitcond = icmp eq i32 %lftr.wideiv, %n + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.inc, %entry, %entry + call void(i1, ...) @llvm.experimental.guard(i1 %not_null) [ "deopt"() ] + ret void +} + attributes #0 = { nounwind uwtable } !0 = !{i64 4} diff --git a/test/Transforms/LICM/hoist-nounwind.ll b/test/Transforms/LICM/hoist-nounwind.ll new file mode 100644 index 000000000000..081729f808bf --- /dev/null +++ b/test/Transforms/LICM/hoist-nounwind.ll @@ -0,0 +1,72 @@ +; RUN: opt -S -basicaa -licm < %s | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='lcssa,require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' -S %s | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @f() nounwind + +; Don't hoist load past nounwind call. +define i32 @test1(i32* noalias nocapture readonly %a) nounwind uwtable { +; CHECK-LABEL: @test1( +entry: + br label %for.body + +; CHECK: tail call void @f() +; CHECK-NEXT: load i32 +for.body: + %i.06 = phi i32 [ 0, %entry ], [ %inc, %for.body ] + %x.05 = phi i32 [ 0, %entry ], [ %add, %for.body ] + tail call void @f() nounwind + %i1 = load i32, i32* %a, align 4 + %add = add nsw i32 %i1, %x.05 + %inc = add nuw nsw i32 %i.06, 1 + %exitcond = icmp eq i32 %inc, 1000 + br i1 %exitcond, label %for.cond.cleanup, label %for.body + +for.cond.cleanup: + ret i32 %add +} + +; Don't hoist division past nounwind call. +define i32 @test2(i32 %N, i32 %c) nounwind uwtable { +; CHECK-LABEL: @test2( +entry: + %cmp4 = icmp sgt i32 %N, 0 + br i1 %cmp4, label %for.body, label %for.cond.cleanup + +; CHECK: tail call void @f() +; CHECK-NEXT: sdiv i32 +for.body: + %i.05 = phi i32 [ %inc, %for.body ], [ 0, %entry ] + tail call void @f() nounwind + %div = sdiv i32 5, %c + %add = add i32 %i.05, 1 + %inc = add i32 %add, %div + %cmp = icmp slt i32 %inc, %N + br i1 %cmp, label %for.body, label %for.cond.cleanup + +for.cond.cleanup: + ret i32 0 +} + +; Don't hoist load past volatile load. +define i32 @test3(i32* noalias nocapture readonly %a, i32* %v) nounwind uwtable { +; CHECK-LABEL: @test3( +entry: + br label %for.body + +; CHECK: load volatile i32 +; CHECK-NEXT: load i32 +for.body: + %i.06 = phi i32 [ 0, %entry ], [ %inc, %for.body ] + %x.05 = phi i32 [ 0, %entry ], [ %add, %for.body ] + %xxx = load volatile i32, i32* %v, align 4 + %i1 = load i32, i32* %a, align 4 + %add = add nsw i32 %i1, %x.05 + %inc = add nuw nsw i32 %i.06, 1 + %exitcond = icmp eq i32 %inc, 1000 + br i1 %exitcond, label %for.cond.cleanup, label %for.body + +for.cond.cleanup: + ret i32 %add +} diff --git a/test/Transforms/LICM/hoist-round.ll b/test/Transforms/LICM/hoist-round.ll new file mode 100644 index 000000000000..a87709b810d2 --- /dev/null +++ b/test/Transforms/LICM/hoist-round.ll @@ -0,0 +1,62 @@ +; RUN: opt -S -licm < %s | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' -S %s | FileCheck %s + +target datalayout = "E-m:e-p:32:32-i8:8:8-i16:16:16-i64:32:32-f64:32:32-v64:32:32-v128:32:32-a0:0:32-n32" + +; This test verifies that ceil, floor, nearbyint, trunc, rint, round, +; copysign, minnum, maxnum and fabs intrinsics are considered safe +; to speculate. + +; CHECK-LABEL: @test +; CHECK: call float @llvm.ceil.f32 +; CHECK: call float @llvm.floor.f32 +; CHECK: call float @llvm.nearbyint.f32 +; CHECK: call float @llvm.rint.f32 +; CHECK: call float @llvm.round.f32 +; CHECK: call float @llvm.trunc.f32 +; CHECK: call float @llvm.fabs.f32 +; CHECK: call float @llvm.copysign.f32 +; CHECK: call float @llvm.minnum.f32 +; CHECK: call float @llvm.maxnum.f32 +; CHECK: for.body: + +define void @test(float %arg1, float %arg2) { +entry: + br label %for.head + +for.head: + %IND = phi i32 [ 0, %entry ], [ %IND.new, %for.body ] + %CMP = icmp slt i32 %IND, 10 + br i1 %CMP, label %for.body, label %exit + +for.body: + %tmp.1 = call float @llvm.ceil.f32(float %arg1) + %tmp.2 = call float @llvm.floor.f32(float %tmp.1) + %tmp.3 = call float @llvm.nearbyint.f32(float %tmp.2) + %tmp.4 = call float @llvm.rint.f32(float %tmp.3) + %tmp.5 = call float @llvm.round.f32(float %tmp.4) + %tmp.6 = call float @llvm.trunc.f32(float %tmp.5) + %tmp.7 = call float @llvm.fabs.f32(float %tmp.6) + %tmp.8 = call float @llvm.copysign.f32(float %tmp.7, float %arg2) + %tmp.9 = call float @llvm.minnum.f32(float %tmp.8, float %arg2) + %tmp.10 = call float @llvm.maxnum.f32(float %tmp.9, float %arg2) + call void @consume(float %tmp.10) + %IND.new = add i32 %IND, 1 + br label %for.head + +exit: + ret void +} + +declare void @consume(float) + +declare float @llvm.ceil.f32(float) +declare float @llvm.floor.f32(float) +declare float @llvm.nearbyint.f32(float) +declare float @llvm.rint.f32(float) +declare float @llvm.round.f32(float) +declare float @llvm.trunc.f32(float) +declare float @llvm.fabs.f32(float) +declare float @llvm.copysign.f32(float, float) +declare float @llvm.minnum.f32(float, float) +declare float @llvm.maxnum.f32(float, float) diff --git a/test/Transforms/LICM/hoisting.ll b/test/Transforms/LICM/hoisting.ll index 8609407cc599..cb6981ede1e7 100644 --- a/test/Transforms/LICM/hoisting.ll +++ b/test/Transforms/LICM/hoisting.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -licm -S | FileCheck %s +; RUN: opt -lcssa %s | opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' -S | FileCheck %s @X = global i32 0 ; <i32*> [#uses=1] @@ -37,16 +38,21 @@ define i32 @test2(i1 %c) { ; CHECK-LABEL: @test2( ; CHECK-NEXT: load i32, i32* @X ; CHECK-NEXT: %B = sdiv i32 4, %A - %A = load i32, i32* @X ; <i32> [#uses=2] - br label %Loop + %A = load i32, i32* @X + br label %Loop + Loop: - ;; Should have hoisted this div! - %B = sdiv i32 4, %A ; <i32> [#uses=2] - call void @foo2( i32 %B ) - br i1 %c, label %Loop, label %Out -Out: ; preds = %Loop - %C = sub i32 %A, %B ; <i32> [#uses=1] - ret i32 %C + ;; Should have hoisted this div! + %B = sdiv i32 4, %A + br label %loop2 + +loop2: + call void @foo2( i32 %B ) + br i1 %c, label %Loop, label %Out + +Out: + %C = sub i32 %A, %B + ret i32 %C } diff --git a/test/Transforms/LICM/lcssa-ssa-promoter.ll b/test/Transforms/LICM/lcssa-ssa-promoter.ll index b0cae8772f3e..d466b3baffc8 100644 --- a/test/Transforms/LICM/lcssa-ssa-promoter.ll +++ b/test/Transforms/LICM/lcssa-ssa-promoter.ll @@ -1,4 +1,5 @@ ; RUN: opt -S -basicaa -licm < %s | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' -S %s| FileCheck %s ; ; Manually validate LCSSA form is preserved even after SSAUpdater is used to ; promote things in the loop bodies. diff --git a/test/Transforms/LICM/no-preheader-test.ll b/test/Transforms/LICM/no-preheader-test.ll index bd3eea38ef3e..4b6847cdad51 100644 --- a/test/Transforms/LICM/no-preheader-test.ll +++ b/test/Transforms/LICM/no-preheader-test.ll @@ -1,5 +1,6 @@ ; Test that LICM works when there is not a loop-preheader ; RUN: opt < %s -licm | llvm-dis +; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' < %s | llvm-dis define void @testfunc(i32 %i.s, i1 %ifcond) { br i1 %ifcond, label %Then, label %Else diff --git a/test/Transforms/LICM/pr26843.ll b/test/Transforms/LICM/pr26843.ll new file mode 100644 index 000000000000..a14acbef964f --- /dev/null +++ b/test/Transforms/LICM/pr26843.ll @@ -0,0 +1,32 @@ +; RUN: opt -S -basicaa -licm < %s | FileCheck %s + +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i686-pc-windows-msvc18.0.0" + +@v = common global i32 zeroinitializer, align 4 + +; Make sure the store to v is not sunk past the memset +; CHECK-LABEL: @main +; CHECK: for.body: +; CHECK-NEXT: store i32 1, i32* @v +; CHECK-NEXT: tail call void @llvm.memset +; CHECK: end: +; CHECK-NEXT: ret i32 0 + +define i32 @main(i1 %k) { +entry: + br label %for.body + +for.body: + store i32 1, i32* @v, align 4 + tail call void @llvm.memset.p0i8.i32(i8* bitcast (i32* @v to i8*), i8 0, i32 4, i32 4, i1 false) + br label %for.latch + +for.latch: + br i1 %k, label %for.body, label %end + +end: + ret i32 0 +} + +declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i32, i1) diff --git a/test/Transforms/LICM/pr27262.ll b/test/Transforms/LICM/pr27262.ll new file mode 100644 index 000000000000..5fc6d9389e0d --- /dev/null +++ b/test/Transforms/LICM/pr27262.ll @@ -0,0 +1,33 @@ +; RUN: opt -S -basicaa -licm < %s | FileCheck %s + +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i686-pc-windows-msvc18.0.0" + +; Make sure the store to v is not sunk past the memset +; CHECK-LABEL: @main +; CHECK: for.body: +; CHECK-NEXT: store i8 1, i8* %p +; CHECK-NEXT: store i8 2, i8* %p1 +; CHECK-NEXT: call void @llvm.memset +; CHECK: end: +; CHECK-NEXT: ret i32 0 + +define i32 @main(i1 %k, i8* %p) { +entry: + %p1 = getelementptr i8, i8* %p, i32 1 + br label %for.body + +for.body: + store i8 1, i8* %p, align 1 + store i8 2, i8* %p1, align 1 + call void @llvm.memset.p0i8.i32(i8* %p, i8 255, i32 4, i32 1, i1 false) + br label %for.latch + +for.latch: + br i1 %k, label %for.body, label %end + +end: + ret i32 0 +} + +declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i32, i1) diff --git a/test/Transforms/LICM/preheader-safe.ll b/test/Transforms/LICM/preheader-safe.ll index 260a5f653b77..adc4f4237a29 100644 --- a/test/Transforms/LICM/preheader-safe.ll +++ b/test/Transforms/LICM/preheader-safe.ll @@ -1,4 +1,5 @@ ; RUN: opt -S -licm < %s | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' -S %s | FileCheck %s declare void @use_nothrow(i64 %a) nounwind declare void @use(i64 %a) @@ -14,6 +15,9 @@ entry: loop: ; preds = %entry, %for.inc %div = udiv i64 %x, %y + br label %loop2 + +loop2: call void @use_nothrow(i64 %div) br label %loop } diff --git a/test/Transforms/LICM/promote-order.ll b/test/Transforms/LICM/promote-order.ll index a189cf22f66b..7d87bb221b76 100644 --- a/test/Transforms/LICM/promote-order.ll +++ b/test/Transforms/LICM/promote-order.ll @@ -1,4 +1,5 @@ ; RUN: opt -tbaa -basicaa -licm -S < %s | FileCheck %s +; RUN: opt -aa-pipeline=type-based-aa,basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' -S %s | FileCheck %s ; LICM should keep the stores in their original order when it sinks/promotes them. ; rdar://12045203 diff --git a/test/Transforms/LICM/promote-tls.ll b/test/Transforms/LICM/promote-tls.ll new file mode 100644 index 000000000000..e3654902a124 --- /dev/null +++ b/test/Transforms/LICM/promote-tls.ll @@ -0,0 +1,134 @@ +; RUN: opt -tbaa -basicaa -licm -S < %s | FileCheck %s +; RUN: opt -aa-pipeline=type-based-aa,basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' -S %s | FileCheck %s + +; If we can prove a local is thread local, we can insert stores during +; promotion which wouldn't be legal otherwise. + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-linux-generic" + +@p = external global i8* + +declare i8* @malloc(i64) + +; Exercise the TLS case +define i32* @test(i32 %n) { +entry: + ;; ignore the required null check for simplicity + %mem = call dereferenceable(16) noalias i8* @malloc(i64 16) + %addr = bitcast i8* %mem to i32* + br label %for.body.lr.ph + +for.body.lr.ph: ; preds = %entry + br label %for.header + +for.header: + %i.02 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.body ] + %old = load i32, i32* %addr, align 4 + ; deliberate impossible to analyze branch + %guard = load atomic i8*, i8** @p monotonic, align 8 + %exitcmp = icmp eq i8* %guard, null + br i1 %exitcmp, label %for.body, label %early-exit + +early-exit: +; CHECK-LABEL: early-exit: +; CHECK: store i32 %new1.lcssa, i32* %addr, align 1 + ret i32* null + +for.body: + %new = add i32 %old, 1 + store i32 %new, i32* %addr, align 4 + %inc = add nsw i32 %i.02, 1 + %cmp = icmp slt i32 %inc, %n + br i1 %cmp, label %for.header, label %for.cond.for.end_crit_edge + +for.cond.for.end_crit_edge: ; preds = %for.body +; CHECK-LABEL: for.cond.for.end_crit_edge: +; CHECK: store i32 %new.lcssa, i32* %addr, align 1 + %split = phi i32* [ %addr, %for.body ] + ret i32* null +} + +declare i8* @not_malloc(i64) + +; Negative test - not TLS +define i32* @test_neg(i32 %n) { +entry: + ;; ignore the required null check for simplicity + %mem = call dereferenceable(16) noalias i8* @not_malloc(i64 16) + %addr = bitcast i8* %mem to i32* + br label %for.body.lr.ph + +for.body.lr.ph: ; preds = %entry + br label %for.header + +for.header: + %i.02 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.body ] + %old = load i32, i32* %addr, align 4 + ; deliberate impossible to analyze branch + %guard = load volatile i8*, i8** @p + %exitcmp = icmp eq i8* %guard, null + br i1 %exitcmp, label %for.body, label %early-exit + +early-exit: +; CHECK-LABEL: early-exit: +; CHECK-NOT: store + ret i32* null + +for.body: +; CHECK-LABEL: for.body: +; CHECK: store i32 %new, i32* %addr, align 4 + %new = add i32 %old, 1 + store i32 %new, i32* %addr, align 4 + %inc = add nsw i32 %i.02, 1 + %cmp = icmp slt i32 %inc, %n + br i1 %cmp, label %for.header, label %for.cond.for.end_crit_edge + +for.cond.for.end_crit_edge: ; preds = %for.body +; CHECK-LABEL: for.cond.for.end_crit_edge: +; CHECK-NOT: store + %split = phi i32* [ %addr, %for.body ] + ret i32* null +} + +; Negative test - can't speculate load since branch +; may control alignment +define i32* @test_neg2(i32 %n) { +entry: + ;; ignore the required null check for simplicity + %mem = call dereferenceable(16) noalias i8* @malloc(i64 16) + %addr = bitcast i8* %mem to i32* + br label %for.body.lr.ph + +for.body.lr.ph: ; preds = %entry + br label %for.header + +for.header: + %i.02 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.body ] + ; deliberate impossible to analyze branch + %guard = load volatile i8*, i8** @p + %exitcmp = icmp eq i8* %guard, null + br i1 %exitcmp, label %for.body, label %early-exit + +early-exit: +; CHECK-LABEL: early-exit: +; CHECK-NOT: store + ret i32* null + +for.body: +; CHECK-LABEL: for.body: +; CHECK: store i32 %new, i32* %addr, align 4 + %old = load i32, i32* %addr, align 4 + %new = add i32 %old, 1 + store i32 %new, i32* %addr, align 4 + %inc = add nsw i32 %i.02, 1 + %cmp = icmp slt i32 %inc, %n + br i1 %cmp, label %for.header, label %for.cond.for.end_crit_edge + +for.cond.for.end_crit_edge: ; preds = %for.body +; CHECK-LABEL: for.cond.for.end_crit_edge: +; CHECK-NOT: store + %split = phi i32* [ %addr, %for.body ] + ret i32* null +} + diff --git a/test/Transforms/LICM/scalar-promote-memmodel.ll b/test/Transforms/LICM/scalar-promote-memmodel.ll index 3603c25ba23c..ceee7292ac5c 100644 --- a/test/Transforms/LICM/scalar-promote-memmodel.ll +++ b/test/Transforms/LICM/scalar-promote-memmodel.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -basicaa -licm -S | FileCheck %s +; RUN: opt -aa-pipeline=type-based-aa,basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' -S %s | FileCheck %s ; Make sure we don't hoist a conditionally-executed store out of the loop; ; it would violate the concurrency memory model diff --git a/test/Transforms/LICM/scalar_promote-unwind.ll b/test/Transforms/LICM/scalar_promote-unwind.ll new file mode 100644 index 000000000000..22e7e50c22e5 --- /dev/null +++ b/test/Transforms/LICM/scalar_promote-unwind.ll @@ -0,0 +1,72 @@ +; RUN: opt < %s -basicaa -licm -S | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' -S %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Make sure we don't hoist the store out of the loop; %a would +; have the wrong value if f() unwinds + +define void @test1(i32* nocapture noalias %a, i1 zeroext %y) uwtable { +entry: + br label %for.body + +for.body: + %i.03 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] + %0 = load i32, i32* %a, align 4 + %add = add nsw i32 %0, 1 + store i32 %add, i32* %a, align 4 + br i1 %y, label %if.then, label %for.inc + +; CHECK: define void @test1 +; CHECK: load i32, i32* +; CHECK-NEXT: add +; CHECK-NEXT: store i32 + +if.then: + tail call void @f() + br label %for.inc + +for.inc: + %inc = add nuw nsw i32 %i.03, 1 + %exitcond = icmp eq i32 %inc, 10000 + br i1 %exitcond, label %for.cond.cleanup, label %for.body + +for.cond.cleanup: + ret void +} + +; We can hoist the store out of the loop here; if f() unwinds, +; the lifetime of %a ends. + +define void @test2(i1 zeroext %y) uwtable { +entry: + %a = alloca i32 + br label %for.body + +for.body: + %i.03 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] + %0 = load i32, i32* %a, align 4 + %add = add nsw i32 %0, 1 + store i32 %add, i32* %a, align 4 + br i1 %y, label %if.then, label %for.inc + +if.then: + tail call void @f() + br label %for.inc + +for.inc: + %inc = add nuw nsw i32 %i.03, 1 + %exitcond = icmp eq i32 %inc, 10000 + br i1 %exitcond, label %for.cond.cleanup, label %for.body + +for.cond.cleanup: + ret void + +; CHECK: define void @test2 +; CHECK: store i32 +; CHECK-NEXT: ret void + ret void +} + +declare void @f() uwtable diff --git a/test/Transforms/LICM/scalar_promote.ll b/test/Transforms/LICM/scalar_promote.ll index 6ef4bac39bbc..91cdbdbc2269 100644 --- a/test/Transforms/LICM/scalar_promote.ll +++ b/test/Transforms/LICM/scalar_promote.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -basicaa -tbaa -licm -S | FileCheck %s +; RUN: opt -aa-pipeline=type-based-aa,basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' -S %s | FileCheck %s target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" @X = global i32 7 ; <i32*> [#uses=4] @@ -135,7 +136,7 @@ Loop: ; preds = %Loop, %0 %x2 = add i32 %x, 1 ; <i32> [#uses=1] store i32 %x2, i32* @X - store volatile i32* @X, i32** %P2 + store atomic i32* @X, i32** %P2 monotonic, align 8 %Next = add i32 %j, 1 ; <i32> [#uses=2] %cond = icmp eq i32 %Next, 0 ; <i1> [#uses=1] diff --git a/test/Transforms/LICM/speculate.ll b/test/Transforms/LICM/speculate.ll index 91b5a25ac0f5..fed1cbaa8555 100644 --- a/test/Transforms/LICM/speculate.ll +++ b/test/Transforms/LICM/speculate.ll @@ -1,4 +1,5 @@ ; RUN: opt -S -licm < %s | FileCheck %s +; RUN: opt -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' -S %s | FileCheck %s ; UDiv is safe to speculate if the denominator is known non-zero. diff --git a/test/Transforms/LICM/update-scev.ll b/test/Transforms/LICM/update-scev.ll new file mode 100644 index 000000000000..221c124c8bf1 --- /dev/null +++ b/test/Transforms/LICM/update-scev.ll @@ -0,0 +1,31 @@ +; RUN: opt -S -licm < %s | FileCheck %s --check-prefix=IR-AFTER-TRANSFORM +; RUN: opt -analyze -scalar-evolution -licm -scalar-evolution < %s | FileCheck %s --check-prefix=SCEV-EXPRS + +declare void @clobber() + +define void @f_0(i1* %loc) { +; IR-AFTER-TRANSFORM-LABEL: @f_0( +; IR-AFTER-TRANSFORM: loop.outer: +; IR-AFTER-TRANSFORM-NEXT: call void @clobber() +; IR-AFTER-TRANSFORM-NEXT: %cond = load i1, i1* %loc +; IR-AFTER-TRANSFORM-NEXT: br label %loop.inner + +; SCEV-EXPRS: Classifying expressions for: @f_0 +; SCEV-EXPRS: Classifying expressions for: @f_0 +; SCEV-EXPRS: %cond = load i1, i1* %loc +; SCEV-EXPRS-NEXT: --> {{.*}} LoopDispositions: { %loop.outer: Variant, %loop.inner: Invariant } + +entry: + br label %loop.outer + +loop.outer: + call void @clobber() + br label %loop.inner + +loop.inner: + %cond = load i1, i1* %loc + br i1 %cond, label %loop.inner, label %leave.inner + +leave.inner: + br label %loop.outer +} diff --git a/test/Transforms/LICM/volatile-alias.ll b/test/Transforms/LICM/volatile-alias.ll index fda930df933b..7836df004c0f 100644 --- a/test/Transforms/LICM/volatile-alias.ll +++ b/test/Transforms/LICM/volatile-alias.ll @@ -1,4 +1,5 @@ ; RUN: opt -basicaa -sroa -loop-rotate -licm -S < %s | FileCheck %s +; RUN: opt -basicaa -sroa -loop-rotate %s | opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,loop(licm)' -S | FileCheck %s ; The objects *p and *q are aliased to each other, but even though *q is ; volatile, *p can be considered invariant in the loop. Check if it is moved ; out of the loop. @@ -9,7 +10,7 @@ target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" ; Function Attrs: nounwind uwtable -define i32 @foo(i32* %p, i32* %q, i32 %n) #0 { +define i32 @foo(i32* dereferenceable(4) nonnull %p, i32* %q, i32 %n) #0 { entry: %p.addr = alloca i32*, align 8 %q.addr = alloca i32*, align 8 |
