Skip to content

Wrong LICM of expression involving pointer to alloca object in coroutine function #149604

@weiguozhi

Description

@weiguozhi

Compile following code

;  opt -passes=licm t19.ll -S

define ptr @f(i32 %n) presplitcoroutine {    
entry:    
  %pointer1 = alloca ptr    
  %pointer2 = alloca ptr    
  %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)    
  %size = call i32 @llvm.coro.size.i32()    
  %alloc = call ptr @malloc(i32 %size)    
  %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %alloc)    
  br label %loop    
    
loop:    
  %n.val = phi i32 [ %n, %entry ], [ %inc, %resume ]    
  %inc = add nsw i32 %n.val, 1    
  call void @print(i32 %n.val)    
  %0 = call i8 @llvm.coro.suspend(token none, i1 false)    
  switch i8 %0, label %suspend [i8 0, label %resume    
                                i8 1, label %cleanup]    
    
resume:    
  %fca.0 = insertvalue [2 x ptr] poison, ptr %pointer1, 0    // These 2 instructions
  %fca.1 = insertvalue [2 x ptr] %fca.0, ptr %pointer2, 1    // should not be hoisted
  call void @foo([2 x ptr] %fca.1)    
  br label %loop    
    
cleanup:    
  %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)    
  call void @free(ptr %mem)    
  br label %suspend    
suspend:    
  %unused = call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)    
  ret ptr %hdl    
}    
    
declare void @free(ptr)    
declare ptr @malloc(i32)    
declare void @print(i32)    
declare void @foo([2 x ptr])    

I got

entry:
  %pointer1 = alloca ptr, align 8
  %pointer2 = alloca ptr, align 8
  %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
  %size = call i32 @llvm.coro.size.i32()
  %alloc = call ptr @malloc(i32 %size)
  %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %alloc)
  %fca.0 = insertvalue [2 x ptr] poison, ptr %pointer1, 0           // %pointer1 and %pointer2 points to 
  %fca.1 = insertvalue [2 x ptr] %fca.0, ptr %pointer2, 1           // stack objects in ramp function
  br label %loop

loop:                                             ; preds = %resume, %entry
  %n.val = phi i32 [ %n, %entry ], [ %inc, %resume ]
  %inc = add nsw i32 %n.val, 1
  call void @print(i32 %n.val)
  %0 = call i8 @llvm.coro.suspend(token none, i1 false)
  switch i8 %0, label %suspend.loopexit [
    i8 0, label %resume
    i8 1, label %cleanup
  ]

resume:                                           ; preds = %loop
  call void @foo([2 x ptr] %fca.1)                                      // This instruction is in the resume function, it can't access ramp function stack objects
  br label %loop

cleanup:                                          ; preds = %loop
  ...

In the original code, two pointers are passed to function foo, so they can be accessed by foo, all of the related instructions (construction of %fca.1 and function call) will be placed in resume function of a coroutine, so there is no problem.

After LICM, the construction of %fca.1 is hoisted out of the loop, and later these instructions will be placed into ramp function. The pointers contained in %fca.1 points to stack objects of ramp function. Later %fca.1 is passed to resume function through coroutine frame, and used by function foo, unfortunately the ramp function frame does not exist at this time, so the pointers passed to foo are invalid.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions