Skip to content

Commit 754913c

Browse files
committed
[LoopInfo] Pointer to stack object may not be loop invariant in a coroutine function
A coroutine function may be split to ramp function and resume function, and they have different stack frames, so a pointer to stack objects may have different addresses depending on where it is used, so it's not a loop invariant.
1 parent a270fdf commit 754913c

File tree

2 files changed

+88
-2
lines changed

2 files changed

+88
-2
lines changed

llvm/lib/Analysis/LoopInfo.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,16 @@ static cl::opt<bool, true>
5959
//
6060

6161
bool Loop::isLoopInvariant(const Value *V) const {
62-
if (const Instruction *I = dyn_cast<Instruction>(V))
63-
return !contains(I);
62+
if (const Instruction *I = dyn_cast<Instruction>(V)) {
63+
// If V is a pointer to stack object and F is a coroutine function, then V
64+
// may not be loop invariant because the ramp function and resume function
65+
// have different stack frames.
66+
if (isa<AllocaInst>(I) &&
67+
I->getParent()->getParent()->isPresplitCoroutine())
68+
return false;
69+
else
70+
return !contains(I);
71+
}
6472
return true; // All non-instructions are loop invariant
6573
}
6674

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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

Comments
 (0)