|
| 1 | +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 |
| 2 | +; RUN: opt < %s -passes=licm -S | FileCheck %s |
| 3 | + |
| 4 | +; %fca.0 and %fca.1 should not be hoisted out of the loop because the ramp |
| 5 | +; function and resume function have different stack frames, so %pointer1 and |
| 6 | +; %pointer2 have different values before and after @llvm.coro.suspend. |
| 7 | + |
| 8 | +define ptr @f(i32 %n) presplitcoroutine { |
| 9 | +; CHECK-LABEL: define ptr @f( |
| 10 | +; CHECK-SAME: i32 [[N:%.*]]) #[[ATTR0:[0-9]+]] { |
| 11 | +; CHECK-NEXT: [[ENTRY:.*]]: |
| 12 | +; CHECK-NEXT: [[POINTER1:%.*]] = alloca ptr, align 8 |
| 13 | +; CHECK-NEXT: [[POINTER2:%.*]] = alloca ptr, align 8 |
| 14 | +; CHECK-NEXT: [[ID:%.*]] = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null) |
| 15 | +; CHECK-NEXT: [[SIZE:%.*]] = call i32 @llvm.coro.size.i32() |
| 16 | +; CHECK-NEXT: [[ALLOC:%.*]] = call ptr @malloc(i32 [[SIZE]]) |
| 17 | +; CHECK-NEXT: [[HDL:%.*]] = call noalias ptr @llvm.coro.begin(token [[ID]], ptr [[ALLOC]]) |
| 18 | +; CHECK-NEXT: br label %[[LOOP:.*]] |
| 19 | +; CHECK: [[LOOP]]: |
| 20 | +; CHECK-NEXT: [[N_VAL:%.*]] = phi i32 [ [[N]], %[[ENTRY]] ], [ [[INC:%.*]], %[[RESUME:.*]] ] |
| 21 | +; CHECK-NEXT: [[INC]] = add nsw i32 [[N_VAL]], 1 |
| 22 | +; CHECK-NEXT: call void @print(i32 [[N_VAL]]) |
| 23 | +; CHECK-NEXT: [[TMP0:%.*]] = call i8 @llvm.coro.suspend(token none, i1 false) |
| 24 | +; CHECK-NEXT: switch i8 [[TMP0]], label %[[SUSPEND_LOOPEXIT:.*]] [ |
| 25 | +; CHECK-NEXT: i8 0, label %[[RESUME]] |
| 26 | +; CHECK-NEXT: i8 1, label %[[CLEANUP:.*]] |
| 27 | +; CHECK-NEXT: ] |
| 28 | +; CHECK: [[RESUME]]: |
| 29 | +; CHECK-NEXT: [[FCA_0:%.*]] = insertvalue [2 x ptr] poison, ptr [[POINTER1]], 0 |
| 30 | +; CHECK-NEXT: [[FCA_1:%.*]] = insertvalue [2 x ptr] [[FCA_0]], ptr [[POINTER2]], 1 |
| 31 | +; CHECK-NEXT: call void @foo([2 x ptr] [[FCA_1]]) |
| 32 | +; CHECK-NEXT: br label %[[LOOP]] |
| 33 | +; CHECK: [[CLEANUP]]: |
| 34 | +; CHECK-NEXT: [[MEM:%.*]] = call ptr @llvm.coro.free(token [[ID]], ptr [[HDL]]) |
| 35 | +; CHECK-NEXT: call void @free(ptr [[MEM]]) |
| 36 | +; CHECK-NEXT: br label %[[SUSPEND:.*]] |
| 37 | +; CHECK: [[SUSPEND_LOOPEXIT]]: |
| 38 | +; CHECK-NEXT: br label %[[SUSPEND]] |
| 39 | +; CHECK: [[SUSPEND]]: |
| 40 | +; CHECK-NEXT: [[UNUSED:%.*]] = call i1 @llvm.coro.end(ptr [[HDL]], i1 false, token none) |
| 41 | +; CHECK-NEXT: ret ptr [[HDL]] |
| 42 | +; |
| 43 | +entry: |
| 44 | + %pointer1 = alloca ptr |
| 45 | + %pointer2 = alloca ptr |
| 46 | + %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null) |
| 47 | + %size = call i32 @llvm.coro.size.i32() |
| 48 | + %alloc = call ptr @malloc(i32 %size) |
| 49 | + %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %alloc) |
| 50 | + br label %loop |
| 51 | + |
| 52 | +loop: |
| 53 | + %n.val = phi i32 [ %n, %entry ], [ %inc, %resume ] |
| 54 | + %inc = add nsw i32 %n.val, 1 |
| 55 | + call void @print(i32 %n.val) |
| 56 | + %0 = call i8 @llvm.coro.suspend(token none, i1 false) |
| 57 | + switch i8 %0, label %suspend [i8 0, label %resume |
| 58 | + i8 1, label %cleanup] |
| 59 | + |
| 60 | +resume: |
| 61 | + %fca.0 = insertvalue [2 x ptr] poison, ptr %pointer1, 0 |
| 62 | + %fca.1 = insertvalue [2 x ptr] %fca.0, ptr %pointer2, 1 |
| 63 | + call void @foo([2 x ptr] %fca.1) |
| 64 | + br label %loop |
| 65 | + |
| 66 | +cleanup: |
| 67 | + %mem = call ptr @llvm.coro.free(token %id, ptr %hdl) |
| 68 | + call void @free(ptr %mem) |
| 69 | + br label %suspend |
| 70 | +suspend: |
| 71 | + %unused = call i1 @llvm.coro.end(ptr %hdl, i1 false, token none) |
| 72 | + ret ptr %hdl |
| 73 | +} |
| 74 | + |
| 75 | +declare void @free(ptr) |
| 76 | +declare ptr @malloc(i32) |
| 77 | +declare void @print(i32) |
| 78 | +declare void @foo([2 x ptr]) |
0 commit comments