diff options
Diffstat (limited to 'test/Transforms/CodeGenPrepare')
| -rw-r--r-- | test/Transforms/CodeGenPrepare/AArch64/free-zext.ll | 82 | ||||
| -rw-r--r-- | test/Transforms/CodeGenPrepare/AArch64/widen_switch.ll | 95 | ||||
| -rw-r--r-- | test/Transforms/CodeGenPrepare/X86/catchpad-phi-cast.ll | 118 | ||||
| -rw-r--r-- | test/Transforms/CodeGenPrepare/X86/cttz-ctlz.ll | 56 | ||||
| -rw-r--r-- | test/Transforms/CodeGenPrepare/X86/select.ll | 141 | ||||
| -rw-r--r-- | test/Transforms/CodeGenPrepare/X86/widen_switch.ll | 95 | ||||
| -rw-r--r-- | test/Transforms/CodeGenPrepare/invariant.group.ll | 23 | ||||
| -rw-r--r-- | test/Transforms/CodeGenPrepare/statepoint-relocate.ll | 87 |
8 files changed, 673 insertions, 24 deletions
diff --git a/test/Transforms/CodeGenPrepare/AArch64/free-zext.ll b/test/Transforms/CodeGenPrepare/AArch64/free-zext.ll new file mode 100644 index 0000000000000..c3c11a1c49499 --- /dev/null +++ b/test/Transforms/CodeGenPrepare/AArch64/free-zext.ll @@ -0,0 +1,82 @@ +; RUN: opt -S -codegenprepare -mtriple=aarch64-linux %s | FileCheck %s + +; Test for CodeGenPrepare::optimizeLoadExt(): simple case: two loads +; feeding a phi that zext's each loaded value. +define i32 @test_free_zext(i32* %ptr, i32* %ptr2, i32 %c) { +; CHECK-LABEL: @test_free_zext( +bb1: +; CHECK-LABEL: bb1: +; CHECK: %[[T1:.*]] = load +; CHECK: %[[A1:.*]] = and i32 %[[T1]], 65535 + %load1 = load i32, i32* %ptr, align 4 + %cmp = icmp ne i32 %c, 0 + br i1 %cmp, label %bb2, label %bb3 +bb2: +; CHECK-LABEL: bb2: +; CHECK: %[[T2:.*]] = load +; CHECK: %[[A2:.*]] = and i32 %[[T2]], 65535 + %load2 = load i32, i32* %ptr2, align 4 + br label %bb3 +bb3: +; CHECK-LABEL: bb3: +; CHECK: phi i32 [ %[[A1]], %bb1 ], [ %[[A2]], %bb2 ] + %phi = phi i32 [ %load1, %bb1 ], [ %load2, %bb2 ] + %and = and i32 %phi, 65535 + ret i32 %and +} + +; Test for CodeGenPrepare::optimizeLoadExt(): exercise all opcode +; cases of active bit calculation. +define i32 @test_free_zext2(i32* %ptr, i16* %dst16, i32* %dst32, i32 %c) { +; CHECK-LABEL: @test_free_zext2( +bb1: +; CHECK-LABEL: bb1: +; CHECK: %[[T1:.*]] = load +; CHECK: %[[A1:.*]] = and i32 %[[T1]], 65535 + %load1 = load i32, i32* %ptr, align 4 + %cmp = icmp ne i32 %c, 0 + br i1 %cmp, label %bb2, label %bb4 +bb2: +; CHECK-LABEL: bb2: + %trunc = trunc i32 %load1 to i16 + store i16 %trunc, i16* %dst16, align 2 + br i1 %cmp, label %bb3, label %bb4 +bb3: +; CHECK-LABEL: bb3: + %shl = shl i32 %load1, 16 + store i32 %shl, i32* %dst32, align 4 + br label %bb4 +bb4: +; CHECK-LABEL: bb4: +; CHECK-NOT: and +; CHECK: ret i32 %[[A1]] + %and = and i32 %load1, 65535 + ret i32 %and +} + +; Test for CodeGenPrepare::optimizeLoadExt(): check case of zext-able +; load feeding a phi in the same block. +define void @test_free_zext3(i32* %ptr, i32* %ptr2, i32* %dst, i64* %c) { +; CHECK-LABEL: @test_free_zext3( +bb1: +; CHECK-LABEL: bb1: +; CHECK: %[[T1:.*]] = load +; CHECK: %[[A1:.*]] = and i32 %[[T1]], 65535 + %load1 = load i32, i32* %ptr, align 4 + br label %loop +loop: +; CHECK-LABEL: loop: +; CHECK: phi i32 [ %[[A1]], %bb1 ], [ %[[A2]], %loop ] + %phi = phi i32 [ %load1, %bb1 ], [ %load2, %loop ] + %and = and i32 %phi, 65535 + store i32 %and, i32* %dst, align 4 + %idx = load volatile i64, i64* %c, align 4 + %addr = getelementptr inbounds i32, i32* %ptr2, i64 %idx +; CHECK: %[[T2:.*]] = load i32 +; CHECK: %[[A2:.*]] = and i32 %[[T2]], 65535 + %load2 = load i32, i32* %addr, align 4 + %cmp = icmp ne i64 %idx, 0 + br i1 %cmp, label %loop, label %end +end: + ret void +} diff --git a/test/Transforms/CodeGenPrepare/AArch64/widen_switch.ll b/test/Transforms/CodeGenPrepare/AArch64/widen_switch.ll new file mode 100644 index 0000000000000..172541a460801 --- /dev/null +++ b/test/Transforms/CodeGenPrepare/AArch64/widen_switch.ll @@ -0,0 +1,95 @@ +;; AArch64 is arbitralily chosen as a 32/64-bit RISC representative to show the transform in all tests. + +; RUN: opt < %s -codegenprepare -S -mtriple=aarch64-unknown-unknown | FileCheck %s --check-prefix=ARM64 + +; AArch64 widens to 32-bit. + +define i32 @widen_switch_i16(i32 %a) { +entry: + %trunc = trunc i32 %a to i16 + switch i16 %trunc, label %sw.default [ + i16 1, label %sw.bb0 + i16 -1, label %sw.bb1 + ] + +sw.bb0: + br label %return + +sw.bb1: + br label %return + +sw.default: + br label %return + +return: + %retval = phi i32 [ -1, %sw.default ], [ 0, %sw.bb0 ], [ 1, %sw.bb1 ] + ret i32 %retval + +; ARM64-LABEL: @widen_switch_i16( +; ARM64: %0 = zext i16 %trunc to i32 +; ARM64-NEXT: switch i32 %0, label %sw.default [ +; ARM64-NEXT: i32 1, label %return +; ARM64-NEXT: i32 65535, label %sw.bb1 +} + +; Widen to 32-bit from a smaller, non-native type. + +define i32 @widen_switch_i17(i32 %a) { +entry: + %trunc = trunc i32 %a to i17 + switch i17 %trunc, label %sw.default [ + i17 10, label %sw.bb0 + i17 -1, label %sw.bb1 + ] + +sw.bb0: + br label %return + +sw.bb1: + br label %return + +sw.default: + br label %return + +return: + %retval = phi i32 [ -1, %sw.default ], [ 0, %sw.bb0 ], [ 1, %sw.bb1 ] + ret i32 %retval + +; ARM64-LABEL: @widen_switch_i17( +; ARM64: %0 = zext i17 %trunc to i32 +; ARM64-NEXT: switch i32 %0, label %sw.default [ +; ARM64-NEXT: i32 10, label %return +; ARM64-NEXT: i32 131071, label %sw.bb1 +} + +; If the switch condition is a sign-extended function argument, then the +; condition and cases should be sign-extended rather than zero-extended +; because the sign-extension can be optimized away. + +define i32 @widen_switch_i16_sext(i2 signext %a) { +entry: + switch i2 %a, label %sw.default [ + i2 1, label %sw.bb0 + i2 -1, label %sw.bb1 + ] + +sw.bb0: + br label %return + +sw.bb1: + br label %return + +sw.default: + br label %return + +return: + %retval = phi i32 [ -1, %sw.default ], [ 0, %sw.bb0 ], [ 1, %sw.bb1 ] + ret i32 %retval + +; ARM64-LABEL: @widen_switch_i16_sext( +; ARM64: %0 = sext i2 %a to i32 +; ARM64-NEXT: switch i32 %0, label %sw.default [ +; ARM64-NEXT: i32 1, label %return +; ARM64-NEXT: i32 -1, label %sw.bb1 +} + diff --git a/test/Transforms/CodeGenPrepare/X86/catchpad-phi-cast.ll b/test/Transforms/CodeGenPrepare/X86/catchpad-phi-cast.ll new file mode 100644 index 0000000000000..8c5e01e3634f8 --- /dev/null +++ b/test/Transforms/CodeGenPrepare/X86/catchpad-phi-cast.ll @@ -0,0 +1,118 @@ +; RUN: opt -codegenprepare -S < %s | FileCheck %s + +; The following target lines are needed for the test to exercise what it should. +; Without these lines, CodeGenPrepare does not try to sink the bitcasts. +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc" + +declare i32 @__CxxFrameHandler3(...) + +declare void @f() + +declare void @g(i8*) +declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #2 + +; CodeGenPrepare will want to sink these bitcasts, but it selects the catchpad +; blocks as the place to which the bitcast should be sunk. Since catchpads +; do not allow non-phi instructions before the terminator, this isn't possible. + +; CHECK-LABEL: @test( +define void @test(i32* %addr) personality i32 (...)* @__CxxFrameHandler3 { +entry: + %x = getelementptr i32, i32* %addr, i32 1 + %p1 = bitcast i32* %x to i8* + invoke void @f() + to label %invoke.cont unwind label %catch1 + +; CHECK: invoke.cont: +; CHECK-NEXT: %y = getelementptr i32, i32* %addr, i32 2 +invoke.cont: + %y = getelementptr i32, i32* %addr, i32 2 + %p2 = bitcast i32* %y to i8* + invoke void @f() + to label %done unwind label %catch2 + +done: + ret void + +catch1: + %cs1 = catchswitch within none [label %handler1] unwind to caller + +handler1: + %cp1 = catchpad within %cs1 [] + br label %catch.shared +; CHECK: handler1: +; CHECK-NEXT: catchpad within %cs1 +; CHECK: %[[p1:[0-9]+]] = bitcast i32* %x to i8* + +catch2: + %cs2 = catchswitch within none [label %handler2] unwind to caller + +handler2: + %cp2 = catchpad within %cs2 [] + br label %catch.shared +; CHECK: handler2: +; CHECK: catchpad within %cs2 +; CHECK: %[[p2:[0-9]+]] = bitcast i32* %y to i8* + +; CHECK: catch.shared: +; CHECK-NEXT: %p = phi i8* [ %[[p1]], %handler1 ], [ %[[p2]], %handler2 ] +catch.shared: + %p = phi i8* [ %p1, %handler1 ], [ %p2, %handler2 ] + call void @g(i8* %p) + unreachable +} + +; CodeGenPrepare will want to hoist these llvm.dbg.value calls to the phi, but +; there is no insertion point in a catchpad block. + +; CHECK-LABEL: @test_dbg_value( +define void @test_dbg_value() personality i32 (...)* @__CxxFrameHandler3 { +entry: + %a = alloca i8 + %b = alloca i8 + invoke void @f() to label %next unwind label %catch.dispatch +next: + invoke void @f() to label %ret unwind label %catch.dispatch +ret: + ret void + +catch.dispatch: + %p = phi i8* [%a, %entry], [%b, %next] + %cs1 = catchswitch within none [label %catch] unwind to caller + +catch: + %cp1 = catchpad within %cs1 [] + tail call void @llvm.dbg.value(metadata i8* %p, i64 0, metadata !11, metadata !13), !dbg !14 + call void @g(i8* %p) + catchret from %cp1 to label %ret + +; CHECK: catch.dispatch: +; CHECK-NEXT: phi i8 +; CHECK-NEXT: catchswitch +; CHECK-NOT: llvm.dbg.value + +; CHECK: catch: +; CHECK-NEXT: catchpad +; CHECK-NEXT: call void @llvm.dbg.value +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.8.0 (trunk 254906) (llvm/trunk 254917)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: null, subprograms: !3) +!1 = !DIFile(filename: "t.c", directory: "D:\5Csrc\5Cllvm\5Cbuild") +!3 = !{!4} +!4 = distinct !DISubprogram(name: "test_dbg_value", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, variables: null) +!5 = !DISubroutineType(types: !6) +!6 = !{null} +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"PIC Level", i32 2} +!10 = !{!"clang version 3.8.0 (trunk 254906) (llvm/trunk 254917)"} +!11 = !DILocalVariable(name: "p", scope: !4, file: !1, line: 2, type: !12) +!12 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char) +!13 = !DIExpression() +!14 = !DILocation(line: 2, column: 8, scope: !4) +!15 = !DILocation(line: 3, column: 1, scope: !4) diff --git a/test/Transforms/CodeGenPrepare/X86/cttz-ctlz.ll b/test/Transforms/CodeGenPrepare/X86/cttz-ctlz.ll new file mode 100644 index 0000000000000..72d82e2a162e6 --- /dev/null +++ b/test/Transforms/CodeGenPrepare/X86/cttz-ctlz.ll @@ -0,0 +1,56 @@ +; RUN: opt -S -codegenprepare < %s | FileCheck %s --check-prefix=SLOW +; RUN: opt -S -codegenprepare -mattr=+bmi < %s | FileCheck %s --check-prefix=FAST_TZ +; RUN: opt -S -codegenprepare -mattr=+lzcnt < %s | FileCheck %s --check-prefix=FAST_LZ + +target triple = "x86_64-unknown-unknown" +target datalayout = "e-n32:64" + +; If the intrinsic is cheap, nothing should change. +; If the intrinsic is expensive, check if the input is zero to avoid the call. +; This is undoing speculation that may have been created by SimplifyCFG + InstCombine. + +define i64 @cttz(i64 %A) { +entry: + %z = call i64 @llvm.cttz.i64(i64 %A, i1 false) + ret i64 %z + +; SLOW-LABEL: @cttz( +; SLOW: entry: +; SLOW: %cmpz = icmp eq i64 %A, 0 +; SLOW: br i1 %cmpz, label %cond.end, label %cond.false +; SLOW: cond.false: +; SLOW: %z = call i64 @llvm.cttz.i64(i64 %A, i1 true) +; SLOW: br label %cond.end +; SLOW: cond.end: +; SLOW: %ctz = phi i64 [ 64, %entry ], [ %z, %cond.false ] +; SLOW: ret i64 %ctz + +; FAST_TZ-LABEL: @cttz( +; FAST_TZ: %z = call i64 @llvm.cttz.i64(i64 %A, i1 false) +; FAST_TZ: ret i64 %z +} + +define i64 @ctlz(i64 %A) { +entry: + %z = call i64 @llvm.ctlz.i64(i64 %A, i1 false) + ret i64 %z + +; SLOW-LABEL: @ctlz( +; SLOW: entry: +; SLOW: %cmpz = icmp eq i64 %A, 0 +; SLOW: br i1 %cmpz, label %cond.end, label %cond.false +; SLOW: cond.false: +; SLOW: %z = call i64 @llvm.ctlz.i64(i64 %A, i1 true) +; SLOW: br label %cond.end +; SLOW: cond.end: +; SLOW: %ctz = phi i64 [ 64, %entry ], [ %z, %cond.false ] +; SLOW: ret i64 %ctz + +; FAST_LZ-LABEL: @ctlz( +; FAST_LZ: %z = call i64 @llvm.ctlz.i64(i64 %A, i1 false) +; FAST_LZ: ret i64 %z +} + +declare i64 @llvm.cttz.i64(i64, i1) +declare i64 @llvm.ctlz.i64(i64, i1) + diff --git a/test/Transforms/CodeGenPrepare/X86/select.ll b/test/Transforms/CodeGenPrepare/X86/select.ll new file mode 100644 index 0000000000000..a26938ad5ee48 --- /dev/null +++ b/test/Transforms/CodeGenPrepare/X86/select.ll @@ -0,0 +1,141 @@ +; RUN: opt -codegenprepare -S < %s | FileCheck %s + +target triple = "x86_64-unknown-unknown" + +; Nothing to sink here, but this gets converted to a branch to +; avoid stalling an out-of-order CPU on a predictable branch. + +define i32 @no_sink(double %a, double* %b, i32 %x, i32 %y) { +entry: + %load = load double, double* %b, align 8 + %cmp = fcmp olt double %load, %a + %sel = select i1 %cmp, i32 %x, i32 %y + ret i32 %sel + +; CHECK-LABEL: @no_sink( +; CHECK: %load = load double, double* %b, align 8 +; CHECK: %cmp = fcmp olt double %load, %a +; CHECK: br i1 %cmp, label %select.end, label %select.false +; CHECK: select.false: +; CHECK: br label %select.end +; CHECK: select.end: +; CHECK: %sel = phi i32 [ %x, %entry ], [ %y, %select.false ] +; CHECK: ret i32 %sel +} + + +; An 'fdiv' is expensive, so sink it rather than speculatively execute it. + +define float @fdiv_true_sink(float %a, float %b) { +entry: + %div = fdiv float %a, %b + %cmp = fcmp ogt float %a, 1.0 + %sel = select i1 %cmp, float %div, float 2.0 + ret float %sel + +; CHECK-LABEL: @fdiv_true_sink( +; CHECK: %cmp = fcmp ogt float %a, 1.0 +; CHECK: br i1 %cmp, label %select.true.sink, label %select.end +; CHECK: select.true.sink: +; CHECK: %div = fdiv float %a, %b +; CHECK: br label %select.end +; CHECK: select.end: +; CHECK: %sel = phi float [ %div, %select.true.sink ], [ 2.000000e+00, %entry ] +; CHECK: ret float %sel +} + +define float @fdiv_false_sink(float %a, float %b) { +entry: + %div = fdiv float %a, %b + %cmp = fcmp ogt float %a, 3.0 + %sel = select i1 %cmp, float 4.0, float %div + ret float %sel + +; CHECK-LABEL: @fdiv_false_sink( +; CHECK: %cmp = fcmp ogt float %a, 3.0 +; CHECK: br i1 %cmp, label %select.end, label %select.false.sink +; CHECK: select.false.sink: +; CHECK: %div = fdiv float %a, %b +; CHECK: br label %select.end +; CHECK: select.end: +; CHECK: %sel = phi float [ 4.000000e+00, %entry ], [ %div, %select.false.sink ] +; CHECK: ret float %sel +} + +define float @fdiv_both_sink(float %a, float %b) { +entry: + %div1 = fdiv float %a, %b + %div2 = fdiv float %b, %a + %cmp = fcmp ogt float %a, 5.0 + %sel = select i1 %cmp, float %div1, float %div2 + ret float %sel + +; CHECK-LABEL: @fdiv_both_sink( +; CHECK: %cmp = fcmp ogt float %a, 5.0 +; CHECK: br i1 %cmp, label %select.true.sink, label %select.false.sink +; CHECK: select.true.sink: +; CHECK: %div1 = fdiv float %a, %b +; CHECK: br label %select.end +; CHECK: select.false.sink: +; CHECK: %div2 = fdiv float %b, %a +; CHECK: br label %select.end +; CHECK: select.end: +; CHECK: %sel = phi float [ %div1, %select.true.sink ], [ %div2, %select.false.sink ] +; CHECK: ret float %sel +} + +; An 'fadd' is not too expensive, so it's ok to speculate. + +define float @fadd_no_sink(float %a, float %b) { + %add = fadd float %a, %b + %cmp = fcmp ogt float 6.0, %a + %sel = select i1 %cmp, float %add, float 7.0 + ret float %sel + +; CHECK-LABEL: @fadd_no_sink( +; CHECK: %sel = select i1 %cmp, float %add, float 7.0 +} + +; Possible enhancement: sinkability is only calculated with the direct +; operand of the select, so we don't try to sink this. The fdiv cost is not +; taken into account. + +define float @fdiv_no_sink(float %a, float %b) { +entry: + %div = fdiv float %a, %b + %add = fadd float %div, %b + %cmp = fcmp ogt float %a, 1.0 + %sel = select i1 %cmp, float %add, float 8.0 + ret float %sel + +; CHECK-LABEL: @fdiv_no_sink( +; CHECK: %sel = select i1 %cmp, float %add, float 8.0 +} + +; Do not transform the CFG if the select operands may have side effects. + +declare i64* @bar(i32, i32, i32) +declare i64* @baz(i32, i32, i32) + +define i64* @calls_no_sink(i32 %in) { + %call1 = call i64* @bar(i32 1, i32 2, i32 3) + %call2 = call i64* @baz(i32 1, i32 2, i32 3) + %tobool = icmp ne i32 %in, 0 + %sel = select i1 %tobool, i64* %call1, i64* %call2 + ret i64* %sel + +; CHECK-LABEL: @calls_no_sink( +; CHECK: %sel = select i1 %tobool, i64* %call1, i64* %call2 +} + +define i32 @sdiv_no_sink(i32 %a, i32 %b) { + %div1 = sdiv i32 %a, %b + %div2 = sdiv i32 %b, %a + %cmp = icmp sgt i32 %a, 5 + %sel = select i1 %cmp, i32 %div1, i32 %div2 + ret i32 %sel + +; CHECK-LABEL: @sdiv_no_sink( +; CHECK: %sel = select i1 %cmp, i32 %div1, i32 %div2 +} + diff --git a/test/Transforms/CodeGenPrepare/X86/widen_switch.ll b/test/Transforms/CodeGenPrepare/X86/widen_switch.ll new file mode 100644 index 0000000000000..53c9cc0735587 --- /dev/null +++ b/test/Transforms/CodeGenPrepare/X86/widen_switch.ll @@ -0,0 +1,95 @@ +;; x86 is chosen to show the transform when 8-bit and 16-bit registers are available. + +; RUN: opt < %s -codegenprepare -S -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefix=X86 + +; No change for x86 because 16-bit registers are part of the architecture. + +define i32 @widen_switch_i16(i32 %a) { +entry: + %trunc = trunc i32 %a to i16 + switch i16 %trunc, label %sw.default [ + i16 1, label %sw.bb0 + i16 -1, label %sw.bb1 + ] + +sw.bb0: + br label %return + +sw.bb1: + br label %return + +sw.default: + br label %return + +return: + %retval = phi i32 [ -1, %sw.default ], [ 0, %sw.bb0 ], [ 1, %sw.bb1 ] + ret i32 %retval + +; X86-LABEL: @widen_switch_i16( +; X86: %trunc = trunc i32 %a to i16 +; X86-NEXT: switch i16 %trunc, label %sw.default [ +; X86-NEXT: i16 1, label %return +; X86-NEXT: i16 -1, label %sw.bb1 +} + +; Widen to 32-bit from a smaller, non-native type. + +define i32 @widen_switch_i17(i32 %a) { +entry: + %trunc = trunc i32 %a to i17 + switch i17 %trunc, label %sw.default [ + i17 10, label %sw.bb0 + i17 -1, label %sw.bb1 + ] + +sw.bb0: + br label %return + +sw.bb1: + br label %return + +sw.default: + br label %return + +return: + %retval = phi i32 [ -1, %sw.default ], [ 0, %sw.bb0 ], [ 1, %sw.bb1 ] + ret i32 %retval + +; X86-LABEL: @widen_switch_i17( +; X86: %0 = zext i17 %trunc to i32 +; X86-NEXT: switch i32 %0, label %sw.default [ +; X86-NEXT: i32 10, label %return +; X86-NEXT: i32 131071, label %sw.bb1 +} + +; If the switch condition is a sign-extended function argument, then the +; condition and cases should be sign-extended rather than zero-extended +; because the sign-extension can be optimized away. + +define i32 @widen_switch_i16_sext(i2 signext %a) { +entry: + switch i2 %a, label %sw.default [ + i2 1, label %sw.bb0 + i2 -1, label %sw.bb1 + ] + +sw.bb0: + br label %return + +sw.bb1: + br label %return + +sw.default: + br label %return + +return: + %retval = phi i32 [ -1, %sw.default ], [ 0, %sw.bb0 ], [ 1, %sw.bb1 ] + ret i32 %retval + +; X86-LABEL: @widen_switch_i16_sext( +; X86: %0 = sext i2 %a to i8 +; X86-NEXT: switch i8 %0, label %sw.default [ +; X86-NEXT: i8 1, label %return +; X86-NEXT: i8 -1, label %sw.bb1 +} + diff --git a/test/Transforms/CodeGenPrepare/invariant.group.ll b/test/Transforms/CodeGenPrepare/invariant.group.ll new file mode 100644 index 0000000000000..e8f1e42ddcbb5 --- /dev/null +++ b/test/Transforms/CodeGenPrepare/invariant.group.ll @@ -0,0 +1,23 @@ +; RUN: opt -codegenprepare -S < %s | FileCheck %s + +@tmp = global i8 0 + +; CHECK-LABEL: define void @foo() { +define void @foo() { +enter: + ; CHECK-NOT: !invariant.group + ; CHECK-NOT: @llvm.invariant.group.barrier( + ; CHECK: %val = load i8, i8* @tmp + %val = load i8, i8* @tmp, !invariant.group !0 + %ptr = call i8* @llvm.invariant.group.barrier(i8* @tmp) + + ; CHECK: store i8 42, i8* @tmp + store i8 42, i8* %ptr, !invariant.group !0 + + ret void +} +; CHECK-LABEL: } + +declare i8* @llvm.invariant.group.barrier(i8*) + +!0 = !{!"something"}
\ No newline at end of file diff --git a/test/Transforms/CodeGenPrepare/statepoint-relocate.ll b/test/Transforms/CodeGenPrepare/statepoint-relocate.ll index b6898b373113b..b31dfe7f3fa63 100644 --- a/test/Transforms/CodeGenPrepare/statepoint-relocate.ll +++ b/test/Transforms/CodeGenPrepare/statepoint-relocate.ll @@ -10,9 +10,9 @@ define i32 @test_sor_basic(i32* %base) gc "statepoint-example" { ; CHECK: getelementptr i32, i32* %base-new, i32 15 entry: %ptr = getelementptr i32, i32* %base, i32 15 - %tok = call i32 (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, i32* %base, i32* %ptr) - %base-new = call i32* @llvm.experimental.gc.relocate.p0i32(i32 %tok, i32 7, i32 7) - %ptr-new = call i32* @llvm.experimental.gc.relocate.p0i32(i32 %tok, i32 7, i32 8) + %tok = call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, i32* %base, i32* %ptr) + %base-new = call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 7) + %ptr-new = call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 8) %ret = load i32, i32* %ptr-new ret i32 %ret } @@ -25,10 +25,10 @@ define i32 @test_sor_two_derived(i32* %base) gc "statepoint-example" { entry: %ptr = getelementptr i32, i32* %base, i32 15 %ptr2 = getelementptr i32, i32* %base, i32 12 - %tok = call i32 (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, i32* %base, i32* %ptr, i32* %ptr2) - %base-new = call i32* @llvm.experimental.gc.relocate.p0i32(i32 %tok, i32 7, i32 7) - %ptr-new = call i32* @llvm.experimental.gc.relocate.p0i32(i32 %tok, i32 7, i32 8) - %ptr2-new = call i32* @llvm.experimental.gc.relocate.p0i32(i32 %tok, i32 7, i32 9) + %tok = call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, i32* %base, i32* %ptr, i32* %ptr2) + %base-new = call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 7) + %ptr-new = call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 8) + %ptr2-new = call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 9) %ret = load i32, i32* %ptr-new ret i32 %ret } @@ -38,9 +38,9 @@ define i32 @test_sor_ooo(i32* %base) gc "statepoint-example" { ; CHECK: getelementptr i32, i32* %base-new, i32 15 entry: %ptr = getelementptr i32, i32* %base, i32 15 - %tok = call i32 (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, i32* %base, i32* %ptr) - %ptr-new = call i32* @llvm.experimental.gc.relocate.p0i32(i32 %tok, i32 7, i32 8) - %base-new = call i32* @llvm.experimental.gc.relocate.p0i32(i32 %tok, i32 7, i32 7) + %tok = call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, i32* %base, i32* %ptr) + %ptr-new = call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 8) + %base-new = call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 7) %ret = load i32, i32* %ptr-new ret i32 %ret } @@ -50,9 +50,9 @@ define i32 @test_sor_gep_smallint([3 x i32]* %base) gc "statepoint-example" { ; CHECK: getelementptr [3 x i32], [3 x i32]* %base-new, i32 0, i32 2 entry: %ptr = getelementptr [3 x i32], [3 x i32]* %base, i32 0, i32 2 - %tok = call i32 (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, [3 x i32]* %base, i32* %ptr) - %base-new = call [3 x i32]* @llvm.experimental.gc.relocate.p0a3i32(i32 %tok, i32 7, i32 7) - %ptr-new = call i32* @llvm.experimental.gc.relocate.p0i32(i32 %tok, i32 7, i32 8) + %tok = call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, [3 x i32]* %base, i32* %ptr) + %base-new = call [3 x i32]* @llvm.experimental.gc.relocate.p0a3i32(token %tok, i32 7, i32 7) + %ptr-new = call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 8) %ret = load i32, i32* %ptr-new ret i32 %ret } @@ -62,27 +62,66 @@ define i32 @test_sor_gep_largeint([3 x i32]* %base) gc "statepoint-example" { ; CHECK-NOT: getelementptr [3 x i32], [3 x i32]* %base-new, i32 0, i32 21 entry: %ptr = getelementptr [3 x i32], [3 x i32]* %base, i32 0, i32 21 - %tok = call i32 (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, [3 x i32]* %base, i32* %ptr) - %base-new = call [3 x i32]* @llvm.experimental.gc.relocate.p0a3i32(i32 %tok, i32 7, i32 7) - %ptr-new = call i32* @llvm.experimental.gc.relocate.p0i32(i32 %tok, i32 7, i32 8) + %tok = call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, [3 x i32]* %base, i32* %ptr) + %base-new = call [3 x i32]* @llvm.experimental.gc.relocate.p0a3i32(token %tok, i32 7, i32 7) + %ptr-new = call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 8) %ret = load i32, i32* %ptr-new ret i32 %ret } define i32 @test_sor_noop(i32* %base) gc "statepoint-example" { ; CHECK: getelementptr i32, i32* %base, i32 15 -; CHECK: call i32* @llvm.experimental.gc.relocate.p0i32(i32 %tok, i32 7, i32 8) -; CHECK: call i32* @llvm.experimental.gc.relocate.p0i32(i32 %tok, i32 7, i32 9) +; CHECK: call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 8) +; CHECK: call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 9) entry: %ptr = getelementptr i32, i32* %base, i32 15 %ptr2 = getelementptr i32, i32* %base, i32 12 - %tok = call i32 (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, i32* %base, i32* %ptr, i32* %ptr2) - %ptr-new = call i32* @llvm.experimental.gc.relocate.p0i32(i32 %tok, i32 7, i32 8) - %ptr2-new = call i32* @llvm.experimental.gc.relocate.p0i32(i32 %tok, i32 7, i32 9) + %tok = call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, i32* %base, i32* %ptr, i32* %ptr2) + %ptr-new = call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 8) + %ptr2-new = call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 9) %ret = load i32, i32* %ptr-new ret i32 %ret } -declare i32 @llvm.experimental.gc.statepoint.p0f_i1f(i64, i32, i1 ()*, i32, i32, ...) -declare i32* @llvm.experimental.gc.relocate.p0i32(i32, i32, i32) -declare [3 x i32]* @llvm.experimental.gc.relocate.p0a3i32(i32, i32, i32) +define i32 @test_sor_basic_wrong_order(i32* %base) gc "statepoint-example" { +; CHECK-LABEL: @test_sor_basic_wrong_order +; Here we have base relocate inserted after derived. Make sure that we don't +; produce uses of the relocated base pointer before it's definition. +entry: + %ptr = getelementptr i32, i32* %base, i32 15 + ; CHECK: getelementptr i32, i32* %base, i32 15 + %tok = call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, i32* %base, i32* %ptr) + %ptr-new = call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 8) + %base-new = call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 7) + ; CHECK: %base-new = call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 7) + ; CHECK-NEXT: getelementptr i32, i32* %base-new, i32 15 + %ret = load i32, i32* %ptr-new + ret i32 %ret +} + +define i32 @test_sor_noop_cross_bb(i1 %external-cond, i32* %base) gc "statepoint-example" { +; CHECK-LABEL: @test_sor_noop_cross_bb +; Here base relocate doesn't dominate derived relocate. Make sure that we don't +; produce undefined use of the relocated base pointer. +entry: + %ptr = getelementptr i32, i32* %base, i32 15 + ; CHECK: getelementptr i32, i32* %base, i32 15 + %tok = call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0, i32* %base, i32* %ptr) + br i1 %external-cond, label %left, label %right + +left: + %ptr-new = call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 8) + ; CHECK: call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 8) + %ret-new = load i32, i32* %ptr-new + ret i32 %ret-new + +right: + %ptr-base = call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 7) + ; CHECK: call i32* @llvm.experimental.gc.relocate.p0i32(token %tok, i32 7, i32 7) + %ret-base = load i32, i32* %ptr-base + ret i32 %ret-base +} + +declare token @llvm.experimental.gc.statepoint.p0f_i1f(i64, i32, i1 ()*, i32, i32, ...) +declare i32* @llvm.experimental.gc.relocate.p0i32(token, i32, i32) +declare [3 x i32]* @llvm.experimental.gc.relocate.p0a3i32(token, i32, i32) |
