From d47801e7182a64c52891b34e749e35c396a002f8 Mon Sep 17 00:00:00 2001 From: John McCall Date: Wed, 14 Aug 2019 03:53:52 +0000 Subject: [PATCH] In coro.retcon lowering, don't explode if the optimizer messes around with the linkage of the prototype or the exact types of the yielded values. llvm-svn: 368793 --- llvm/lib/Transforms/Coroutines/CoroSplit.cpp | 17 +++++++++++++++++ llvm/lib/Transforms/Coroutines/Coroutines.cpp | 12 +++++++++++- llvm/test/Transforms/Coroutines/coro-retcon.ll | 20 ++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp index 318a012..1183352 100644 --- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp @@ -585,8 +585,25 @@ void CoroCloner::create() { SmallVector Returns; + // Ignore attempts to change certain attributes of the function. + // TODO: maybe there should be a way to suppress this during cloning? + auto savedVisibility = NewF->getVisibility(); + auto savedUnnamedAddr = NewF->getUnnamedAddr(); + auto savedDLLStorageClass = NewF->getDLLStorageClass(); + + // NewF's linkage (which CloneFunctionInto does *not* change) might not + // be compatible with the visibility of OrigF (which it *does* change), + // so protect against that. + auto savedLinkage = NewF->getLinkage(); + NewF->setLinkage(llvm::GlobalValue::ExternalLinkage); + CloneFunctionInto(NewF, &OrigF, VMap, /*ModuleLevelChanges=*/true, Returns); + NewF->setLinkage(savedLinkage); + NewF->setVisibility(savedVisibility); + NewF->setUnnamedAddr(savedUnnamedAddr); + NewF->setDLLStorageClass(savedDLLStorageClass); + auto &Context = NewF->getContext(); // Replace the attributes of the new function: diff --git a/llvm/lib/Transforms/Coroutines/Coroutines.cpp b/llvm/lib/Transforms/Coroutines/Coroutines.cpp index b81a085..1217657 100644 --- a/llvm/lib/Transforms/Coroutines/Coroutines.cpp +++ b/llvm/lib/Transforms/Coroutines/Coroutines.cpp @@ -405,7 +405,17 @@ void coro::Shape::buildFrom(Function &F) { auto SI = Suspend->value_begin(), SE = Suspend->value_end(); auto RI = ResultTys.begin(), RE = ResultTys.end(); for (; SI != SE && RI != RE; ++SI, ++RI) { - if ((*SI)->getType() != *RI) { + auto SrcTy = (*SI)->getType(); + if (SrcTy != *RI) { + // The optimizer likes to eliminate bitcasts leading into variadic + // calls, but that messes with our invariants. Re-insert the + // bitcast and ignore this type mismatch. + if (CastInst::isBitCastable(SrcTy, *RI)) { + auto BCI = new BitCastInst(*SI, *RI, "", Suspend); + SI->set(BCI); + continue; + } + #ifndef NDEBUG Suspend->dump(); Prototype->getFunctionType()->dump(); diff --git a/llvm/test/Transforms/Coroutines/coro-retcon.ll b/llvm/test/Transforms/Coroutines/coro-retcon.ll index 298ce57..5cd4cb6 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon.ll @@ -78,6 +78,25 @@ entry: ; CHECK-NEXT: call void @print(i32 [[INC]]) ; CHECK-NEXT: ret i32 0 +define hidden { i8*, i8* } @g(i8* %buffer, i16* %ptr) { +entry: + %id = call token @llvm.coro.id.retcon(i32 8, i32 4, i8* %buffer, i8* bitcast ({ i8*, i8* } (i8*, i1)* @g_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: + %ptr2 = bitcast i16* %ptr to i8* + %unwind0 = call i1 (...) @llvm.coro.suspend.retcon.i1(i8* %ptr2) + br i1 %unwind0, label %cleanup, label %resume + +resume: + br label %loop + +cleanup: + call i1 @llvm.coro.end(i8* %hdl, i1 0) + unreachable +} + 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.i1(...) @@ -85,6 +104,7 @@ declare i1 @llvm.coro.end(i8*, i1) declare i8* @llvm.coro.prepare.retcon(i8*) declare i8* @prototype(i8*, i1 zeroext) +declare {i8*,i8*} @g_prototype(i8*, i1 zeroext) declare noalias i8* @allocate(i32 %size) declare void @deallocate(i8* %ptr) -- 2.7.4