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 @@ -429,12 +429,15 @@ Align StructAlign; bool IsFinished = false; + Optional MaxFrameAlignment; + SmallVector Fields; DenseMap FieldIndexByKey; public: - FrameTypeBuilder(LLVMContext &Context, DataLayout const &DL) - : DL(DL), Context(Context) {} + FrameTypeBuilder(LLVMContext &Context, DataLayout const &DL, + Optional MaxFrameAlignment) + : DL(DL), Context(Context), MaxFrameAlignment(MaxFrameAlignment) {} /// Add a field to this structure for the storage of an `alloca` /// instruction. @@ -485,7 +488,8 @@ /// Add a field to this structure. LLVM_NODISCARD FieldIDType addField(Type *Ty, MaybeAlign FieldAlignment, - bool IsHeader = false) { + bool IsHeader = false, + bool IsSpillOfValue = false) { assert(!IsFinished && "adding fields to a finished builder"); assert(Ty && "must provide a type for a field"); @@ -500,8 +504,16 @@ // The field alignment might not be the type alignment, but we need // to remember the type alignment anyway to build the type. - Align TyAlignment = DL.getABITypeAlign(Ty); - if (!FieldAlignment) FieldAlignment = TyAlignment; + // If we are spilling values we don't need to worry about ABI alignment + // concerns. + auto ABIAlign = DL.getABITypeAlign(Ty); + Align TyAlignment = + (IsSpillOfValue && MaxFrameAlignment) + ? (*MaxFrameAlignment < ABIAlign ? *MaxFrameAlignment : ABIAlign) + : ABIAlign; + if (!FieldAlignment) { + FieldAlignment = TyAlignment; + } // Lay out header fields immediately. uint64_t Offset; @@ -1089,7 +1101,11 @@ return StructType::create(C, Name); }(); - FrameTypeBuilder B(C, DL); + // We will use this value to cap the alignment of spilled values. + Optional MaxFrameAlignment; + if (Shape.ABI == coro::ABI::Async) + MaxFrameAlignment = Shape.AsyncLowering.getContextAlignment(); + FrameTypeBuilder B(C, DL, MaxFrameAlignment); AllocaInst *PromiseAlloca = Shape.getPromiseAlloca(); Optional SwitchIndexFieldId; @@ -1142,7 +1158,8 @@ if (const Argument *A = dyn_cast(S.first)) if (A->hasByValAttr()) FieldType = FieldType->getPointerElementType(); - FieldIDType Id = B.addField(FieldType, None); + FieldIDType Id = + B.addField(FieldType, None, false /*header*/, true /*IsSpillOfValue*/); FrameData.setFieldIndex(S.first, Id); } diff --git a/llvm/test/Transforms/Coroutines/coro-async.ll b/llvm/test/Transforms/Coroutines/coro-async.ll --- a/llvm/test/Transforms/Coroutines/coro-async.ll +++ b/llvm/test/Transforms/Coroutines/coro-async.ll @@ -57,6 +57,7 @@ define swiftcc void @my_async_function(i8* swiftasync %async.ctxt, %async.task* %task, %async.actor* %actor) !dbg !1 { entry: %tmp = alloca { i64, i64 }, align 8 + %vector = alloca <4 x double>, align 16 %proj.1 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %tmp, i64 0, i32 0 %proj.2 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %tmp, i64 0, i32 1 @@ -88,6 +89,7 @@ store i8* %async.ctxt, i8** %callee_context.caller_context.addr %resume_proj_fun = bitcast i8*(i8*)* @resume_context_projection to i8* %callee = bitcast void(i8*, %async.task*, %async.actor*)* @asyncSuspend to i8* + %vector_spill = load <4 x double>, <4 x double>* %vector, align 16 %res = call {i8*, i8*, i8*} (i32, i8*, i8*, ...) @llvm.coro.suspend.async(i32 0, i8* %resume.func_ptr, i8* %resume_proj_fun, @@ -101,7 +103,7 @@ call void @some_user(i64 %val) %val.2 = load i64, i64* %proj.2 call void @some_user(i64 %val.2) - + store <4 x double> %vector_spill, <4 x double>* %vector, align 16 tail call swiftcc void @asyncReturn(i8* %async.ctxt, %async.task* %task.2, %async.actor* %actor) call i1 (i8*, i1, ...) @llvm.coro.end.async(i8* %hdl, i1 0) unreachable