[llvm] r368789 - Generalize llvm.coro.suspend.retcon to allow an arbitrary number of arguments to be passed back to the continuation function.

John McCall via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 13 20:53:26 PDT 2019


Author: rjmccall
Date: Tue Aug 13 20:53:26 2019
New Revision: 368789

URL: http://llvm.org/viewvc/llvm-project?rev=368789&view=rev
Log:
Generalize llvm.coro.suspend.retcon to allow an arbitrary number of arguments to be passed back to the continuation function.

Added:
    llvm/trunk/test/Transforms/Coroutines/coro-retcon-resume-values.ll
    llvm/trunk/test/Transforms/Coroutines/coro-retcon-resume-values2.ll
Modified:
    llvm/trunk/include/llvm/IR/Intrinsics.td
    llvm/trunk/lib/Transforms/Coroutines/CoroInternal.h
    llvm/trunk/lib/Transforms/Coroutines/CoroSplit.cpp
    llvm/trunk/lib/Transforms/Coroutines/Coroutines.cpp
    llvm/trunk/test/Transforms/Coroutines/coro-retcon-once-value.ll
    llvm/trunk/test/Transforms/Coroutines/coro-retcon-once-value2.ll
    llvm/trunk/test/Transforms/Coroutines/coro-retcon-value.ll
    llvm/trunk/test/Transforms/Coroutines/coro-retcon.ll

Modified: llvm/trunk/include/llvm/IR/Intrinsics.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Intrinsics.td?rev=368789&r1=368788&r2=368789&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Intrinsics.td (original)
+++ llvm/trunk/include/llvm/IR/Intrinsics.td Tue Aug 13 20:53:26 2019
@@ -982,7 +982,7 @@ def int_coro_size : Intrinsic<[llvm_anyi
 
 def int_coro_save : Intrinsic<[llvm_token_ty], [llvm_ptr_ty], []>;
 def int_coro_suspend : Intrinsic<[llvm_i8_ty], [llvm_token_ty, llvm_i1_ty], []>;
-def int_coro_suspend_retcon : Intrinsic<[llvm_i1_ty], [llvm_vararg_ty], []>;
+def int_coro_suspend_retcon : Intrinsic<[llvm_any_ty], [llvm_vararg_ty], []>;
 def int_coro_prepare_retcon : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty],
                                         [IntrNoMem]>;
 

Modified: llvm/trunk/lib/Transforms/Coroutines/CoroInternal.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Coroutines/CoroInternal.h?rev=368789&r1=368788&r2=368789&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Coroutines/CoroInternal.h (original)
+++ llvm/trunk/lib/Transforms/Coroutines/CoroInternal.h Tue Aug 13 20:53:26 2019
@@ -171,7 +171,7 @@ struct LLVM_LIBRARY_VISIBILITY Shape {
            ABI == coro::ABI::RetconOnce);
     auto FTy = CoroBegin->getFunction()->getFunctionType();
 
-    // This is checked by AnyCoroIdRetconInst::isWellFormed().
+    // The safety of all this is checked by checkWFRetconPrototype.
     if (auto STy = dyn_cast<StructType>(FTy->getReturnType())) {
       return STy->elements().slice(1);
     } else {
@@ -179,6 +179,15 @@ struct LLVM_LIBRARY_VISIBILITY Shape {
     }
   }
 
+  ArrayRef<Type*> getRetconResumeTypes() const {
+    assert(ABI == coro::ABI::Retcon ||
+           ABI == coro::ABI::RetconOnce);
+
+    // The safety of all this is checked by checkWFRetconPrototype.
+    auto FTy = RetconLowering.ResumePrototype->getFunctionType();
+    return FTy->params().slice(1);
+  }
+
   CallingConv::ID getResumeFunctionCC() const {
     switch (ABI) {
     case coro::ABI::Switch:

Modified: llvm/trunk/lib/Transforms/Coroutines/CoroSplit.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Coroutines/CoroSplit.cpp?rev=368789&r1=368788&r2=368789&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Coroutines/CoroSplit.cpp (original)
+++ llvm/trunk/lib/Transforms/Coroutines/CoroSplit.cpp Tue Aug 13 20:53:26 2019
@@ -144,6 +144,7 @@ private:
   void createDeclaration();
   void replaceEntryBlock();
   Value *deriveNewFramePointer();
+  void replaceRetconSuspendUses();
   void replaceCoroSuspends();
   void replaceCoroEnds();
   void handleFinalSuspend();
@@ -402,6 +403,52 @@ static Function *createCloneDeclaration(
   return NewF;
 }
 
+/// Replace uses of the active llvm.coro.suspend.retcon call with the
+/// arguments to the continuation function.
+///
+/// This assumes that the builder has a meaningful insertion point.
+void CoroCloner::replaceRetconSuspendUses() {
+  assert(Shape.ABI == coro::ABI::Retcon ||
+         Shape.ABI == coro::ABI::RetconOnce);
+
+  auto NewS = VMap[ActiveSuspend];
+  if (NewS->use_empty()) return;
+
+  // Copy out all the continuation arguments after the buffer pointer into
+  // an easily-indexed data structure for convenience.
+  SmallVector<Value*, 8> Args;
+  for (auto I = std::next(NewF->arg_begin()), E = NewF->arg_end(); I != E; ++I)
+    Args.push_back(&*I);
+
+  // If the suspend returns a single scalar value, we can just do a simple
+  // replacement.
+  if (!isa<StructType>(NewS->getType())) {
+    assert(Args.size() == 1);
+    NewS->replaceAllUsesWith(Args.front());
+    return;
+  }
+
+  // Try to peephole extracts of an aggregate return.
+  for (auto UI = NewS->use_begin(), UE = NewS->use_end(); UI != UE; ) {
+    auto EVI = dyn_cast<ExtractValueInst>((UI++)->getUser());
+    if (!EVI || EVI->getNumIndices() != 1)
+      continue;
+
+    EVI->replaceAllUsesWith(Args[EVI->getIndices().front()]);
+    EVI->eraseFromParent();
+  }
+
+  // If we have no remaining uses, we're done.
+  if (NewS->use_empty()) return;
+
+  // Otherwise, we need to create an aggregate.
+  Value *Agg = UndefValue::get(NewS->getType());
+  for (size_t I = 0, E = Args.size(); I != E; ++I)
+    Agg = Builder.CreateInsertValue(Agg, Args[I], I);
+
+  NewS->replaceAllUsesWith(Agg);
+}
+
 void CoroCloner::replaceCoroSuspends() {
   Value *SuspendResult;
 
@@ -416,15 +463,12 @@ void CoroCloner::replaceCoroSuspends() {
     SuspendResult = Builder.getInt8(isSwitchDestroyFunction() ? 1 : 0);
     break;
 
-  // In continuation lowering, replace all of the suspend uses with false to
-  // indicate that they're not unwinding resumes.  We've already mapped the
-  // active suspend to the appropriate argument, so any other suspend values
-  // that are still being used must be from previous suspends.  It's UB to try
-  // to suspend during unwind, so they must be from regular resumes.
+  // In returned-continuation lowering, the arguments from earlier
+  // continuations are theoretically arbitrary, and they should have been
+  // spilled.
   case coro::ABI::RetconOnce:
   case coro::ABI::Retcon:
-    SuspendResult = Builder.getInt1(false);
-    break;
+    return;
   }
 
   for (AnyCoroSuspendInst *CS : Shape.CoroSuspends) {
@@ -619,14 +663,11 @@ void CoroCloner::create() {
 
   case coro::ABI::Retcon:
   case coro::ABI::RetconOnce:
-    // Replace the active suspend with the should-unwind argument.
-    // Coerce it to i1 if necessary.
+    // Replace uses of the active suspend with the corresponding
+    // continuation-function arguments.
     assert(ActiveSuspend != nullptr &&
            "no active suspend when lowering a continuation-style coroutine");
-    Value *ShouldUnwind = &*std::next(NewF->arg_begin());
-    if (!ShouldUnwind->getType()->isIntegerTy(1))
-      ShouldUnwind = Builder.CreateIsNotNull(ShouldUnwind);
-    VMap[ActiveSuspend]->replaceAllUsesWith(ShouldUnwind);
+    replaceRetconSuspendUses();
     break;
   }
 

Modified: llvm/trunk/lib/Transforms/Coroutines/Coroutines.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Coroutines/Coroutines.cpp?rev=368789&r1=368788&r2=368789&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Coroutines/Coroutines.cpp (original)
+++ llvm/trunk/lib/Transforms/Coroutines/Coroutines.cpp Tue Aug 13 20:53:26 2019
@@ -387,6 +387,7 @@ void coro::Shape::buildFrom(Function &F)
     // Determine the result value types, and make sure they match up with
     // the values passed to the suspends.
     auto ResultTys = getRetconResultTypes();
+    auto ResumeTys = getRetconResumeTypes();
 
     for (auto AnySuspend : CoroSuspends) {
       auto Suspend = dyn_cast<CoroSuspendRetconInst>(AnySuspend);
@@ -396,6 +397,7 @@ void coro::Shape::buildFrom(Function &F)
                            "coro.suspend.retcon");
       }
 
+      // Check that the argument types of the suspend match the results.
       auto SI = Suspend->value_begin(), SE = Suspend->value_end();
       auto RI = ResultTys.begin(), RE = ResultTys.end();
       for (; SI != SE && RI != RE; ++SI, ++RI) {
@@ -411,6 +413,26 @@ void coro::Shape::buildFrom(Function &F)
         Prototype->getFunctionType()->dump();
         report_fatal_error("wrong number of arguments to coro.suspend.retcon");
       }
+
+      // Check that the result type of the suspend matches the resume types.
+      Type *SResultTy = Suspend->getType();
+      ArrayRef<Type*> SuspendResultTys =
+        (isa<StructType>(SResultTy)
+           ? cast<StructType>(SResultTy)->elements()
+           : SResultTy); // forms an ArrayRef using SResultTy, be careful
+      if (SuspendResultTys.size() != ResumeTys.size()) {
+        Suspend->dump();
+        Prototype->getFunctionType()->dump();
+        report_fatal_error("wrong number of results from coro.suspend.retcon");
+      }
+      for (size_t I = 0, E = ResumeTys.size(); I != E; ++I) {
+        if (SuspendResultTys[I] != ResumeTys[I]) {
+          Suspend->dump();
+          Prototype->getFunctionType()->dump();
+          report_fatal_error("result from coro.suspend.retcon does not "
+                             "match corresponding prototype function param");
+        }
+      }
     }
     break;
   }
@@ -501,7 +523,7 @@ static void fail(const Instruction *I, c
 static void checkWFRetconPrototype(const AnyCoroIdRetconInst *I, Value *V) {
   auto F = dyn_cast<Function>(V->stripPointerCasts());
   if (!F)
-    fail(I, "llvm.coro.retcon.* prototype not a Function", V);
+    fail(I, "llvm.coro.id.retcon.* prototype not a Function", V);
 
   auto FT = F->getFunctionType();
 
@@ -517,23 +539,20 @@ static void checkWFRetconPrototype(const
       ResultOkay = false;
     }
     if (!ResultOkay)
-      fail(I, "llvm.coro.retcon prototype must return pointer as first result",
-           F);
+      fail(I, "llvm.coro.id.retcon prototype must return pointer as first "
+              "result", F);
 
     if (FT->getReturnType() !=
           I->getFunction()->getFunctionType()->getReturnType())
-      fail(I, "llvm.coro.retcon.* prototype return type must be same as"
+      fail(I, "llvm.coro.id.retcon prototype return type must be same as"
               "current function return type", F);
   } else {
     // No meaningful validation to do here for llvm.coro.id.unique.once.
   }
 
-  if (FT->getNumParams() != 2)
-    fail(I, "llvm.coro.retcon.* prototype must take exactly two parameters", F);
-  if (!FT->getParamType(0)->isPointerTy())
-    fail(I, "llvm.coro.retcon.* prototype must take pointer as 1st param", F);
-  if (!FT->getParamType(1)->isIntegerTy()) // an i1, but not for abi purposes
-    fail(I, "llvm.coro.retcon.* prototype must take integer as 2nd param", F);
+  if (FT->getNumParams() == 0 || !FT->getParamType(0)->isPointerTy())
+    fail(I, "llvm.coro.id.retcon.* prototype must take pointer as "
+            "its first parameter", F);
 }
 
 /// Check that the given value is a well-formed allocator.

Modified: llvm/trunk/test/Transforms/Coroutines/coro-retcon-once-value.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Coroutines/coro-retcon-once-value.ll?rev=368789&r1=368788&r2=368789&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/Coroutines/coro-retcon-once-value.ll (original)
+++ llvm/trunk/test/Transforms/Coroutines/coro-retcon-once-value.ll Tue Aug 13 20:53:26 2019
@@ -4,14 +4,14 @@ target triple = "x86_64-apple-macosx10.1
 
 define {i8*, i32} @f(i8* %buffer, i32* %array) {
 entry:
-  %id = call token @llvm.coro.id.retcon.once(i32 8, i32 8, i8* %buffer, i8* bitcast (void (i8*, i8)* @prototype to i8*), i8* bitcast (i8* (i32)* @allocate to i8*), i8* bitcast (void (i8*)* @deallocate to i8*))
+  %id = call token @llvm.coro.id.retcon.once(i32 8, i32 8, i8* %buffer, i8* bitcast (void (i8*, i1)* @prototype to i8*), i8* bitcast (i8* (i32)* @allocate to i8*), i8* bitcast (void (i8*)* @deallocate to i8*))
   %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
   %load = load i32, i32* %array
   %load.pos = icmp sgt i32 %load, 0
   br i1 %load.pos, label %pos, label %neg
 
 pos:
-  %unwind0 = call i1 (...) @llvm.coro.suspend.retcon(i32 %load)
+  %unwind0 = call i1 (...) @llvm.coro.suspend.retcon.i1(i32 %load)
   br i1 %unwind0, label %cleanup, label %pos.cont
 
 pos.cont:
@@ -19,7 +19,7 @@ pos.cont:
   br label %cleanup
 
 neg:
-  %unwind1 = call i1 (...) @llvm.coro.suspend.retcon(i32 0)
+  %unwind1 = call i1 (...) @llvm.coro.suspend.retcon.i1(i32 0)
   br i1 %unwind1, label %cleanup, label %neg.cont
 
 neg.cont:
@@ -37,9 +37,9 @@ cleanup:
 ; CHECK-NEXT:    store i32* %array, i32** [[T0]], align 8
 ; CHECK-NEXT:    %load = load i32, i32* %array, align 4
 ; CHECK-NEXT:    %load.pos = icmp sgt i32 %load, 0
-; CHECK-NEXT:    [[CONT:%.*]] = select i1 %load.pos, void (i8*, i8)* @f.resume.0, void (i8*, i8)* @f.resume.1
+; CHECK-NEXT:    [[CONT:%.*]] = select i1 %load.pos, void (i8*, i1)* @f.resume.0, void (i8*, i1)* @f.resume.1
 ; CHECK-NEXT:    [[VAL:%.*]] = select i1 %load.pos, i32 %load, i32 0
-; CHECK-NEXT:    [[CONT_CAST:%.*]] = bitcast void (i8*, i8)* [[CONT]] to i8*
+; CHECK-NEXT:    [[CONT_CAST:%.*]] = bitcast void (i8*, i1)* [[CONT]] to i8*
 ; CHECK-NEXT:    [[T0:%.*]] = insertvalue { i8*, i32 } undef, i8* [[CONT_CAST]], 0
 ; CHECK-NEXT:    [[T1:%.*]] = insertvalue { i8*, i32 } [[T0]], i32 [[VAL]], 1
 ; CHECK-NEXT:    ret { i8*, i32 } [[T1]]
@@ -47,8 +47,7 @@ cleanup:
 
 ; CHECK-LABEL: define internal void @f.resume.0(i8* noalias nonnull %0, i1 zeroext %1)
 ; CHECK-NEXT:  :
-; CHECK-NEXT:    [[T0:%.*]] = icmp eq i8 %1, 0
-; CHECK-NEXT:    br i1 [[T0]],
+; CHECK-NEXT:    br i1 %1,
 ; CHECK:       :
 ; CHECK-NEXT:    [[T0:%.*]] = bitcast i8* %0 to i32**
 ; CHECK-NEXT:    [[RELOAD:%.*]] = load i32*, i32** [[T0]], align 8
@@ -60,8 +59,7 @@ cleanup:
 
 ; CHECK-LABEL: define internal void @f.resume.1(i8* noalias nonnull %0, i1 zeroext %1)
 ; CHECK-NEXT:  :
-; CHECK-NEXT:    [[T0:%.*]] = icmp eq i8 %1, 0
-; CHECK-NEXT:    br i1 [[T0]],
+; CHECK-NEXT:    br i1 %1,
 ; CHECK:       :
 ; CHECK-NEXT:    [[T0:%.*]] = bitcast i8* %0 to i32**
 ; CHECK-NEXT:    [[RELOAD:%.*]] = load i32*, i32** [[T0]], align 8
@@ -81,8 +79,8 @@ entry:
   %value = extractvalue {i8*, i32} %result, 1
   call void @print(i32 %value)
   %cont = extractvalue {i8*, i32} %result, 0
-  %cont.cast = bitcast i8* %cont to void (i8*, i8)*
-  call void %cont.cast(i8* %buffer, i8 zeroext 0)
+  %cont.cast = bitcast i8* %cont to void (i8*, i1)*
+  call void %cont.cast(i8* %buffer, i1 zeroext 0)
   ret void
 }
 
@@ -95,19 +93,19 @@ entry:
 ; CHECK-NEXT:    store i32* %array, i32** [[BUFFER]], align 8
 ; CHECK-NEXT:    [[LOAD:%.*]] = load i32, i32* %array, align 4
 ; CHECK-NEXT:    [[LOAD_POS:%.*]] = icmp sgt i32 [[LOAD]], 0
-; CHECK-NEXT:    [[CONT:%.*]] = select i1 [[LOAD_POS]], void (i8*, i8)* @f.resume.0, void (i8*, i8)* @f.resume.1
+; CHECK-NEXT:    [[CONT:%.*]] = select i1 [[LOAD_POS]], void (i8*, i1)* @f.resume.0, void (i8*, i1)* @f.resume.1
 ; CHECK-NEXT:    [[VAL:%.*]] = select i1 [[LOAD_POS]], i32 [[LOAD]], i32 0
 ; CHECK-NEXT:    call void @print(i32 [[VAL]])
-; CHECK-NEXT:    call void [[CONT]](i8* nonnull [[BUFFER_CAST]], i8 zeroext 0)
+; CHECK-NEXT:    call void [[CONT]](i8* nonnull [[BUFFER_CAST]], i1 zeroext false)
 ; CHECK-NEXT:    ret void
 
 declare token @llvm.coro.id.retcon.once(i32, i32, i8*, i8*, i8*, i8*)
 declare i8* @llvm.coro.begin(token, i8*)
-declare i1 @llvm.coro.suspend.retcon(...)
+declare i1 @llvm.coro.suspend.retcon.i1(...)
 declare i1 @llvm.coro.end(i8*, i1)
 declare i8* @llvm.coro.prepare.retcon(i8*)
 
-declare void @prototype(i8*, i8 zeroext)
+declare void @prototype(i8*, i1 zeroext)
 
 declare noalias i8* @allocate(i32 %size)
 declare void @deallocate(i8* %ptr)

Modified: llvm/trunk/test/Transforms/Coroutines/coro-retcon-once-value2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Coroutines/coro-retcon-once-value2.ll?rev=368789&r1=368788&r2=368789&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/Coroutines/coro-retcon-once-value2.ll (original)
+++ llvm/trunk/test/Transforms/Coroutines/coro-retcon-once-value2.ll Tue Aug 13 20:53:26 2019
@@ -5,11 +5,11 @@ target triple = "x86_64-apple-macosx10.1
 define {i8*, i32*} @f(i8* %buffer, i32* %ptr) "coroutine.presplit"="1" {
 entry:
   %temp = alloca i32, align 4
-  %id = call token @llvm.coro.id.retcon.once(i32 8, i32 8, i8* %buffer, i8* bitcast (void (i8*, i8)* @prototype to i8*), i8* bitcast (i8* (i32)* @allocate to i8*), i8* bitcast (void (i8*)* @deallocate to i8*))
+  %id = call token @llvm.coro.id.retcon.once(i32 8, i32 8, i8* %buffer, i8* bitcast (void (i8*, i1)* @prototype to i8*), i8* bitcast (i8* (i32)* @allocate to i8*), i8* bitcast (void (i8*)* @deallocate to i8*))
   %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
   %oldvalue = load i32, i32* %ptr
   store i32 %oldvalue, i32* %temp
-  %unwind = call i1 (...) @llvm.coro.suspend.retcon(i32* %temp)
+  %unwind = call i1 (...) @llvm.coro.suspend.retcon.i1(i32* %temp)
   br i1 %unwind, label %cleanup, label %cont
 
 cont:
@@ -33,7 +33,7 @@ cleanup:
 ; CHECK-NEXT:    store i32* %ptr, i32** [[SPILL]]
 ; CHECK-NEXT:    %oldvalue = load i32, i32* %ptr
 ; CHECK-NEXT:    store i32 %oldvalue, i32* %temp
-; CHECK-NEXT:    [[T0:%.*]] = insertvalue { i8*, i32* } { i8* bitcast (void (i8*, i8)* @f.resume.0 to i8*), i32* undef }, i32* %temp, 1
+; CHECK-NEXT:    [[T0:%.*]] = insertvalue { i8*, i32* } { i8* bitcast (void (i8*, i1)* @f.resume.0 to i8*), i32* undef }, i32* %temp, 1
 ; CHECK-NEXT:    ret { i8*, i32* } [[T0]]
 ; CHECK-NEXT:  }
 
@@ -42,9 +42,8 @@ cleanup:
 ; CHECK-NEXT:    [[T0:%.*]] = bitcast i8* %0 to [[FRAME_T:%.*]]**
 ; CHECK-NEXT:    [[FRAME:%.*]] = load [[FRAME_T]]*, [[FRAME_T]]** [[T0]]
 ; CHECK-NEXT:    bitcast [[FRAME_T]]* [[FRAME]] to i8*
-; CHECK-NEXT:    [[T0:%.*]] = icmp ne i8 %1, 0
 ; CHECK-NEXT:    %temp = getelementptr inbounds [[FRAME_T]], [[FRAME_T]]* [[FRAME]], i32 0, i32 1
-; CHECK-NEXT:    br i1 [[T0]],
+; CHECK-NEXT:    br i1 %1,
 ; CHECK:       :
 ; CHECK-NEXT:    [[TEMP_SLOT:%.*]] = getelementptr inbounds [[FRAME_T]], [[FRAME_T]]* [[FRAME]], i32 0, i32 1
 ; CHECK-NEXT:    [[PTR_SLOT:%.*]] = getelementptr inbounds [[FRAME_T]], [[FRAME_T]]* [[FRAME]], i32 0, i32 0
@@ -60,11 +59,10 @@ cleanup:
 
 declare token @llvm.coro.id.retcon.once(i32, i32, i8*, i8*, i8*, i8*)
 declare i8* @llvm.coro.begin(token, i8*)
-declare i1 @llvm.coro.suspend.retcon(...)
+declare i1 @llvm.coro.suspend.retcon.i1(...)
 declare i1 @llvm.coro.end(i8*, i1)
-declare i8* @llvm.coro.prepare.retcon(i8*)
 
-declare void @prototype(i8*, i8 zeroext)
+declare void @prototype(i8*, i1 zeroext)
 
 declare noalias i8* @allocate(i32 %size)
 declare fastcc void @deallocate(i8* %ptr)

Added: llvm/trunk/test/Transforms/Coroutines/coro-retcon-resume-values.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Coroutines/coro-retcon-resume-values.ll?rev=368789&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/Coroutines/coro-retcon-resume-values.ll (added)
+++ llvm/trunk/test/Transforms/Coroutines/coro-retcon-resume-values.ll Tue Aug 13 20:53:26 2019
@@ -0,0 +1,85 @@
+; RUN: opt < %s -enable-coroutines -O2 -S | FileCheck %s
+
+define i8* @f(i8* %buffer, i32 %n) {
+entry:
+  %id = call token @llvm.coro.id.retcon(i32 8, i32 4, i8* %buffer, i8* bitcast (i8* (i8*, i32, i1)* @prototype to i8*), i8* bitcast (i8* (i32)* @allocate to i8*), i8* bitcast (void (i8*)* @deallocate to i8*))
+  %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
+  br label %loop
+
+loop:
+  %n.val = phi i32 [ %n, %entry ], [ %sum, %resume ]
+  %values = call { i32, i1 } (...) @llvm.coro.suspend.retcon.sl_i32i1s()
+  %finished = extractvalue { i32, i1 } %values, 1
+  br i1 %finished, label %cleanup, label %resume
+
+resume:
+  %input = extractvalue { i32, i1 } %values, 0
+  %sum = add i32 %n.val, %input
+  br label %loop
+
+cleanup:
+  call void @print(i32 %n.val)
+  call i1 @llvm.coro.end(i8* %hdl, i1 0)
+  unreachable
+}
+
+; CHECK-LABEL: define i8* @f(i8* %buffer, i32 %n)
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[T0:%.*]] = bitcast i8* %buffer to i32*
+; CHECK-NEXT:    store i32 %n, i32* [[T0]], align 4
+; CHECK-NEXT:    ret i8* bitcast (i8* (i8*, i32, i1)* @f.resume.0 to i8*)
+; CHECK-NEXT:  }
+
+; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull %0, i32 %1, i1 zeroext %2)
+; CHECK-NEXT:  :
+; CHECK-NEXT:    [[T0:%.*]] = bitcast i8* %0 to i32*
+; CHECK-NEXT:    [[T1:%.*]] = load i32, i32* [[T0]], align 4
+; CHECK-NEXT:    br i1 %2,
+; CHECK:       :
+; CHECK-NEXT:    %sum = add i32 [[T1]], %1
+; CHECK-NEXT:    store i32 %sum, i32* [[T0]], align 4
+; CHECK-NEXT:    ret i8* bitcast (i8* (i8*, i32, i1)* @f.resume.0 to i8*)
+; CHECK:       :
+; CHECK-NEXT:    call void @print(i32 [[T1]])
+; CHECK-NEXT:    ret i8* null
+; CHECK-NEXT:  }
+
+define i32 @main() {
+entry:
+  %0 = alloca [8 x i8], align 4
+  %buffer = bitcast [8 x i8]* %0 to i8*
+  %prepare = call i8* @llvm.coro.prepare.retcon(i8* bitcast (i8* (i8*, i32)* @f to i8*))
+  %f = bitcast i8* %prepare to i8* (i8*, i32)*
+  %cont0 = call i8* %f(i8* %buffer, i32 1)
+  %cont0.cast = bitcast i8* %cont0 to i8* (i8*, i32, i1)*
+  %cont1 = call i8* %cont0.cast(i8* %buffer, i32 2, i1 zeroext false)
+  %cont1.cast = bitcast i8* %cont1 to i8* (i8*, i32, i1)*
+  %cont2 = call i8* %cont1.cast(i8* %buffer, i32 4, i1 zeroext false)
+  %cont2.cast = bitcast i8* %cont2 to i8* (i8*, i32, i1)*
+  call i8* %cont2.cast(i8* %buffer, i32 100, i1 zeroext true)
+  ret i32 0
+}
+
+;   Unfortunately, we don't seem to fully optimize this right now due
+;   to some sort of phase-ordering thing.
+; CHECK-LABEL: define i32 @main
+; CHECK-NEXT:  entry:
+; CHECK:         [[BUFFER:%.*]] = alloca [8 x i8], align 4
+; CHECK:         [[SLOT:%.*]] = bitcast [8 x i8]* [[BUFFER]] to i32*
+; CHECK-NEXT:    store i32 7, i32* [[SLOT]], align 4
+; CHECK-NEXT:    call void @print(i32 7)
+; CHECK-NEXT:    ret i32 0
+
+declare token @llvm.coro.id.retcon(i32, i32, i8*, i8*, i8*, i8*)
+declare i8* @llvm.coro.begin(token, i8*)
+declare { i32, i1 } @llvm.coro.suspend.retcon.sl_i32i1s(...)
+declare i1 @llvm.coro.end(i8*, i1)
+declare i8* @llvm.coro.prepare.retcon(i8*)
+
+declare i8* @prototype(i8*, i32, i1 zeroext)
+
+declare noalias i8* @allocate(i32 %size)
+declare void @deallocate(i8* %ptr)
+
+declare void @print(i32)
+

Added: llvm/trunk/test/Transforms/Coroutines/coro-retcon-resume-values2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Coroutines/coro-retcon-resume-values2.ll?rev=368789&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/Coroutines/coro-retcon-resume-values2.ll (added)
+++ llvm/trunk/test/Transforms/Coroutines/coro-retcon-resume-values2.ll Tue Aug 13 20:53:26 2019
@@ -0,0 +1,100 @@
+; RUN: opt < %s -coro-split -coro-cleanup -S | FileCheck %s
+
+define i8* @f(i8* %buffer, i32 %n) "coroutine.presplit"="1" {
+entry:
+  %id = call token @llvm.coro.id.retcon(i32 8, i32 4, i8* %buffer, i8* bitcast (i8* (i8*, i32)* @prototype to i8*), i8* bitcast (i8* (i32)* @allocate to i8*), i8* bitcast (void (i8*)* @deallocate to i8*))
+  %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
+  %value0 = call i32 (...) @llvm.coro.suspend.retcon.i32()
+  %sum0 = call i32 @add(i32 %n, i32 %value0)
+  %value1 = call i32 (...) @llvm.coro.suspend.retcon.i32()
+  %sum1 = call i32 @add(i32 %sum0, i32 %value0)
+  %sum2 = call i32 @add(i32 %sum1, i32 %value1)
+  %value2 = call i32 (...) @llvm.coro.suspend.retcon.i32()
+  %sum3 = call i32 @add(i32 %sum2, i32 %value0)
+  %sum4 = call i32 @add(i32 %sum3, i32 %value1)
+  %sum5 = call i32 @add(i32 %sum4, i32 %value2)
+  call void @print(i32 %sum5)
+  call i1 @llvm.coro.end(i8* %hdl, i1 0)
+  unreachable
+}
+
+; CHECK-LABEL: define i8* @f(i8* %buffer, i32 %n)
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[ALLOC:%.*]] = call i8* @allocate(i32 20)
+; CHECK-NEXT:    [[T0:%.*]] = bitcast i8* %buffer to i8**
+; CHECK-NEXT:    store i8* [[ALLOC]], i8** [[T0]]
+; CHECK-NEXT:    [[FRAME:%.*]] = bitcast i8* [[ALLOC]] to [[FRAME_T:%.*]]*
+; CHECK-NEXT:    [[T0:%.*]] = getelementptr inbounds [[FRAME_T]], [[FRAME_T]]* [[FRAME]], i32 0, i32 0
+; CHECK-NEXT:    store i32 %n, i32* [[T0]]
+; CHECK-NEXT:    ret i8* bitcast (i8* (i8*, i32)* @f.resume.0 to i8*)
+; CHECK-NEXT:  }
+
+; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull %0, i32 %1)
+; CHECK-NEXT:  :
+; CHECK-NEXT:    [[T0:%.*]] = bitcast i8* %0 to [[FRAME_T:%.*]]**
+; CHECK-NEXT:    [[FRAME:%.*]] = load [[FRAME_T]]*, [[FRAME_T]]** [[T0]]
+; CHECK-NEXT:    [[VFRAME:%.*]] = bitcast [[FRAME_T]]* [[FRAME]] to i8*
+; CHECK-NEXT:    [[T0:%.*]] = getelementptr inbounds [[FRAME_T]], [[FRAME_T]]* [[FRAME]], i32 0, i32 1
+; CHECK-NEXT:    store i32 %1, i32* [[T0]]
+; CHECK-NEXT:    [[T0:%.*]] = getelementptr inbounds [[FRAME_T]], [[FRAME_T]]* [[FRAME]], i32 0, i32 0
+; CHECK-NEXT:    [[N:%.*]] = load i32, i32* [[T0]]
+; CHECK-NEXT:    %sum0 = call i32 @add(i32 [[N]], i32 %1)
+; CHECK-NEXT:    [[T0:%.*]] = getelementptr inbounds [[FRAME_T]], [[FRAME_T]]* [[FRAME]], i32 0, i32 2
+; CHECK-NEXT:    store i32 %sum0, i32* [[T0]]
+; CHECK-NEXT:    [[CONT:%.*]] = bitcast i8* (i8*, i32)* @f.resume.1 to i8*
+; CHECK-NEXT:    ret i8* [[CONT]]
+; CHECK-NEXT:  }
+
+; CHECK-LABEL: define internal i8* @f.resume.1(i8* noalias nonnull %0, i32 %1)
+; CHECK-NEXT:  :
+; CHECK-NEXT:    [[T0:%.*]] = bitcast i8* %0 to [[FRAME_T:%.*]]**
+; CHECK-NEXT:    [[FRAME:%.*]] = load [[FRAME_T]]*, [[FRAME_T]]** [[T0]]
+; CHECK-NEXT:    [[VFRAME:%.*]] = bitcast [[FRAME_T]]* [[FRAME]] to i8*
+; CHECK-NEXT:    [[T0:%.*]] = getelementptr inbounds [[FRAME_T]], [[FRAME_T]]* [[FRAME]], i32 0, i32 3
+; CHECK-NEXT:    store i32 %1, i32* [[T0]]
+; CHECK-NEXT:    [[T0:%.*]] = getelementptr inbounds [[FRAME_T]], [[FRAME_T]]* [[FRAME]], i32 0, i32 2
+; CHECK-NEXT:    [[SUM0:%.*]] = load i32, i32* [[T0]]
+; CHECK-NEXT:    [[T0:%.*]] = getelementptr inbounds [[FRAME_T]], [[FRAME_T]]* [[FRAME]], i32 0, i32 1
+; CHECK-NEXT:    [[VALUE0:%.*]] = load i32, i32* [[T0]]
+; CHECK-NEXT:    %sum1 = call i32 @add(i32 [[SUM0]], i32 [[VALUE0]])
+; CHECK-NEXT:    %sum2 = call i32 @add(i32 %sum1, i32 %1)
+; CHECK-NEXT:    [[T0:%.*]] = getelementptr inbounds [[FRAME_T]], [[FRAME_T]]* [[FRAME]], i32 0, i32 4
+; CHECK-NEXT:    store i32 %sum2, i32* [[T0]]
+; CHECK-NEXT:    [[CONT:%.*]] = bitcast i8* (i8*, i32)* @f.resume.2 to i8*
+; CHECK-NEXT:    ret i8* [[CONT]]
+; CHECK-NEXT:  }
+
+; CHECK-LABEL: define internal i8* @f.resume.2(i8* noalias nonnull %0, i32 %1)
+; CHECK-NEXT:  :
+; CHECK-NEXT:    [[T0:%.*]] = bitcast i8* %0 to [[FRAME_T:%.*]]**
+; CHECK-NEXT:    [[FRAME:%.*]] = load [[FRAME_T]]*, [[FRAME_T]]** [[T0]]
+; CHECK-NEXT:    [[VFRAME:%.*]] = bitcast [[FRAME_T]]* [[FRAME]] to i8*
+; CHECK-NEXT:    [[T0:%.*]] = getelementptr inbounds [[FRAME_T]], [[FRAME_T]]* [[FRAME]], i32 0, i32 4
+; CHECK-NEXT:    [[SUM2:%.*]] = load i32, i32* [[T0]]
+; CHECK-NEXT:    [[T0:%.*]] = getelementptr inbounds [[FRAME_T]], [[FRAME_T]]* [[FRAME]], i32 0, i32 3
+; CHECK-NEXT:    [[VALUE1:%.*]] = load i32, i32* [[T0]]
+; CHECK-NEXT:    [[T0:%.*]] = getelementptr inbounds [[FRAME_T]], [[FRAME_T]]* [[FRAME]], i32 0, i32 1
+; CHECK-NEXT:    [[VALUE0:%.*]] = load i32, i32* [[T0]]
+; CHECK-NEXT:    %sum3 = call i32 @add(i32 [[SUM2]], i32 [[VALUE0]])
+; CHECK-NEXT:    %sum4 = call i32 @add(i32 %sum3, i32 [[VALUE1]])
+; CHECK-NEXT:    %sum5 = call i32 @add(i32 %sum4, i32 %1)
+; CHECK-NEXT:    call void @print(i32 %sum5)
+; CHECK-NEXT:    [[CONT:%.*]] = bitcast [[FRAME_T]]* [[FRAME]] to i8*
+; CHECK-NEXT:    call void @deallocate(i8* [[CONT]])
+; CHECK-NEXT:    ret i8* null
+; CHECK-NEXT:  }
+
+declare token @llvm.coro.id.retcon(i32, i32, i8*, i8*, i8*, i8*)
+declare i8* @llvm.coro.begin(token, i8*)
+declare i32 @llvm.coro.suspend.retcon.i32(...)
+declare i1 @llvm.coro.end(i8*, i1)
+declare i8* @llvm.coro.prepare.retcon(i8*)
+
+declare i8* @prototype(i8*, i32)
+
+declare noalias i8* @allocate(i32 %size)
+declare void @deallocate(i8* %ptr)
+
+declare i32 @add(i32, i32)
+declare void @print(i32)
+

Modified: llvm/trunk/test/Transforms/Coroutines/coro-retcon-value.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Coroutines/coro-retcon-value.ll?rev=368789&r1=368788&r2=368789&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/Coroutines/coro-retcon-value.ll (original)
+++ llvm/trunk/test/Transforms/Coroutines/coro-retcon-value.ll Tue Aug 13 20:53:26 2019
@@ -9,7 +9,8 @@ entry:
 
 loop:
   %n.val = phi i32 [ %n, %entry ], [ %inc, %resume ]
-  %unwind0 = call i1 (...) @llvm.coro.suspend.retcon(i32 %n.val)
+  %unwind = call i8 (...) @llvm.coro.suspend.retcon.i8(i32 %n.val)
+  %unwind0 = icmp ne i8 %unwind, 0
   br i1 %unwind0, label %cleanup, label %resume
 
 resume:
@@ -89,7 +90,7 @@ entry:
 
 declare token @llvm.coro.id.retcon(i32, i32, i8*, i8*, i8*, i8*)
 declare i8* @llvm.coro.begin(token, i8*)
-declare i1 @llvm.coro.suspend.retcon(...)
+declare i8 @llvm.coro.suspend.retcon.i8(...)
 declare i1 @llvm.coro.end(i8*, i1)
 declare i8* @llvm.coro.prepare.retcon(i8*)
 

Modified: llvm/trunk/test/Transforms/Coroutines/coro-retcon.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Coroutines/coro-retcon.ll?rev=368789&r1=368788&r2=368789&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/Coroutines/coro-retcon.ll (original)
+++ llvm/trunk/test/Transforms/Coroutines/coro-retcon.ll Tue Aug 13 20:53:26 2019
@@ -3,14 +3,14 @@
 
 define i8* @f(i8* %buffer, i32 %n) {
 entry:
-  %id = call token @llvm.coro.id.retcon(i32 8, i32 4, i8* %buffer, i8* bitcast (i8* (i8*, i8)* @prototype to i8*), i8* bitcast (i8* (i32)* @allocate to i8*), i8* bitcast (void (i8*)* @deallocate to i8*))
+  %id = call token @llvm.coro.id.retcon(i32 8, i32 4, i8* %buffer, i8* bitcast (i8* (i8*, i1)* @prototype to i8*), i8* bitcast (i8* (i32)* @allocate to i8*), i8* bitcast (void (i8*)* @deallocate to i8*))
   %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
   br label %loop
 
 loop:
   %n.val = phi i32 [ %n, %entry ], [ %inc, %resume ]
   call void @print(i32 %n.val)
-  %unwind0 = call i1 (...) @llvm.coro.suspend.retcon()
+  %unwind0 = call i1 (...) @llvm.coro.suspend.retcon.i1()
   br i1 %unwind0, label %cleanup, label %resume
 
 resume:
@@ -27,20 +27,19 @@ cleanup:
 ; CHECK-NEXT:    [[T0:%.*]] = bitcast i8* %buffer to i32*
 ; CHECK-NEXT:    store i32 %n, i32* [[T0]], align 4
 ; CHECK-NEXT:    call void @print(i32 %n)
-; CHECK-NEXT:    ret i8* bitcast (i8* (i8*, i8)* @f.resume.0 to i8*)
+; CHECK-NEXT:    ret i8* bitcast (i8* (i8*, i1)* @f.resume.0 to i8*)
 ; CHECK-NEXT:  }
 
 ; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull %0, i1 zeroext %1)
 ; CHECK-NEXT:  :
-; CHECK-NEXT:    [[T0:%.*]] = icmp eq i8 %1, 0
-; CHECK-NEXT:    br i1 [[T0]],
+; CHECK-NEXT:    br i1 %1,
 ; CHECK:       :
 ; CHECK-NEXT:    [[T0:%.*]] = bitcast i8* %0 to i32*
 ; CHECK-NEXT:    [[T1:%.*]] = load i32, i32* [[T0]], align 4
 ; CHECK-NEXT:    %inc = add i32 [[T1]], 1
 ; CHECK-NEXT:    store i32 %inc, i32* [[T0]], align 4
 ; CHECK-NEXT:    call void @print(i32 %inc)
-; CHECK-NEXT:    ret i8* bitcast (i8* (i8*, i8)* @f.resume.0 to i8*)
+; CHECK-NEXT:    ret i8* bitcast (i8* (i8*, i1)* @f.resume.0 to i8*)
 ; CHECK:       :
 ; CHECK-NEXT:    ret i8* null
 ; CHECK-NEXT:  }
@@ -52,12 +51,12 @@ entry:
   %prepare = call i8* @llvm.coro.prepare.retcon(i8* bitcast (i8* (i8*, i32)* @f to i8*))
   %f = bitcast i8* %prepare to i8* (i8*, i32)*
   %cont0 = call i8* %f(i8* %buffer, i32 4)
-  %cont0.cast = bitcast i8* %cont0 to i8* (i8*, i8)*
-  %cont1 = call i8* %cont0.cast(i8* %buffer, i8 zeroext 0)
-  %cont1.cast = bitcast i8* %cont1 to i8* (i8*, i8)*
-  %cont2 = call i8* %cont1.cast(i8* %buffer, i8 zeroext 0)
-  %cont2.cast = bitcast i8* %cont2 to i8* (i8*, i8)*
-  call i8* %cont2.cast(i8* %buffer, i8 zeroext 1)
+  %cont0.cast = bitcast i8* %cont0 to i8* (i8*, i1)*
+  %cont1 = call i8* %cont0.cast(i8* %buffer, i1 zeroext false)
+  %cont1.cast = bitcast i8* %cont1 to i8* (i8*, i1)*
+  %cont2 = call i8* %cont1.cast(i8* %buffer, i1 zeroext false)
+  %cont2.cast = bitcast i8* %cont2 to i8* (i8*, i1)*
+  call i8* %cont2.cast(i8* %buffer, i1 zeroext true)
   ret i32 0
 }
 
@@ -81,11 +80,11 @@ entry:
 
 declare token @llvm.coro.id.retcon(i32, i32, i8*, i8*, i8*, i8*)
 declare i8* @llvm.coro.begin(token, i8*)
-declare i1 @llvm.coro.suspend.retcon(...)
+declare i1 @llvm.coro.suspend.retcon.i1(...)
 declare i1 @llvm.coro.end(i8*, i1)
 declare i8* @llvm.coro.prepare.retcon(i8*)
 
-declare i8* @prototype(i8*, i8 zeroext)
+declare i8* @prototype(i8*, i1 zeroext)
 
 declare noalias i8* @allocate(i32 %size)
 declare void @deallocate(i8* %ptr)




More information about the llvm-commits mailing list