1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 2; RUN: opt -passes=instcombine -S < %s | FileCheck %s 3 4declare void @llvm.init.trampoline(ptr, ptr, ptr) 5declare ptr @llvm.adjust.trampoline(ptr) 6declare i32 @f(ptr nest, i32) 7 8; Most common case 9define i32 @test0(i32 %n) !dbg !4 { 10; CHECK-LABEL: define i32 @test0 11; CHECK-SAME: (i32 [[N:%.*]]) !dbg [[DBG4:![0-9]+]] { 12; CHECK-NEXT: [[ALLOCA:%.*]] = alloca [10 x i8], align 16 13; CHECK-NEXT: call void @llvm.init.trampoline(ptr nonnull [[ALLOCA]], ptr nonnull @f, ptr null) 14; CHECK-NEXT: [[RET:%.*]] = call i32 @f(ptr nest null, i32 [[N]]), !dbg [[DBG10:![0-9]+]] 15; CHECK-NEXT: ret i32 [[RET]] 16; 17 %alloca = alloca [10 x i8], align 16 18 call void @llvm.init.trampoline(ptr %alloca, ptr @f, 19 ptr null) 20 %tramp = call ptr @llvm.adjust.trampoline(ptr %alloca) 21 %ret = call i32 %tramp(i32 %n), !dbg !10 22 ret i32 %ret 23 24} 25 26define i32 @test1(i32 %n, ptr %trampmem) { 27; CHECK-LABEL: define i32 @test1 28; CHECK-SAME: (i32 [[N:%.*]], ptr [[TRAMPMEM:%.*]]) { 29; CHECK-NEXT: call void @llvm.init.trampoline(ptr [[TRAMPMEM]], ptr nonnull @f, ptr null) 30; CHECK-NEXT: [[RET:%.*]] = call i32 @f(ptr nest null, i32 [[N]]) 31; CHECK-NEXT: ret i32 [[RET]] 32; 33 call void @llvm.init.trampoline(ptr %trampmem, 34 ptr @f, 35 ptr null) 36 %tramp = call ptr @llvm.adjust.trampoline(ptr %trampmem) 37 %ret = call i32 %tramp(i32 %n) 38 ret i32 %ret 39} 40 41define i32 @test2(i32 %n, ptr %trampmem) { 42; CHECK-LABEL: define i32 @test2 43; CHECK-SAME: (i32 [[N:%.*]], ptr [[TRAMPMEM:%.*]]) { 44; CHECK-NEXT: [[TRAMP:%.*]] = call ptr @llvm.adjust.trampoline(ptr [[TRAMPMEM]]) 45; CHECK-NEXT: [[RET:%.*]] = call i32 [[TRAMP]](i32 [[N]]) 46; CHECK-NEXT: ret i32 [[RET]] 47; 48 %tramp = call ptr @llvm.adjust.trampoline(ptr %trampmem) 49 %ret = call i32 %tramp(i32 %n) 50 ret i32 %ret 51} 52 53define i32 @test3(i32 %n, ptr %trampmem) { 54; CHECK-LABEL: define i32 @test3 55; CHECK-SAME: (i32 [[N:%.*]], ptr [[TRAMPMEM:%.*]]) { 56; CHECK-NEXT: call void @llvm.init.trampoline(ptr [[TRAMPMEM]], ptr nonnull @f, ptr null) 57; CHECK-NEXT: [[RET0:%.*]] = call i32 @f(ptr nest null, i32 [[N]]) 58; CHECK-NEXT: [[TRAMP1:%.*]] = call ptr @llvm.adjust.trampoline(ptr [[TRAMPMEM]]) 59; CHECK-NEXT: [[RET1:%.*]] = call i32 [[TRAMP1]](i32 [[N]]) 60; CHECK-NEXT: ret i32 [[RET1]] 61; 62 call void @llvm.init.trampoline(ptr %trampmem, 63 ptr @f, 64 ptr null) 65 66 %tramp0 = call ptr @llvm.adjust.trampoline(ptr %trampmem) 67 %ret0 = call i32 %tramp0(i32 %n) 68 69 ;; Not optimized since previous call could be writing. 70 %tramp1 = call ptr @llvm.adjust.trampoline(ptr %trampmem) 71 %ret1 = call i32 %tramp1(i32 %n) 72 73 ret i32 %ret1 74} 75 76define i32 @test4(i32 %n) { 77; CHECK-LABEL: define i32 @test4 78; CHECK-SAME: (i32 [[N:%.*]]) { 79; CHECK-NEXT: [[ALLOCA:%.*]] = alloca [10 x i8], align 16 80; CHECK-NEXT: call void @llvm.init.trampoline(ptr nonnull [[ALLOCA]], ptr nonnull @f, ptr null) 81; CHECK-NEXT: [[RET0:%.*]] = call i32 @f(ptr nest null, i32 [[N]]) 82; CHECK-NEXT: [[RET1:%.*]] = call i32 @f(ptr nest null, i32 [[N]]) 83; CHECK-NEXT: [[RET2:%.*]] = call i32 @f(ptr nest null, i32 [[N]]) 84; CHECK-NEXT: ret i32 [[RET2]] 85; 86 %alloca = alloca [10 x i8], align 16 87 call void @llvm.init.trampoline(ptr %alloca, ptr @f, 88 ptr null) 89 90 %tramp0 = call ptr @llvm.adjust.trampoline(ptr %alloca) 91 %ret0 = call i32 %tramp0(i32 %n) 92 93 %tramp1 = call ptr @llvm.adjust.trampoline(ptr %alloca) 94 %ret1 = call i32 %tramp0(i32 %n) 95 96 %tramp2 = call ptr @llvm.adjust.trampoline(ptr %alloca) 97 %ret2 = call i32 %tramp2(i32 %n) 98 99 ret i32 %ret2 100 101} 102 103!llvm.dbg.cu = !{!0} 104!llvm.module.flags = !{!3} 105 106!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.0 (trunk 127710)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !2) 107!1 = !DIFile(filename: "string.h", directory: "Game") 108!2 = !{} 109!3 = !{i32 1, !"Debug Info Version", i32 3} 110!4 = distinct !DISubprogram(name: "passthru", scope: !1, file: !1, line: 79, type: !5, isLocal: true, isDefinition: true, scopeLine: 79, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !8) 111!5 = !DISubroutineType(types: !6) 112!6 = !{!7} 113!7 = !DIDerivedType(tag: DW_TAG_pointer_type, scope: !0, baseType: null, size: 64, align: 64) 114!8 = !{!9} 115!9 = !DILocalVariable(name: "a", arg: 1, scope: !4, file: !1, line: 78, type: !7) 116!10 = !DILocation(line: 78, column: 28, scope: !4) 117