From 1c8cd268bedaa5bcfad7ab6a73fc85ded09e547f Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 16 Nov 2020 17:55:02 +0100 Subject: [PATCH] stage1: Fix asyncCall with non-abi-aligned arguments Make the code used to calculate the variable slot index into the frame match what's done during the structure layout calculation. Prevents a few nasty LLVM errors when such types are passed around. --- src/stage1/codegen.cpp | 22 ++++++++++++++++------ test/stage1/behavior/async_fn.zig | 19 +++++++++++++++++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index 53b9385e27..ff6ab2b223 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -242,14 +242,24 @@ struct CalcLLVMFieldIndex { static void calc_llvm_field_index_add(CodeGen *g, CalcLLVMFieldIndex *calc, ZigType *ty) { if (!type_has_bits(g, ty)) return; uint32_t ty_align = get_abi_alignment(g, ty); + if (calc->offset % ty_align != 0) { uint32_t llvm_align = LLVMABIAlignmentOfType(g->target_data_ref, get_llvm_type(g, ty)); - if (llvm_align >= ty_align) { - ty_align = llvm_align; // llvm's padding is sufficient - } else if (calc->offset) { - calc->field_index += 1; // zig will insert an extra padding field here - } - calc->offset += ty_align - (calc->offset % ty_align); // padding bytes + + // Alignment according to Zig. + uint32_t adj_offset = calc->offset + (ty_align - (calc->offset % ty_align)); + // Alignment according to LLVM. + uint32_t adj_llvm_offset = (calc->offset % llvm_align) ? + calc->offset + (llvm_align - (calc->offset % llvm_align)) : + calc->offset; + // Cannot under-align structure fields. + assert(adj_offset >= adj_llvm_offset); + + // Zig will insert an extra padding field here. + if (adj_offset != adj_llvm_offset) + calc->field_index += 1; + + calc->offset = adj_offset; } calc->offset += ty->abi_size; calc->field_index += 1; diff --git a/test/stage1/behavior/async_fn.zig b/test/stage1/behavior/async_fn.zig index d148d84064..eb9c3f5d07 100644 --- a/test/stage1/behavior/async_fn.zig +++ b/test/stage1/behavior/async_fn.zig @@ -1589,3 +1589,22 @@ test "@asyncCall with pass-by-value arguments" { F2, }); } + +test "@asyncCall with arguments having non-standard alignment" { + const F0: u64 = 0xbeefbeef; + const F1: u64 = 0xf00df00df00df00d; + + const S = struct { + pub fn f(_fill0: u32, s: struct { x: u64 align(16) }, _fill1: u64) callconv(.Async) void { + // The compiler inserts extra alignment for s, check that the + // generated code picks the right slot for fill1. + expectEqual(F0, _fill0); + expectEqual(F1, _fill1); + } + }; + + var buffer: [1024]u8 align(@alignOf(@Frame(S.f))) = undefined; + // The function pointer must not be comptime-known. + var t = S.f; + var frame_ptr = @asyncCall(&buffer, {}, t, .{ F0, undefined, F1 }); +}