diff --git a/lib/Transforms/Coroutines/CoroSplit.cpp b/lib/Transforms/Coroutines/CoroSplit.cpp index f122fe6f079..6ab56f25e8b 100644 --- a/lib/Transforms/Coroutines/CoroSplit.cpp +++ b/lib/Transforms/Coroutines/CoroSplit.cpp @@ -250,7 +250,7 @@ static Function *createClone(Function &F, Twine Suffix, coro::Shape &Shape, auto *FnTy = cast(FnPtrTy->getElementType()); Function *NewF = - Function::Create(FnTy, GlobalValue::LinkageTypes::InternalLinkage, + Function::Create(FnTy, GlobalValue::LinkageTypes::ExternalLinkage, F.getName() + Suffix, M); NewF->addParamAttr(0, Attribute::NonNull); NewF->addParamAttr(0, Attribute::NoAlias); @@ -265,7 +265,7 @@ static Function *createClone(Function &F, Twine Suffix, coro::Shape &Shape, SmallVector Returns; CloneFunctionInto(NewF, &F, VMap, /*ModuleLevelChanges=*/true, Returns); - NewF->setDSOLocal(true); + NewF->setLinkage(GlobalValue::LinkageTypes::InternalLinkage); // Remove old returns. for (ReturnInst *Return : Returns) diff --git a/test/Transforms/Coroutines/coro-split-hidden.ll b/test/Transforms/Coroutines/coro-split-hidden.ll new file mode 100644 index 00000000000..4d080db1696 --- /dev/null +++ b/test/Transforms/Coroutines/coro-split-hidden.ll @@ -0,0 +1,81 @@ +; Tests that coro-split can convert functions with hidden visibility. +; These may be generated by a frontend such as Clang, when inlining with +; '-fvisibility-inlines-hidden'. +; RUN: opt < %s -coro-split -S | FileCheck %s + +define hidden i8* @f() "coroutine.presplit"="1" { +entry: + %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null) + %need.alloc = call i1 @llvm.coro.alloc(token %id) + br i1 %need.alloc, label %dyn.alloc, label %begin + +dyn.alloc: + %size = call i32 @llvm.coro.size.i32() + %alloc = call i8* @malloc(i32 %size) + br label %begin + +begin: + %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ] + %hdl = call i8* @llvm.coro.begin(token %id, i8* %phi) + call void @print(i32 0) + %0 = call i8 @llvm.coro.suspend(token none, i1 false) + switch i8 %0, label %suspend [i8 0, label %resume + i8 1, label %cleanup] +resume: + call void @print(i32 1) + br label %cleanup + +cleanup: + %mem = call i8* @llvm.coro.free(token %id, i8* %hdl) + call void @free(i8* %mem) + br label %suspend +suspend: + call i1 @llvm.coro.end(i8* %hdl, i1 0) + ret i8* %hdl +} + +; CHECK-LABEL: hidden{{.*}}@f( +; CHECK: call i8* @malloc +; CHECK: @llvm.coro.begin(token %id, i8* %phi) +; CHECK: store void (%f.Frame*)* @f.resume, void (%f.Frame*)** %resume.addr +; CHECK: %[[SEL:.+]] = select i1 %need.alloc, void (%f.Frame*)* @f.destroy, void (%f.Frame*)* @f.cleanup +; CHECK: store void (%f.Frame*)* %[[SEL]], void (%f.Frame*)** %destroy.addr +; CHECK: call void @print(i32 0) +; CHECK-NOT: call void @print(i32 1) +; CHECK-NOT: call void @free( +; CHECK: ret i8* %hdl + +; CHECK-LABEL: internal{{.*}}@f.resume( +; CHECK-NOT: call i8* @malloc +; CHECK-NOT: call void @print(i32 0) +; CHECK: call void @print(i32 1) +; CHECK-NOT: call void @print(i32 0) +; CHECK: call void @free( +; CHECK: ret void + +; CHECK-LABEL: internal{{.*}}@f.destroy( +; CHECK-NOT: call i8* @malloc +; CHECK-NOT: call void @print( +; CHECK: call void @free( +; CHECK: ret void + +; CHECK-LABEL: internal{{.*}}@f.cleanup( +; CHECK-NOT: call i8* @malloc +; CHECK-NOT: call void @print( +; CHECK-NOT: call void @free( +; CHECK: ret void + +declare i8* @llvm.coro.free(token, i8*) +declare i32 @llvm.coro.size.i32() +declare i8 @llvm.coro.suspend(token, i1) +declare void @llvm.coro.resume(i8*) +declare void @llvm.coro.destroy(i8*) + +declare token @llvm.coro.id(i32, i8*, i8*, i8*) +declare i1 @llvm.coro.alloc(token) +declare i8* @llvm.coro.begin(token, i8*) +declare i1 @llvm.coro.end(i8*, i1) + +declare noalias i8* @malloc(i32) +declare void @print(i32) +declare void @free(i8*)