diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -1634,7 +1634,7 @@ // // Note: If we change the strategy dealing with alignment, we need to refine // this casting. - if (GEP->getResultElementType() != Orig->getType()) + if (GEP->getType() != Orig->getType()) return Builder.CreateBitCast(GEP, Orig->getType(), Orig->getName() + Twine(".cast")); } diff --git a/llvm/test/Transforms/Coroutines/coro-frame-reuse-type-fix.ll b/llvm/test/Transforms/Coroutines/coro-frame-reuse-type-fix.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/Coroutines/coro-frame-reuse-type-fix.ll @@ -0,0 +1,93 @@ +; RUN: opt < %s --opaque-pointers=0 -passes='cgscc(coro-split),verify' -S | FileCheck %s +; Test that CoroFrame adds correct bitcast so pointer types match when frame +; slots get merged resulting in verifier problems and invalid bitcode. +; Note: This test is only relevant for typed pointer mode and can be removed +; when LLVM switches fully to opaque pointers. + +; just make sure the 2 allocas got merged into a single i8* slot on the frame; +; we are good if the IR verifier did not find a type mismatch. +; CHECK: %a.Frame = type { void (%a.Frame*)*, void (%a.Frame*)*, i8*, i1 } + +define void @a(i1 zeroext %cond) presplitcoroutine { +entry: + %v0 = alloca i8*, align 8 + %v1 = alloca i8, align 8 + + %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null) + %size = call i64 @llvm.coro.size.i64() + %alloc = call i8* @malloc(i64 %size) + %vFrame = call noalias nonnull i8* @llvm.coro.begin(token %id, i8* %alloc) + + br i1 %cond, label %btrue, label %bfalse + +btrue: + %p0 = bitcast i8** %v0 to i8* + call void @llvm.lifetime.start.p0i8(i64 8, i8* %p0) + store i8* null, i8** %v0, align 8 + + %suspend0 = call i8 @llvm.coro.suspend(token none, i1 false) + switch i8 %suspend0, label %e0 [ + i8 0, label %await.ready0 + i8 1, label %cont0 + ] +e0: + call void @llvm.lifetime.end.p0i8(i64 8, i8* %p0) + br label %exit + +await.ready0: + call void @consume(i8* %p0) + call void @llvm.lifetime.end.p0i8(i64 8, i8* %p0) + %dummy0 = call token @llvm.coro.save(i8* null) + br label %exit + +cont0: + call void @llvm.lifetime.end.p0i8(i64 8, i8* %p0) + br label %free + +bfalse: + call void @llvm.lifetime.start.p0i8(i64 1, i8* %v1) + store i8 42, i8* %v1, align 8 + + %suspend1 = call i8 @llvm.coro.suspend(token none, i1 false) + switch i8 %suspend1, label %e1 [ + i8 0, label %await.ready1 + i8 1, label %cont1 + ] + +e1: + call void @llvm.lifetime.end.p0i8(i64 1, i8* %v1) + br label %exit + +await.ready1: + call void @consume(i8* %v1) + call void @llvm.lifetime.end.p0i8(i64 1, i8* %v1) + %dummy1 = call token @llvm.coro.save(i8* null) + br label %exit + +cont1: + call void @llvm.lifetime.end.p0i8(i64 1, i8* %v1) + br label %free + +free: + %mem = call i8* @llvm.coro.free(token %id, i8* %vFrame) + call void @free(i8* %mem) + br label %exit + +exit: + call i1 @llvm.coro.end(i8* null, i1 false) + ret void +} + +declare i8* @malloc(i64) +declare void @free(i8*) +declare void @consume(i8*) + +declare token @llvm.coro.id(i32, i8* readnone, i8* nocapture readonly, i8*) +declare i64 @llvm.coro.size.i64() +declare i8* @llvm.coro.begin(token, i8* writeonly) +declare token @llvm.coro.save(i8*) +declare i8 @llvm.coro.suspend(token, i1) +declare i8* @llvm.coro.free(token, i8* nocapture readonly) +declare i1 @llvm.coro.end(i8*, i1) +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)