Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,193 @@
; RUN: opt < %s -gvn -enable-load-pre -disable-output
%struct.VEC_rtx_base = type { i32, i32, [1 x %struct.rtx_def*] }
%struct.VEC_rtx_gc = type { %struct.VEC_rtx_base }
%struct.block_symbol = type { [3 x %struct.cgraph_rtl_info], %struct.object_block*, i64 }
%struct.cgraph_rtl_info = type { i32 }
%struct.object_block = type { %struct.section*, i32, i64, %struct.VEC_rtx_gc*, %struct.VEC_rtx_gc* }
%struct.rtvec_def = type { i32, [1 x %struct.rtx_def*] }
%struct.rtx_def = type { i16, i8, i8, %struct.u }
%struct.section = type { %struct.unnamed_section }
%struct.u = type { %struct.block_symbol }
%struct.unnamed_section = type { %struct.cgraph_rtl_info, void (i8*)*, i8*, %struct.section* }
declare %struct.rtvec_def* @gen_rtvec(i32, ...)
declare %struct.rtx_def* @plus_constant(%struct.rtx_def*, i64)
declare %struct.rtx_def* @gen_rtx_fmt_Ei(i32, i32, %struct.rtvec_def*, i32)
declare i32 @local_symbolic_operand(%struct.rtx_def*, i32)
define %struct.rtx_def* @legitimize_pic_address(%struct.rtx_def* %orig, %struct.rtx_def* %reg) nounwind {
entry:
%addr = alloca %struct.rtx_def* ; <%struct.rtx_def**> [#uses=5]
%iftmp.1532 = alloca %struct.rtx_def* ; <%struct.rtx_def**> [#uses=3]
store %struct.rtx_def* %orig, %struct.rtx_def** null
%0 = load %struct.rtx_def*, %struct.rtx_def** null, align 4 ; <%struct.rtx_def*> [#uses=0]
br i1 false, label %bb96, label %bb59
bb59: ; preds = %entry
%1 = load %struct.rtx_def*, %struct.rtx_def** %addr, align 4 ; <%struct.rtx_def*> [#uses=1]
%2 = call i32 @local_symbolic_operand(%struct.rtx_def* %1, i32 0) nounwind ; <i32> [#uses=0]
br i1 false, label %bb96, label %bb63
bb63: ; preds = %bb59
br i1 false, label %bb64, label %bb74
bb64: ; preds = %bb63
br i1 false, label %bb72, label %bb65
bb65: ; preds = %bb64
br label %bb72
bb72: ; preds = %bb65, %bb64
br label %bb74
bb74: ; preds = %bb72, %bb63
br i1 false, label %bb75, label %bb76
bb75: ; preds = %bb74
br label %bb76
bb76: ; preds = %bb75, %bb74
br i1 false, label %bb77, label %bb84
bb77: ; preds = %bb76
%3 = getelementptr [1 x %struct.cgraph_rtl_info], [1 x %struct.cgraph_rtl_info]* null, i32 0, i32 0 ; <%struct.cgraph_rtl_info*> [#uses=0]
unreachable
bb84: ; preds = %bb76
br i1 false, label %bb85, label %bb86
bb85: ; preds = %bb84
br label %bb87
bb86: ; preds = %bb84
br label %bb87
bb87: ; preds = %bb86, %bb85
%4 = call %struct.rtx_def* @gen_rtx_fmt_Ei(i32 16, i32 0, %struct.rtvec_def* null, i32 1) nounwind ; <%struct.rtx_def*> [#uses=0]
br i1 false, label %bb89, label %bb90
bb89: ; preds = %bb87
br label %bb91
bb90: ; preds = %bb87
br label %bb91
bb91: ; preds = %bb90, %bb89
br i1 false, label %bb92, label %bb93
bb92: ; preds = %bb91
br label %bb94
bb93: ; preds = %bb91
br label %bb94
bb94: ; preds = %bb93, %bb92
unreachable
bb96: ; preds = %bb59, %entry
%5 = load %struct.rtx_def*, %struct.rtx_def** %addr, align 4 ; <%struct.rtx_def*> [#uses=1]
%6 = getelementptr %struct.rtx_def, %struct.rtx_def* %5, i32 0, i32 0 ; <i16*> [#uses=1]
%7 = load i16, i16* %6, align 2 ; <i16> [#uses=0]
br i1 false, label %bb147, label %bb97
bb97: ; preds = %bb96
%8 = load %struct.rtx_def*, %struct.rtx_def** %addr, align 4 ; <%struct.rtx_def*> [#uses=0]
br i1 false, label %bb147, label %bb99
bb99: ; preds = %bb97
unreachable
bb147: ; preds = %bb97, %bb96
%9 = load %struct.rtx_def*, %struct.rtx_def** %addr, align 4 ; <%struct.rtx_def*> [#uses=1]
%10 = getelementptr %struct.rtx_def, %struct.rtx_def* %9, i32 0, i32 0 ; <i16*> [#uses=1]
%11 = load i16, i16* %10, align 2 ; <i16> [#uses=0]
br i1 false, label %bb164, label %bb148
bb148: ; preds = %bb147
br i1 false, label %bb164, label %bb149
bb149: ; preds = %bb148
br i1 false, label %bb150, label %bb152
bb150: ; preds = %bb149
unreachable
bb152: ; preds = %bb149
br label %bb164
bb164: ; preds = %bb152, %bb148, %bb147
%12 = getelementptr [1 x %struct.cgraph_rtl_info], [1 x %struct.cgraph_rtl_info]* null, i32 0, i32 1 ; <%struct.cgraph_rtl_info*> [#uses=0]
br i1 false, label %bb165, label %bb166
bb165: ; preds = %bb164
br label %bb167
bb166: ; preds = %bb164
br label %bb167
bb167: ; preds = %bb166, %bb165
br i1 false, label %bb211, label %bb168
bb168: ; preds = %bb167
br i1 false, label %bb211, label %bb170
bb170: ; preds = %bb168
br i1 false, label %bb172, label %bb181
bb172: ; preds = %bb170
br i1 false, label %bb179, label %bb174
bb174: ; preds = %bb172
br i1 false, label %bb177, label %bb175
bb175: ; preds = %bb174
br i1 false, label %bb177, label %bb176
bb176: ; preds = %bb175
br label %bb178
bb177: ; preds = %bb175, %bb174
br label %bb178
bb178: ; preds = %bb177, %bb176
br label %bb180
bb179: ; preds = %bb172
br label %bb180
bb180: ; preds = %bb179, %bb178
br label %bb181
bb181: ; preds = %bb180, %bb170
%13 = call %struct.rtvec_def* (i32, ...) @gen_rtvec(i32 1, %struct.rtx_def* null) nounwind ; <%struct.rtvec_def*> [#uses=0]
unreachable
bb211: ; preds = %bb168, %bb167
%14 = load %struct.rtx_def*, %struct.rtx_def** %addr, align 4 ; <%struct.rtx_def*> [#uses=0]
%15 = getelementptr [1 x %struct.cgraph_rtl_info], [1 x %struct.cgraph_rtl_info]* null, i32 0, i32 0 ; <%struct.cgraph_rtl_info*> [#uses=0]
store %struct.rtx_def* null, %struct.rtx_def** null, align 4
br i1 false, label %bb212, label %bb213
bb212: ; preds = %bb211
store %struct.rtx_def* null, %struct.rtx_def** %iftmp.1532, align 4
br label %bb214
bb213: ; preds = %bb211
store %struct.rtx_def* null, %struct.rtx_def** %iftmp.1532, align 4
br label %bb214
bb214: ; preds = %bb213, %bb212
%16 = bitcast %struct.block_symbol* null to [1 x %struct.cgraph_rtl_info]* ; <[1 x %struct.cgraph_rtl_info]*> [#uses=1]
%17 = getelementptr [1 x %struct.cgraph_rtl_info], [1 x %struct.cgraph_rtl_info]* %16, i32 0, i32 1 ; <%struct.cgraph_rtl_info*> [#uses=0]
%18 = load %struct.rtx_def*, %struct.rtx_def** %iftmp.1532, align 4 ; <%struct.rtx_def*> [#uses=0]
%19 = getelementptr %struct.rtx_def, %struct.rtx_def* null, i32 0, i32 3 ; <%struct.u*> [#uses=1]
%20 = getelementptr %struct.u, %struct.u* %19, i32 0, i32 0 ; <%struct.block_symbol*> [#uses=1]
%21 = bitcast %struct.block_symbol* %20 to [1 x i64]* ; <[1 x i64]*> [#uses=1]
%22 = getelementptr [1 x i64], [1 x i64]* %21, i32 0, i32 0 ; <i64*> [#uses=0]
%23 = call %struct.rtx_def* @plus_constant(%struct.rtx_def* null, i64 0) nounwind ; <%struct.rtx_def*> [#uses=0]
unreachable
}

View File

@@ -0,0 +1,73 @@
; RUN: opt < %s -gvn -enable-load-pre -S | FileCheck %s
; CHECK-NOT: pre1
; GVN load pre was hoisting the loads at %13 and %16 up to bb4.outer.
; This is invalid as it bypasses the check for %m.0.ph==null in bb4.
; ModuleID = 'mbuf.c'
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
target triple = "i386-apple-darwin9.6"
%struct.mbuf = type { %struct.mbuf*, %struct.mbuf*, i32, i8*, i16, i16, i32 }
define void @m_adj(%struct.mbuf* %mp, i32 %req_len) nounwind optsize {
entry:
%0 = icmp eq %struct.mbuf* %mp, null ; <i1> [#uses=1]
%1 = icmp slt i32 %req_len, 0 ; <i1> [#uses=1]
%or.cond = or i1 %1, %0 ; <i1> [#uses=1]
br i1 %or.cond, label %return, label %bb4.preheader
bb4.preheader: ; preds = %entry
br label %bb4.outer
bb2: ; preds = %bb1
%2 = sub i32 %len.0, %13 ; <i32> [#uses=1]
%3 = getelementptr %struct.mbuf, %struct.mbuf* %m.0.ph, i32 0, i32 2 ; <i32*> [#uses=1]
store i32 0, i32* %3, align 4
%4 = getelementptr %struct.mbuf, %struct.mbuf* %m.0.ph, i32 0, i32 0 ; <%struct.mbuf**> [#uses=1]
%5 = load %struct.mbuf*, %struct.mbuf** %4, align 4 ; <%struct.mbuf*> [#uses=1]
br label %bb4.outer
bb4.outer: ; preds = %bb4.preheader, %bb2
%m.0.ph = phi %struct.mbuf* [ %5, %bb2 ], [ %mp, %bb4.preheader ] ; <%struct.mbuf*> [#uses=7]
%len.0.ph = phi i32 [ %2, %bb2 ], [ %req_len, %bb4.preheader ] ; <i32> [#uses=1]
%6 = icmp ne %struct.mbuf* %m.0.ph, null ; <i1> [#uses=1]
%7 = getelementptr %struct.mbuf, %struct.mbuf* %m.0.ph, i32 0, i32 2 ; <i32*> [#uses=1]
%8 = getelementptr %struct.mbuf, %struct.mbuf* %m.0.ph, i32 0, i32 2 ; <i32*> [#uses=1]
%9 = getelementptr %struct.mbuf, %struct.mbuf* %m.0.ph, i32 0, i32 3 ; <i8**> [#uses=1]
%10 = getelementptr %struct.mbuf, %struct.mbuf* %m.0.ph, i32 0, i32 3 ; <i8**> [#uses=1]
br label %bb4
bb4: ; preds = %bb4.outer, %bb3
%len.0 = phi i32 [ 0, %bb3 ], [ %len.0.ph, %bb4.outer ] ; <i32> [#uses=6]
%11 = icmp sgt i32 %len.0, 0 ; <i1> [#uses=1]
%12 = and i1 %11, %6 ; <i1> [#uses=1]
br i1 %12, label %bb1, label %bb7
bb1: ; preds = %bb4
%13 = load i32, i32* %7, align 4 ; <i32> [#uses=3]
%14 = icmp sgt i32 %13, %len.0 ; <i1> [#uses=1]
br i1 %14, label %bb3, label %bb2
bb3: ; preds = %bb1
%15 = sub i32 %13, %len.0 ; <i32> [#uses=1]
store i32 %15, i32* %8, align 4
%16 = load i8*, i8** %9, align 4 ; <i8*> [#uses=1]
%17 = getelementptr i8, i8* %16, i32 %len.0 ; <i8*> [#uses=1]
store i8* %17, i8** %10, align 4
br label %bb4
bb7: ; preds = %bb4
%18 = getelementptr %struct.mbuf, %struct.mbuf* %mp, i32 0, i32 5 ; <i16*> [#uses=1]
%19 = load i16, i16* %18, align 2 ; <i16> [#uses=1]
%20 = zext i16 %19 to i32 ; <i32> [#uses=1]
%21 = and i32 %20, 2 ; <i32> [#uses=1]
%22 = icmp eq i32 %21, 0 ; <i1> [#uses=1]
br i1 %22, label %return, label %bb8
bb8: ; preds = %bb7
%23 = sub i32 %req_len, %len.0 ; <i32> [#uses=1]
%24 = getelementptr %struct.mbuf, %struct.mbuf* %mp, i32 0, i32 6 ; <i32*> [#uses=1]
store i32 %23, i32* %24, align 4
ret void
return: ; preds = %bb7, %entry
ret void
}

View File

@@ -0,0 +1,60 @@
; RUN: opt < %s -basicaa -gvn -S | FileCheck %s
; This test is checking that (a) this doesn't crash, and (b) we don't
; conclude the value of %tmp17 is available in bb1.bb15_crit_edge.
; rdar://9429882
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-macosx10.7.0"
define i1 @rb_intern(i8 *%foo) nounwind ssp {
; CHECK-LABEL: @rb_intern(
bb:
%tmp = alloca i8*, align 8
store i8* null, i8** %tmp, align 8
store i8 undef, i8* null, align 536870912
br label %bb1
bb1:
br i1 undef, label %bb3, label %bb15
; CHECK: bb1:
; CHECK: [[TMP:%.*]] = phi i8* [ %tmp14, %bb10 ], [ null, %bb ]
; CHECK: bb1.bb15_crit_edge:
; CHECK: %tmp17.pre = load i8, i8* [[TMP]], align 1
bb3:
call void @isalnum()
br i1 undef, label %bb10, label %bb5
bb5:
br i1 undef, label %bb10, label %bb6
bb6:
%tmp7 = load i8*, i8** %tmp, align 8
%tmp8 = load i8, i8* %tmp7, align 1
%tmp9 = zext i8 %tmp8 to i64
br i1 undef, label %bb15, label %bb10
bb10:
%tmp11 = load i8*, i8** %tmp, align 8
%tmp12 = load i8, i8* %tmp11, align 1
%tmp13 = zext i8 %tmp12 to i64
%tmp14 = getelementptr inbounds i8, i8* %foo, i64 undef
store i8* %tmp14, i8** %tmp, align 8
br label %bb1
bb15:
%tmp16 = load i8*, i8** %tmp, align 8
%tmp17 = load i8, i8* %tmp16, align 1
%tmp18 = icmp eq i8 %tmp17, 0
br label %bb19
; CHECK: bb15:
; CHECK: %tmp17 = phi i8 [ %tmp17.pre, %bb1.bb15_crit_edge ], [ %tmp8, %bb6 ]
bb19: ; preds = %bb15
ret i1 %tmp18
}
declare void @isalnum() nounwind inlinehint ssp

View File

@@ -0,0 +1,79 @@
; This test checks if debug loc is propagated to load/store created by GVN/Instcombine.
; RUN: opt < %s -gvn -S | FileCheck %s --check-prefixes=ALL,GVN
; RUN: opt < %s -gvn -instcombine -S | FileCheck %s --check-prefixes=ALL,INSTCOMBINE
; struct node {
; int *v;
; struct desc *descs;
; };
; struct desc {
; struct node *node;
; };
; extern int bar(void *v, void* n);
; int test(struct desc *desc)
; {
; void *v, *n;
; v = !desc ? ((void *)0) : desc->node->v; // Line 15
; n = &desc->node->descs[0]; // Line 16
; return bar(v, n);
; }
; Line 16, Column 13:
; n = &desc->node->descs[0];
; ^
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64--linux-gnu"
%struct.desc = type { %struct.node* }
%struct.node = type { i32*, %struct.desc* }
define i32 @test(%struct.desc* readonly %desc) local_unnamed_addr #0 !dbg !4 {
entry:
%tobool = icmp eq %struct.desc* %desc, null
br i1 %tobool, label %cond.end, label %cond.false, !dbg !9
; ALL: br i1 %tobool, label %entry.cond.end_crit_edge, label %cond.false, !dbg [[LOC_15_6:![0-9]+]]
; ALL: entry.cond.end_crit_edge:
; GVN: %.pre = load %struct.node*, %struct.node** null, align 8, !dbg [[LOC_16_13:![0-9]+]]
; INSTCOMBINE:store %struct.node* undef, %struct.node** null, align 536870912, !dbg [[LOC_16_13:![0-9]+]]
cond.false:
%0 = bitcast %struct.desc* %desc to i8***, !dbg !11
%1 = load i8**, i8*** %0, align 8, !dbg !11
%2 = load i8*, i8** %1, align 8
br label %cond.end, !dbg !9
cond.end:
%3 = phi i8* [ %2, %cond.false ], [ null, %entry ], !dbg !9
%node2 = getelementptr inbounds %struct.desc, %struct.desc* %desc, i64 0, i32 0
%4 = load %struct.node*, %struct.node** %node2, align 8, !dbg !10
%descs = getelementptr inbounds %struct.node, %struct.node* %4, i64 0, i32 1
%5 = bitcast %struct.desc** %descs to i8**
%6 = load i8*, i8** %5, align 8
%call = tail call i32 @bar(i8* %3, i8* %6)
ret i32 %call
}
declare i32 @bar(i8*, i8*) local_unnamed_addr #1
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!2, !3}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, emissionKind: FullDebug)
!1 = !DIFile(filename: "test.c", directory: ".")
!2 = !{i32 2, !"Dwarf Version", i32 4}
!3 = !{i32 2, !"Debug Info Version", i32 3}
!4 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 12, type: !5, isLocal: false, isDefinition: true, scopeLine: 13, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !8)
!5 = !DISubroutineType(types: !6)
!6 = !{!7}
!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!8 = !{}
!9 = !DILocation(line: 15, column: 6, scope: !4)
!10 = !DILocation(line: 16, column: 13, scope: !4)
!11 = !DILocation(line: 15, column: 34, scope: !4)
;ALL: [[SCOPE:![0-9]+]] = distinct !DISubprogram(name: "test",{{.*}}
;ALL: [[LOC_15_6]] = !DILocation(line: 15, column: 6, scope: [[SCOPE]])
;ALL: [[LOC_16_13]] = !DILocation(line: 16, column: 13, scope: [[SCOPE]])

View File

@@ -0,0 +1,39 @@
; RUN: opt -S -gvn -enable-load-pre < %s | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
%ArrayImpl = type { i64, i64 addrspace(100)*, [1 x i64], [1 x i64], [1 x i64], i64, i64, double addrspace(100)*, double addrspace(100)*, i8, i64 }
; Function Attrs: readnone
declare %ArrayImpl* @getaddr_ArrayImpl(%ArrayImpl addrspace(100)*) #0
; Function Attrs: readnone
declare i64* @getaddr_i64(i64 addrspace(100)*) #0
; Make sure that the test compiles without a crash.
; Bug https://bugs.llvm.org/show_bug.cgi?id=34937
define hidden void @wrapon_fn173() {
; CHECK-LABEL: @wrapon_fn173
; CHECK: entry:
; CHECK-NEXT: call %ArrayImpl* @getaddr_ArrayImpl(%ArrayImpl addrspace(100)* undef)
; CHECK-NEXT: %.pre = load i64 addrspace(100)*, i64 addrspace(100)** null, align 8
; CHECK-NEXT: br label %loop
; CHECK: loop:
; CHECK-NEXT: call i64* @getaddr_i64(i64 addrspace(100)* %.pre)
; CHECK-NEXT: br label %loop
entry:
%0 = call %ArrayImpl* @getaddr_ArrayImpl(%ArrayImpl addrspace(100)* undef)
br label %loop
loop:
%1 = call %ArrayImpl* @getaddr_ArrayImpl(%ArrayImpl addrspace(100)* undef)
%2 = load i64 addrspace(100)*, i64 addrspace(100)** null, align 8
%3 = call i64* @getaddr_i64(i64 addrspace(100)* %2)
br label %loop
}
attributes #0 = { readnone }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,136 @@
; Test if the !invariant.load metadata is maintained by GVN.
; RUN: opt -basicaa -gvn -S < %s | FileCheck %s
define i32 @test1(i32* nocapture %p, i8* nocapture %q) {
; CHECK-LABEL: test1
; CHECK: %x = load i32, i32* %p, align 4, !invariant.load !0
; CHECK-NOT: %y = load
entry:
%x = load i32, i32* %p, align 4, !invariant.load !0
%conv = trunc i32 %x to i8
store i8 %conv, i8* %q, align 1
%y = load i32, i32* %p, align 4, !invariant.load !0
%add = add i32 %y, 1
ret i32 %add
}
define i32 @test2(i32* nocapture %p, i8* nocapture %q) {
; CHECK-LABEL: test2
; CHECK-NOT: !invariant.load
; CHECK-NOT: %y = load
entry:
%x = load i32, i32* %p, align 4
%conv = trunc i32 %x to i8
store i8 %conv, i8* %q, align 1
%y = load i32, i32* %p, align 4, !invariant.load !0
%add = add i32 %y, 1
ret i32 %add
}
; With the invariant.load metadata, what would otherwise
; be a case for PRE becomes a full redundancy.
define i32 @test3(i1 %cnd, i32* %p, i32* %q) {
; CHECK-LABEL: test3
; CHECK-NOT: load
entry:
%v1 = load i32, i32* %p
br i1 %cnd, label %bb1, label %bb2
bb1:
store i32 5, i32* %q
br label %bb2
bb2:
%v2 = load i32, i32* %p, !invariant.load !0
%res = sub i32 %v1, %v2
ret i32 %res
}
; This test is here to document a case which doesn't optimize
; as well as it could.
define i32 @test4(i1 %cnd, i32* %p, i32* %q) {
; CHECK-LABEL: test4
; %v2 is redundant, but GVN currently doesn't catch that
entry:
%v1 = load i32, i32* %p, !invariant.load !0
br i1 %cnd, label %bb1, label %bb2
bb1:
store i32 5, i32* %q
br label %bb2
bb2:
%v2 = load i32, i32* %p
%res = sub i32 %v1, %v2
ret i32 %res
}
; Checks that we return the mustalias store as a def
; so that it contributes to value forwarding. Note
; that we could and should remove the store too.
define i32 @test5(i1 %cnd, i32* %p) {
; CHECK-LABEL: test5
; CHECK-LABEL: entry:
; CHECK-NEXT: store i32 5, i32* %p
; CHECK-NEXT: ret i32 5
entry:
%v1 = load i32, i32* %p, !invariant.load !0
store i32 5, i32* %p ;; must alias store, want to exploit
%v2 = load i32, i32* %p, !invariant.load !0
ret i32 %v2
}
declare void @foo()
; Clobbering (mayalias) stores, even in function calls, can be ignored
define i32 @test6(i1 %cnd, i32* %p) {
; CHECK-LABEL: test6
; CHECK-LABEL: entry:
; CHECK-NEXT: @foo
; CHECK-NEXT: ret i32 0
entry:
%v1 = load i32, i32* %p, !invariant.load !0
call void @foo()
%v2 = load i32, i32* %p, !invariant.load !0
%res = sub i32 %v1, %v2
ret i32 %res
}
declare noalias i32* @bar(...)
; Same as previous, but a function with a noalias result (since they're handled
; differently in MDA)
define i32 @test7(i1 %cnd, i32* %p) {
; CHECK-LABEL: test7
; CHECK-LABEL: entry:
; CHECK-NEXT: @bar
; CHECK-NEXT: ret i32 0
entry:
%v1 = load i32, i32* %p, !invariant.load !0
call i32* (...) @bar(i32* %p)
%v2 = load i32, i32* %p, !invariant.load !0
%res = sub i32 %v1, %v2
ret i32 %res
}
define i32 @test8(i1 %cnd, i32* %p) {
; CHECK-LABEL: test8
; CHECK: @bar
; CHECK: load i32, i32* %p2, !invariant.load
; CHECK: br label %merge
entry:
%v1 = load i32, i32* %p, !invariant.load !0
br i1 %cnd, label %taken, label %merge
taken:
%p2 = call i32* (...) @bar(i32* %p)
br label %merge
merge:
%p3 = phi i32* [%p, %entry], [%p2, %taken]
%v2 = load i32, i32* %p3, !invariant.load !0
%res = sub i32 %v1, %v2
ret i32 %res
}
!0 = !{ }

View File

@@ -0,0 +1,24 @@
; RUN: opt -S -gvn < %s | FileCheck %s
define i32 @test1(i32* %p, i1 %C) {
; CHECK-LABEL: @test1(
block1:
br i1 %C, label %block2, label %block3
block2:
br label %block4
; CHECK: block2:
; CHECK-NEXT: load i32, i32* %p, !range !0, !invariant.group !1
block3:
store i32 0, i32* %p
br label %block4
block4:
%PRE = load i32, i32* %p, !range !0, !invariant.group !1
ret i32 %PRE
}
!0 = !{i32 40, i32 100}
!1 = !{!"magic ptr"}

View File

@@ -0,0 +1,44 @@
; RUN: opt < %s -gvn -S | FileCheck %s
target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:64:64-v128:128:128-a0:0:32-n32"
@p = external global i32
define i32 @test(i32 %n) nounwind {
; CHECK-LABEL: @test(
entry:
br label %for.cond
; loads aligned greater than the memory should not be moved past conditionals
; CHECK-NOT: load
; CHECK: br i1
for.cond:
%i.0 = phi i32 [ 0, %entry ], [ %indvar.next, %for.inc ]
%cmp = icmp slt i32 %i.0, %n
br i1 %cmp, label %for.body, label %for.cond.for.end_crit_edge
for.cond.for.end_crit_edge:
; ...but PRE can still move the load out of for.end to here.
; CHECK: for.cond.for.end_crit_edge:
; CHECK-NEXT: load
br label %for.end
for.body:
%tmp3 = load i32, i32* @p, align 8
%dec = add i32 %tmp3, -1
store i32 %dec, i32* @p
%cmp6 = icmp slt i32 %dec, 0
br i1 %cmp6, label %for.body.for.end_crit_edge, label %for.inc
for.body.for.end_crit_edge:
br label %for.end
for.inc:
%indvar.next = add i32 %i.0, 1
br label %for.cond
for.end:
%tmp9 = load i32, i32* @p, align 8
ret i32 %tmp9
}

View File

@@ -0,0 +1,39 @@
; RUN: opt -S -basicaa -gvn < %s | FileCheck %s
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32"
target triple = "i386-apple-darwin11.0.0"
@sortlist = external global [5001 x i32], align 4
define void @Bubble() nounwind noinline {
; CHECK: entry:
; CHECK-NEXT: %tmp7.pre = load i32
entry:
br label %while.body5
; CHECK: while.body5:
; CHECK: %tmp7 = phi i32
; CHECK-NOT: %tmp7 = load i32
while.body5:
%indvar = phi i32 [ 0, %entry ], [ %tmp6, %if.end ]
%tmp5 = add i32 %indvar, 2
%arrayidx9 = getelementptr [5001 x i32], [5001 x i32]* @sortlist, i32 0, i32 %tmp5
%tmp6 = add i32 %indvar, 1
%arrayidx = getelementptr [5001 x i32], [5001 x i32]* @sortlist, i32 0, i32 %tmp6
%tmp7 = load i32, i32* %arrayidx, align 4
%tmp10 = load i32, i32* %arrayidx9, align 4
%cmp11 = icmp sgt i32 %tmp7, %tmp10
br i1 %cmp11, label %if.then, label %if.end
; CHECK: if.then:
if.then:
store i32 %tmp10, i32* %arrayidx, align 4
store i32 %tmp7, i32* %arrayidx9, align 4
br label %if.end
if.end:
%exitcond = icmp eq i32 %tmp6, 100
br i1 %exitcond, label %while.end.loopexit, label %while.body5
while.end.loopexit:
ret void
}

View File

@@ -0,0 +1,112 @@
; RUN: opt -S -o - -basicaa -domtree -gvn %s | FileCheck %s
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
%struct.S1 = type { i32, i32 }
@a2 = common global i32* null, align 8
@a = common global i32* null, align 8
@s1 = common global %struct.S1 zeroinitializer, align 8
; Check that GVN doesn't determine %2 is partially redundant.
; CHECK-LABEL: define i32 @volatile_load
; CHECK: for.body:
; CHECK: %2 = load i32, i32*
; CHECK: %3 = load volatile i32, i32*
; CHECK: for.cond.for.end_crit_edge:
define i32 @volatile_load(i32 %n) {
entry:
%cmp6 = icmp sgt i32 %n, 0
br i1 %cmp6, label %for.body.lr.ph, label %for.end
for.body.lr.ph:
%0 = load i32*, i32** @a2, align 8, !tbaa !1
%1 = load i32*, i32** @a, align 8, !tbaa !1
br label %for.body
for.body:
%indvars.iv = phi i64 [ 0, %for.body.lr.ph ], [ %indvars.iv.next, %for.body ]
%s.09 = phi i32 [ 0, %for.body.lr.ph ], [ %add, %for.body ]
%p.08 = phi i32* [ %0, %for.body.lr.ph ], [ %incdec.ptr, %for.body ]
%2 = load i32, i32* %p.08, align 4, !tbaa !5
%arrayidx = getelementptr inbounds i32, i32* %1, i64 %indvars.iv
store i32 %2, i32* %arrayidx, align 4, !tbaa !5
%3 = load volatile i32, i32* %p.08, align 4, !tbaa !5
%add = add nsw i32 %3, %s.09
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
%incdec.ptr = getelementptr inbounds i32, i32* %p.08, i64 1
%lftr.wideiv = trunc i64 %indvars.iv.next to i32
%exitcond = icmp ne i32 %lftr.wideiv, %n
br i1 %exitcond, label %for.body, label %for.cond.for.end_crit_edge
for.cond.for.end_crit_edge:
%add.lcssa = phi i32 [ %add, %for.body ]
br label %for.end
for.end:
%s.0.lcssa = phi i32 [ %add.lcssa, %for.cond.for.end_crit_edge ], [ 0, %entry ]
ret i32 %s.0.lcssa
}
; %1 is partially redundant if %0 can be widened to a 64-bit load.
; But we should not widen %0 to 64-bit load.
; CHECK-LABEL: define i32 @overaligned_load
; CHECK: if.then:
; CHECK-NOT: %0 = load i64
; CHECK-NOT: [[LSHR:%[0-9]+]] = lshr i64 %0, 32, !dbg [[LSHR_LOC:![0-9]+]]
; CHECK-NOT: trunc i64 [[LSHR]] to i32
; CHECK: if.end:
; CHECK: %1 = load i32, i32*
; CHECK-NOT: [[LSHR_LOC]] = !DILocation(line: 101, column: 1, scope: !{{.*}})
define i32 @overaligned_load(i32 %a, i32* nocapture %b) !dbg !13 {
entry:
%cmp = icmp sgt i32 %a, 0, !dbg !14
br i1 %cmp, label %if.then, label %if.else, !dbg !14
if.then:
%0 = load i32, i32* getelementptr inbounds (%struct.S1, %struct.S1* @s1, i64 0, i32 0), align 8, !tbaa !5, !dbg !15
br label %if.end, !dbg !15
if.else:
%arrayidx = getelementptr inbounds i32, i32* %b, i64 2, !dbg !16
store i32 10, i32* %arrayidx, align 4, !tbaa !5, !dbg !16
br label %if.end, !dbg !16
if.end:
%i.0 = phi i32 [ %0, %if.then ], [ 0, %if.else ]
%p.0 = phi i32* [ getelementptr inbounds (%struct.S1, %struct.S1* @s1, i64 0, i32 0), %if.then ], [ %b, %if.else ]
%add.ptr = getelementptr inbounds i32, i32* %p.0, i64 1, !dbg !17
%1 = load i32, i32* %add.ptr, align 4, !tbaa !5, !dbg !17
%add1 = add nsw i32 %1, %i.0, !dbg !17
ret i32 %add1, !dbg !17
}
!1 = !{!2, !2, i64 0}
!2 = !{!"any pointer", !3, i64 0}
!3 = !{!"omnipotent char", !4, i64 0}
!4 = !{!"Simple C/C++ TBAA"}
!5 = !{!6, !6, i64 0}
!6 = !{!"int", !3, i64 0}
!llvm.module.flags = !{!7, !8, !9}
!llvm.dbg.cu = !{!18}
!7 = !{i32 2, !"Dwarf Version", i32 4}
!8 = !{i32 2, !"Debug Info Version", i32 3}
!9 = !{i32 1, !"PIC Level", i32 2}
!10 = !{}
!11 = !DISubroutineType(types: !10)
!12 = !DIFile(filename: "test.cpp", directory: "/tmp")
!13 = distinct !DISubprogram(name: "test", scope: !12, file: !12, line: 99, type: !11, isLocal: false, isDefinition: true, scopeLine: 100, flags: DIFlagPrototyped, isOptimized: false, unit: !18, variables: !10)
!14 = !DILocation(line: 100, column: 1, scope: !13)
!15 = !DILocation(line: 101, column: 1, scope: !13)
!16 = !DILocation(line: 102, column: 1, scope: !13)
!17 = !DILocation(line: 103, column: 1, scope: !13)
!18 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang",
file: !12,
isOptimized: true, flags: "-O2",
splitDebugFilename: "abc.debug", emissionKind: 2)

View File

@@ -0,0 +1,147 @@
; RUN: opt < %s -gvn -enable-pre -S | FileCheck %s
declare void @may_exit() nounwind
declare void @may_exit_1(i32) nounwind
define i32 @main(i32 %p, i32 %q) {
; CHECK-LABEL: @main(
block1:
%cmp = icmp eq i32 %p, %q
br i1 %cmp, label %block2, label %block3
block2:
%a = add i32 %p, 1
br label %block4
block3:
br label %block4
; CHECK: %.pre = add i32 %p, 1
; CHECK-NEXT: br label %block4
block4:
%b = add i32 %p, 1
ret i32 %b
; CHECK: %b.pre-phi = phi i32 [ %.pre, %block3 ], [ %a, %block2 ]
; CHECK-NEXT: ret i32 %b.pre-phi
}
; Don't PRE across implicit control flow.
define i32 @test2(i32 %p, i32 %q) {
; CHECK-LABEL: @test2
; CHECK: block1:
block1:
%cmp = icmp eq i32 %p, %q
br i1 %cmp, label %block2, label %block3
block2:
%a = sdiv i32 %p, %q
br label %block4
block3:
br label %block4
; CHECK: block4:
; CHECK-NEXT: call void @may_exit(
; CHECK-NEXT: %b = sdiv
; CHECK-NEXT: ret i32 %b
block4:
call void @may_exit() nounwind
%b = sdiv i32 %p, %q
ret i32 %b
}
; Don't PRE across implicit control flow.
define i32 @test3(i32 %p, i32 %q, i1 %r) {
; CHECK-LABEL: @test3
; CHECK: block1:
block1:
br i1 %r, label %block2, label %block3
block2:
%a = sdiv i32 %p, %q
br label %block4
block3:
br label %block4
block4:
; CHECK: block4:
; CHECK-NEXT: phi i32
; CHECK-NEXT: call void @may_exit_1(
; CHECK-NEXT: %b = sdiv
; CHECK-NEXT: ret i32 %b
%phi = phi i32 [ 0, %block3 ], [ %a, %block2 ]
call void @may_exit_1(i32 %phi) nounwind
%b = sdiv i32 %p, %q
ret i32 %b
}
; It's OK to PRE an instruction that is guaranteed to be safe to execute
; speculatively.
; TODO: Does it make any sense in this case?
define i32 @test4(i32 %p, i32 %q) {
; CHECK-LABEL: @test4
; CHECK: block1:
block1:
%cmp = icmp eq i32 %p, %q
br i1 %cmp, label %block2, label %block3
block2:
%a = sdiv i32 %p, 6
br label %block4
block3:
br label %block4
; CHECK: block4:
; CHECK-NEXT: %b.pre-phi = phi i32
; CHECK-NEXT: call void @may_exit(
; CHECK-NEXT: ret i32 %b
block4:
call void @may_exit() nounwind
%b = sdiv i32 %p, 6
ret i32 %b
}
; It is OK to PRE across implicit control flow if we don't insert new
; instructions.
define i32 @test5(i1 %cond, i32 %p, i32 %q) {
; CHECK-LABEL: @test5
; CHECK: block1:
block1:
br i1 %cond, label %block2, label %block3
block2:
%a = sdiv i32 %p, %q
br label %block4
block3:
%b = sdiv i32 %p, %q
br label %block4
; CHECK: block4:
; CHECK-NEXT: %c.pre-phi = phi i32 [ %b, %block3 ], [ %a, %block2 ]
; CHECK-NEXT: call void @may_exit()
; CHECK-NEXT: ret i32 %c.pre-phi
block4:
call void @may_exit() nounwind
%c = sdiv i32 %p, %q
ret i32 %c
}

View File

@@ -0,0 +1,40 @@
; RUN: opt -S -basicaa -gvn -enable-load-pre < %s | FileCheck %s
;
; The partially redundant load in bb1 should be hoisted to "bb". This comes
; from this C code (GCC PR 23455):
; unsigned outcnt; extern void flush_outbuf(void);
; void bi_windup(unsigned char *outbuf, unsigned char bi_buf) {
; outbuf[outcnt] = bi_buf;
; if (outcnt == 16384)
; flush_outbuf();
; outbuf[outcnt] = bi_buf;
; }
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
target triple = "i386-apple-darwin7"
@outcnt = common global i32 0 ; <i32*> [#uses=3]
define void @bi_windup(i8* %outbuf, i8 zeroext %bi_buf) nounwind {
entry:
%"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0]
%0 = load i32, i32* @outcnt, align 4 ; <i32> [#uses=1]
%1 = getelementptr i8, i8* %outbuf, i32 %0 ; <i8*> [#uses=1]
store i8 %bi_buf, i8* %1, align 1
%2 = load i32, i32* @outcnt, align 4 ; <i32> [#uses=1]
%3 = icmp eq i32 %2, 16384 ; <i1> [#uses=1]
br i1 %3, label %bb, label %bb1
bb: ; preds = %entry
call void @flush_outbuf() nounwind
br label %bb1
bb1: ; preds = %bb, %entry
; CHECK: bb1:
; CHECK-NEXT: phi
; CHECK-NEXT: getelementptr
%4 = load i32, i32* @outcnt, align 4 ; <i32> [#uses=1]
%5 = getelementptr i8, i8* %outbuf, i32 %4 ; <i8*> [#uses=1]
store i8 %bi_buf, i8* %5, align 1
ret void
}
declare void @flush_outbuf()

View File

@@ -0,0 +1,55 @@
; RUN: opt -S -gvn -enable-load-pre < %s | FileCheck %s
;
; Make sure the load in bb3.backedge is removed and moved into bb1 after the
; call. This makes the non-call case faster.
;
; This test is derived from this C++ code (GCC PR 37810):
; void g();
; struct A {
; int n; int m;
; A& operator++(void) { ++n; if (n == m) g(); return *this; }
; A() : n(0), m(0) { }
; friend bool operator!=(A const& a1, A const& a2) { return a1.n != a2.n; }
; };
; void testfunction(A& iter) { A const end; while (iter != end) ++iter; }
;
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
target triple = "i386-apple-darwin7"
%struct.A = type { i32, i32 }
define void @_Z12testfunctionR1A(%struct.A* %iter) {
entry:
%0 = getelementptr %struct.A, %struct.A* %iter, i32 0, i32 0 ; <i32*> [#uses=3]
%1 = load i32, i32* %0, align 4 ; <i32> [#uses=2]
%2 = icmp eq i32 %1, 0 ; <i1> [#uses=1]
br i1 %2, label %return, label %bb.nph
bb.nph: ; preds = %entry
%3 = getelementptr %struct.A, %struct.A* %iter, i32 0, i32 1 ; <i32*> [#uses=1]
br label %bb
bb: ; preds = %bb3.backedge, %bb.nph
%.rle = phi i32 [ %1, %bb.nph ], [ %7, %bb3.backedge ] ; <i32> [#uses=1]
%4 = add i32 %.rle, 1 ; <i32> [#uses=2]
store i32 %4, i32* %0, align 4
%5 = load i32, i32* %3, align 4 ; <i32> [#uses=1]
%6 = icmp eq i32 %4, %5 ; <i1> [#uses=1]
br i1 %6, label %bb1, label %bb3.backedge
bb1: ; preds = %bb
tail call void @_Z1gv()
br label %bb3.backedge
bb3.backedge: ; preds = %bb, %bb1
; CHECK: bb3.backedge:
; CHECK-NEXT: phi
; CHECK-NEXT: icmp
%7 = load i32, i32* %0, align 4 ; <i32> [#uses=2]
%8 = icmp eq i32 %7, 0 ; <i1> [#uses=1]
br i1 %8, label %return, label %bb
return: ; preds = %bb3.backedge, %entry
ret void
}
declare void @_Z1gv()

View File

@@ -0,0 +1,39 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -gvn -S < %s | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:4"
target triple = "x86_64-unknown-linux-gnu"
define void @nipre(double addrspace(4)** noalias %p, i64 addrspace(4)** noalias %p2, i8 %jmp) {
; CHECK-LABEL: @nipre(
; CHECK: [[PCAST:%.*]] = bitcast double addrspace(4)** [[P:%.*]] to i64 addrspace(4)**
; CHECK: a:
; CHECK: [[L1:%.*]] = load i64 addrspace(4)*, i64 addrspace(4)** [[PCAST]]
; CHECK: [[TMP0:%.*]] = bitcast i64 addrspace(4)* [[L1]] to double addrspace(4)*
; CHECK: b:
; CHECK: [[L2:%.*]] = load i64 addrspace(4)*, i64 addrspace(4)** [[PCAST]]
; CHECK: [[TMP1:%.*]] = bitcast i64 addrspace(4)* [[L2]] to double addrspace(4)*
; CHECK: c:
; CHECK-NEXT: [[L3_PRE:%.*]] = load double addrspace(4)*, double addrspace(4)** %p
entry:
%pcast = bitcast double addrspace(4)** %p to i64 addrspace(4)**
switch i8 %jmp, label %c [ i8 0, label %a
i8 1, label %b]
a:
%l1 = load i64 addrspace(4)*, i64 addrspace(4)** %pcast
store i64 addrspace(4)* %l1, i64 addrspace(4)** %p2
br label %tail
b:
%l2 = load i64 addrspace(4)*, i64 addrspace(4)** %pcast
store i64 addrspace(4)* %l2, i64 addrspace(4)** %p2
br label %tail
c:
br label %tail
tail:
%l3 = load double addrspace(4)*, double addrspace(4)** %p
%l3cast = bitcast double addrspace(4)* %l3 to i64 addrspace(4)*
store i64 addrspace(4)* %l3cast, i64 addrspace(4)** %p2
ret void
}

View File

@@ -0,0 +1,176 @@
; RUN: opt < %s -gvn -S | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
@a = common global [100 x i64] zeroinitializer, align 16
@b = common global [100 x i64] zeroinitializer, align 16
@g1 = common global i64 0, align 8
@g2 = common global i64 0, align 8
@g3 = common global i64 0, align 8
declare i64 @goo(...) local_unnamed_addr #1
define void @test1(i64 %a, i64 %b, i64 %c, i64 %d) {
entry:
%mul = mul nsw i64 %b, %a
store i64 %mul, i64* @g1, align 8
%t0 = load i64, i64* @g2, align 8
%cmp = icmp sgt i64 %t0, 3
br i1 %cmp, label %if.then, label %if.end
if.then: ; preds = %entry
%mul2 = mul nsw i64 %d, %c
store i64 %mul2, i64* @g2, align 8
br label %if.end
; Check phi-translate works and mul is removed.
; CHECK-LABEL: @test1(
; CHECK: if.end:
; CHECK: %[[MULPHI:.*]] = phi i64 [ {{.*}}, %if.then ], [ %mul, %entry ]
; CHECK-NOT: = mul
; CHECK: store i64 %[[MULPHI]], i64* @g3, align 8
if.end: ; preds = %if.then, %entry
%b.addr.0 = phi i64 [ %d, %if.then ], [ %b, %entry ]
%a.addr.0 = phi i64 [ %c, %if.then ], [ %a, %entry ]
%mul3 = mul nsw i64 %a.addr.0, %b.addr.0
store i64 %mul3, i64* @g3, align 8
ret void
}
define void @test2(i64 %i) {
entry:
%arrayidx = getelementptr inbounds [100 x i64], [100 x i64]* @a, i64 0, i64 %i
%t0 = load i64, i64* %arrayidx, align 8
%arrayidx1 = getelementptr inbounds [100 x i64], [100 x i64]* @b, i64 0, i64 %i
%t1 = load i64, i64* %arrayidx1, align 8
%mul = mul nsw i64 %t1, %t0
store i64 %mul, i64* @g1, align 8
%cmp = icmp sgt i64 %mul, 3
br i1 %cmp, label %if.then, label %if.end
; Check phi-translate works for the phi generated by loadpre. A new mul will be
; inserted in if.then block.
; CHECK-LABEL: @test2(
; CHECK: if.then:
; CHECK: %[[MUL_THEN:.*]] = mul
; CHECK: br label %if.end
if.then: ; preds = %entry
%call = tail call i64 (...) @goo() #2
store i64 %call, i64* @g2, align 8
br label %if.end
; CHECK: if.end:
; CHECK: %[[MULPHI:.*]] = phi i64 [ %[[MUL_THEN]], %if.then ], [ %mul, %entry ]
; CHECK-NOT: = mul
; CHECK: store i64 %[[MULPHI]], i64* @g3, align 8
if.end: ; preds = %if.then, %entry
%i.addr.0 = phi i64 [ 3, %if.then ], [ %i, %entry ]
%arrayidx3 = getelementptr inbounds [100 x i64], [100 x i64]* @a, i64 0, i64 %i.addr.0
%t2 = load i64, i64* %arrayidx3, align 8
%arrayidx4 = getelementptr inbounds [100 x i64], [100 x i64]* @b, i64 0, i64 %i.addr.0
%t3 = load i64, i64* %arrayidx4, align 8
%mul5 = mul nsw i64 %t3, %t2
store i64 %mul5, i64* @g3, align 8
ret void
}
; Check phi-translate doesn't go through backedge, which may lead to incorrect
; pre transformation.
; CHECK: for.end:
; CHECK-NOT: %{{.*pre-phi}} = phi
; CHECK: ret void
define void @test3(i64 %N, i64* nocapture readonly %a) {
entry:
br label %for.cond
for.cond: ; preds = %for.body, %entry
%i.0 = phi i64 [ 0, %entry ], [ %add, %for.body ]
%add = add nuw nsw i64 %i.0, 1
%arrayidx = getelementptr inbounds i64, i64* %a, i64 %add
%tmp0 = load i64, i64* %arrayidx, align 8
%cmp = icmp slt i64 %i.0, %N
br i1 %cmp, label %for.body, label %for.end
for.body: ; preds = %for.cond
%call = tail call i64 (...) @goo() #2
%add1 = sub nsw i64 0, %call
%tobool = icmp eq i64 %tmp0, %add1
br i1 %tobool, label %for.cond, label %for.end
for.end: ; preds = %for.body, %for.cond
%i.0.lcssa = phi i64 [ %i.0, %for.body ], [ %i.0, %for.cond ]
%arrayidx2 = getelementptr inbounds i64, i64* %a, i64 %i.0.lcssa
%tmp1 = load i64, i64* %arrayidx2, align 8
store i64 %tmp1, i64* @g1, align 8
ret void
}
; It is incorrect to use the value of %andres in last loop iteration
; to do pre.
; CHECK-LABEL: @test4(
; CHECK: for.body:
; CHECK-NOT: %andres.pre-phi = phi i32
; CHECK: br i1 %tobool1
define i32 @test4(i32 %cond, i32 %SectionAttrs.0231.ph, i32 *%AttrFlag) {
for.body.preheader:
%t514 = load volatile i32, i32* %AttrFlag
br label %for.body
for.body:
%t320 = phi i32 [ %t334, %bb343 ], [ %t514, %for.body.preheader ]
%andres = and i32 %t320, %SectionAttrs.0231.ph
%tobool1 = icmp eq i32 %andres, 0
br i1 %tobool1, label %bb343, label %critedge.loopexit
bb343:
%t334 = load volatile i32, i32* %AttrFlag
%tobool2 = icmp eq i32 %cond, 0
br i1 %tobool2, label %critedge.loopexit, label %for.body
critedge.loopexit:
unreachable
}
; Check sub expression will be pre transformed.
; CHECK-LABEL: @test5(
; CHECK: entry:
; CHECK: %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast
; CHECK: br i1 %cmp
; CHECK: if.then2:
; CHECK: %[[PTRTOINT:.*]] = ptrtoint i32* %add.ptr to i64
; CHECK: %[[SUB:.*]] = sub i64 %sub.ptr.lhs.cast, %[[PTRTOINT]]
; CHECK: br label %if.end3
; CHECK: if.end3:
; CHECK: %[[PREPHI:.*]] = phi i64 [ %sub.ptr.sub, %if.else ], [ %[[SUB]], %if.then2 ], [ %sub.ptr.sub, %entry ]
; CHECK: %[[DIV:.*]] = ashr exact i64 %[[PREPHI]], 2
; CHECK: ret i64 %[[DIV]]
declare void @bar(...) local_unnamed_addr #1
; Function Attrs: nounwind uwtable
define i64 @test5(i32* %start, i32* %e, i32 %n1, i32 %n2) local_unnamed_addr #0 {
entry:
%sub.ptr.lhs.cast = ptrtoint i32* %e to i64
%sub.ptr.rhs.cast = ptrtoint i32* %start to i64
%sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast
%cmp = icmp sgt i64 %sub.ptr.sub, 4000
br i1 %cmp, label %if.then, label %if.end3
if.then: ; preds = %entry
%cmp1 = icmp sgt i32 %n1, %n2
br i1 %cmp1, label %if.then2, label %if.else
if.then2: ; preds = %if.then
%add.ptr = getelementptr inbounds i32, i32* %start, i64 800
br label %if.end3
if.else: ; preds = %if.then
tail call void (...) @bar() #2
br label %if.end3
if.end3: ; preds = %if.then2, %if.else, %entry
%p.0 = phi i32* [ %add.ptr, %if.then2 ], [ %start, %if.else ], [ %start, %entry ]
%sub.ptr.rhs.cast5 = ptrtoint i32* %p.0 to i64
%sub.ptr.sub6 = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast5
%sub.ptr.div7 = ashr exact i64 %sub.ptr.sub6, 2
ret i64 %sub.ptr.div7
}

View File

@@ -0,0 +1,56 @@
; RUN: opt -basicaa -gvn -S < %s | FileCheck %s
target datalayout = "e-p:64:64:64"
; CHECK-LABEL: @foo(
; CHECK: entry.end_crit_edge:
; CHECK: %[[INDEX:[a-z0-9.]+]] = sext i32 %x to i64{{$}}
; CHECK: %[[ADDRESS:[a-z0-9.]+]] = getelementptr [100 x i32], [100 x i32]* @G, i64 0, i64 %[[INDEX]]{{$}}
; CHECK: %n.pre = load i32, i32* %[[ADDRESS]], !dbg [[N_LOC:![0-9]+]]
; CHECK: br label %end
; CHECK: then:
; CHECK: store i32 %z
; CHECK: end:
; CHECK: %n = phi i32 [ %n.pre, %entry.end_crit_edge ], [ %z, %then ], !dbg [[N_LOC]]
; CHECK: ret i32 %n
; CHECK: [[N_LOC]] = !DILocation(line: 47, column: 1, scope: !{{.*}})
@G = external global [100 x i32]
define i32 @foo(i32 %x, i32 %z) !dbg !6 {
entry:
%tobool = icmp eq i32 %z, 0, !dbg !7
br i1 %tobool, label %end, label %then, !dbg !7
then:
%i = sext i32 %x to i64, !dbg !8
%p = getelementptr [100 x i32], [100 x i32]* @G, i64 0, i64 %i, !dbg !8
store i32 %z, i32* %p, !dbg !8
br label %end, !dbg !8
end:
%j = sext i32 %x to i64, !dbg !9
%q = getelementptr [100 x i32], [100 x i32]* @G, i64 0, i64 %j, !dbg !10
%n = load i32, i32* %q, !dbg !11
ret i32 %n, !dbg !11
}
!llvm.module.flags = !{!0, !1, !2}
!llvm.dbg.cu = !{!12}
!0 = !{i32 2, !"Dwarf Version", i32 4}
!1 = !{i32 2, !"Debug Info Version", i32 3}
!2 = !{i32 1, !"PIC Level", i32 2}
!3 = !{}
!4 = !DISubroutineType(types: !3)
!5 = !DIFile(filename: "a.cc", directory: "/tmp")
!6 = distinct !DISubprogram(name: "foo", scope: !5, file: !5, line: 42, type: !4, isLocal: false, isDefinition: true, scopeLine: 43, flags: DIFlagPrototyped, isOptimized: false, unit: !12, variables: !3)
!7 = !DILocation(line: 43, column: 1, scope: !6)
!8 = !DILocation(line: 44, column: 1, scope: !6)
!9 = !DILocation(line: 45, column: 1, scope: !6)
!10 = !DILocation(line: 46, column: 1, scope: !6)
!11 = !DILocation(line: 47, column: 1, scope: !6)
!12 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang",
file: !5,
isOptimized: true, flags: "-O2",
splitDebugFilename: "abc.debug", emissionKind: 2)

View File

@@ -0,0 +1,32 @@
; RUN: opt < %s -gvn -enable-pre -S | FileCheck %s
@H = common global i32 0 ; <i32*> [#uses=2]
@G = common global i32 0 ; <i32*> [#uses=1]
define i32 @test() nounwind {
entry:
%0 = load i32, i32* @H, align 4 ; <i32> [#uses=2]
%1 = call i32 (...) @foo() nounwind ; <i32> [#uses=1]
%2 = icmp ne i32 %1, 0 ; <i1> [#uses=1]
br i1 %2, label %bb, label %bb1
bb: ; preds = %entry
%3 = add i32 %0, 42 ; <i32> [#uses=1]
; CHECK: %.pre = add i32 %0, 42
store i32 %3, i32* @G, align 4
br label %bb1
bb1: ; preds = %bb, %entry
%4 = add i32 %0, 42 ; <i32> [#uses=1]
store i32 %4, i32* @H, align 4
br label %return
; CHECK: %.pre-phi = phi i32 [ %.pre, %entry.bb1_crit_edge ], [ %3, %bb ]
; CHECK-NEXT: store i32 %.pre-phi, i32* @H, align 4
; CHECK-NEXT: ret i32 0
return: ; preds = %bb1
ret i32 0
}
declare i32 @foo(...)

View File

@@ -0,0 +1,82 @@
; RUN: opt < %s -basicaa -gvn -enable-load-pre -S | FileCheck %s
; RUN: opt < %s -aa-pipeline=basic-aa -passes=gvn -enable-load-pre -S | FileCheck %s
target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"
target triple = "aarch64--linux-gnu"
define double @foo(i32 %stat, i32 %i, double** %p) {
; CHECK-LABEL: @foo(
entry:
switch i32 %stat, label %sw.default [
i32 0, label %sw.bb
i32 1, label %sw.bb
i32 2, label %sw.bb2
]
sw.bb: ; preds = %entry, %entry
%idxprom = sext i32 %i to i64
%arrayidx = getelementptr inbounds double*, double** %p, i64 0
%0 = load double*, double** %arrayidx, align 8
%arrayidx1 = getelementptr inbounds double, double* %0, i64 %idxprom
%1 = load double, double* %arrayidx1, align 8
%sub = fsub double %1, 1.000000e+00
%cmp = fcmp olt double %sub, 0.000000e+00
br i1 %cmp, label %if.then, label %if.end
if.then: ; preds = %sw.bb
br label %return
if.end: ; preds = %sw.bb
br label %sw.bb2
sw.bb2: ; preds = %if.end, %entry
%idxprom3 = sext i32 %i to i64
%arrayidx4 = getelementptr inbounds double*, double** %p, i64 0
%2 = load double*, double** %arrayidx4, align 8
%arrayidx5 = getelementptr inbounds double, double* %2, i64 %idxprom3
%3 = load double, double* %arrayidx5, align 8
; CHECK: sw.bb2:
; CHECK-NOT: sext
; CHECK: phi double [
; CHECK-NOT: load
%sub6 = fsub double 3.000000e+00, %3
br label %return
sw.default: ; preds = %entry
br label %return
return: ; preds = %sw.default, %sw.bb2, %if.then
%retval.0 = phi double [ 0.000000e+00, %sw.default ], [ %sub6, %sw.bb2 ], [ %sub, %if.then ]
ret double %retval.0
}
; The load causes the GEP's operands to be PREd earlier than normal. The
; resulting sext ends up in pre.dest and in the GVN system before that BB is
; actually processed. Make sure we can deal with the situation.
define void @test_shortcut_safe(i1 %tst, i32 %p1, i32* %a) {
; CHECK-LABEL: define void @test_shortcut_safe
; CHECK: [[SEXT1:%.*]] = sext i32 %p1 to i64
; CHECK: [[PHI1:%.*]] = phi i64 [ [[SEXT1]], {{%.*}} ], [ [[PHI2:%.*]], {{%.*}} ]
; CHECK: [[SEXT2:%.*]] = sext i32 %p1 to i64
; CHECK: [[PHI2]] = phi i64 [ [[SEXT2]], {{.*}} ], [ [[PHI1]], {{%.*}} ]
; CHECK: getelementptr inbounds i32, i32* %a, i64 [[PHI2]]
br i1 %tst, label %sext1, label %pre.dest
pre.dest:
br label %sext.use
sext1:
%idxprom = sext i32 %p1 to i64
br label %sext.use
sext.use:
%idxprom2 = sext i32 %p1 to i64
%arrayidx3 = getelementptr inbounds i32, i32* %a, i64 %idxprom2
%val = load i32, i32* %arrayidx3, align 4
tail call void (i32) @g(i32 %val)
br label %pre.dest
}
declare void @g(i32)

View File

@@ -0,0 +1,36 @@
; RUN: opt < %s -gvn -enable-pre -jump-threading -S | FileCheck %s
@H = common global i32 0
@G = common global i32 0
define i32 @test(i1 %cond, i32 %v) nounwind {
; CHECK-LABEL: @test
entry:
br i1 %cond, label %bb, label %bb1
bb:
; CHECK: store
; CHECK-NOT: br label %return
%add.1 = add nuw nsw i32 %v, -1
store i32 %add.1, i32* @G, align 4
br label %merge
bb1:
br label %merge
merge:
%add.2 = add i32 %v, -1
%cmp = icmp sgt i32 %add.2, 0
br i1 %cmp, label %action, label %return
action:
; CHECK: store
; CHECK-NEXT: br label %return
store i32 %add.2, i32* @H, align 4
br label %return
return:
%p = phi i32 [0, %merge], [1, %action]
ret i32 %p
}

Some files were not shown because too many files have changed in this diff Show More