authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-07 14:54:58-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-07 14:54:58-05:00
log4a606893097748123c053a2df329e70050a70487
tree62ed77576ea5d2468eeddc57c1e89a4755242b52
parent3fce8008cc1303cb3a8ed6c2c48cbebc81dadaa8
signaturelock-open Commit is signed but in an unrecognized format.

more carefully calculate llvm field indexes

more correctly solves #4403

4 files changed, 118 insertions(+), 22 deletions(-)

doc/docgen.zig+2-2
......@@ -34,10 +34,10 @@ pub fn main() !void {
3434 const out_file_name = try (args_it.next(allocator) orelse @panic("expected output arg"));
3535 defer allocator.free(out_file_name);
3636
37 var in_file = try fs.File.openRead(in_file_name);
37 var in_file = try fs.cwd().openFile(in_file_name, .{.read = true});
3838 defer in_file.close();
3939
40 var out_file = try fs.File.openWrite(out_file_name);
40 var out_file = try fs.cwd().openFile(out_file_name, .{.write = true});
4141 defer out_file.close();
4242
4343 var file_in_stream = in_file.inStream();
lib/std/fs/file.zig+1-1
......@@ -195,7 +195,7 @@ pub const File = struct {
195195 }
196196 return Stat{
197197 .size = @bitCast(u64, info.StandardInformation.EndOfFile),
198 .mode = {},
198 .mode = 0,
199199 .atime = windows.fromSysTime(info.BasicInformation.LastAccessTime),
200200 .mtime = windows.fromSysTime(info.BasicInformation.LastWriteTime),
201201 .ctime = windows.fromSysTime(info.BasicInformation.CreationTime),
src/codegen.cpp+73-19
......@@ -343,22 +343,54 @@ static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {
343343 zig_unreachable();
344344}
345345
346struct CalcLLVMFieldIndex {
347 uint32_t offset;
348 uint32_t field_index;
349};
350
351static void calc_llvm_field_index_add(CodeGen *g, CalcLLVMFieldIndex *calc, ZigType *ty) {
352 if (!type_has_bits(ty)) return;
353 uint32_t ty_align = get_abi_alignment(g, ty);
354 if (calc->offset % ty_align != 0) {
355 uint32_t llvm_align = LLVMABIAlignmentOfType(g->target_data_ref, get_llvm_type(g, ty));
356 if (llvm_align >= ty_align) {
357 ty_align = llvm_align; // llvm's padding is sufficient
358 } else if (calc->offset) {
359 calc->field_index += 1; // zig will insert an extra padding field here
360 }
361 calc->offset += ty_align - (calc->offset % ty_align); // padding bytes
362 }
363 calc->offset += ty->abi_size;
364 calc->field_index += 1;
365}
366
346367// label (grep this): [fn_frame_struct_layout]
368static void frame_index_trace_arg_calc(CodeGen *g, CalcLLVMFieldIndex *calc, ZigType *return_type) {
369 calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // function pointer
370 calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // resume index
371 calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // awaiter index
372
373 if (type_has_bits(return_type)) {
374 calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // *ReturnType (callee's)
375 calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // *ReturnType (awaiter's)
376 calc_llvm_field_index_add(g, calc, return_type); // ReturnType
377 }
378}
379
347380static uint32_t frame_index_trace_arg(CodeGen *g, ZigType *return_type) {
348 // [0] *ReturnType (callee's)
349 // [1] *ReturnType (awaiter's)
350 // [2] ReturnType
351 uint32_t return_field_count = type_has_bits(return_type) ? 3 : 0;
352 return frame_ret_start + return_field_count;
381 CalcLLVMFieldIndex calc = {0};
382 frame_index_trace_arg_calc(g, &calc, return_type);
383 return calc.field_index;
353384}
354385
355386// label (grep this): [fn_frame_struct_layout]
356static uint32_t frame_index_arg(CodeGen *g, ZigType *return_type) {
357 bool have_stack_trace = codegen_fn_has_err_ret_tracing_arg(g, return_type);
358 // [0] *StackTrace (callee's)
359 // [1] *StackTrace (awaiter's)
360 uint32_t trace_field_count = have_stack_trace ? 2 : 0;
361 return frame_index_trace_arg(g, return_type) + trace_field_count;
387static void frame_index_arg_calc(CodeGen *g, CalcLLVMFieldIndex *calc, ZigType *return_type) {
388 frame_index_trace_arg_calc(g, calc, return_type);
389
390 if (codegen_fn_has_err_ret_tracing_arg(g, return_type)) {
391 calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // *StackTrace (callee's)
392 calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // *StackTrace (awaiter's)
393 }
362394}
363395
364396// label (grep this): [fn_frame_struct_layout]
......@@ -3922,7 +3954,9 @@ static void set_call_instr_sret(CodeGen *g, LLVMValueRef call_instr) {
39223954static void render_async_spills(CodeGen *g) {
39233955 ZigType *fn_type = g->cur_fn->type_entry;
39243956 ZigType *import = get_scope_import(&g->cur_fn->fndef_scope->base);
3925 uint32_t async_var_index = frame_index_arg(g, fn_type->data.fn.fn_type_id.return_type);
3957
3958 CalcLLVMFieldIndex arg_calc = {0};
3959 frame_index_arg_calc(g, &arg_calc, fn_type->data.fn.fn_type_id.return_type);
39263960 for (size_t var_i = 0; var_i < g->cur_fn->variable_list.length; var_i += 1) {
39273961 ZigVar *var = g->cur_fn->variable_list.at(var_i);
39283962
......@@ -3943,8 +3977,8 @@ static void render_async_spills(CodeGen *g) {
39433977 continue;
39443978 }
39453979
3946 var->value_ref = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, async_var_index, var->name);
3947 async_var_index += 1;
3980 calc_llvm_field_index_add(g, &arg_calc, var->var_type);
3981 var->value_ref = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, arg_calc.field_index - 1, var->name);
39483982 if (var->decl_node) {
39493983 var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
39503984 var->name, import->data.structure.root_struct->di_file,
......@@ -4267,17 +4301,35 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn
42674301 LLVMValueRef result;
42684302
42694303 if (callee_is_async) {
4270 uint32_t arg_start_i = frame_index_arg(g, fn_type->data.fn.fn_type_id.return_type);
4304 CalcLLVMFieldIndex arg_calc_start = {0};
4305 frame_index_arg_calc(g, &arg_calc_start, fn_type->data.fn.fn_type_id.return_type);
42714306
42724307 LLVMValueRef casted_frame;
42734308 if (instruction->new_stack != nullptr && instruction->fn_entry == nullptr) {
42744309 // We need the frame type to be a pointer to a struct that includes the args
4275 size_t field_count = arg_start_i + gen_param_values.length;
4310
4311 // Count ahead to determine how many llvm struct fields we need.
4312 CalcLLVMFieldIndex arg_calc = arg_calc_start;
4313 for (size_t i = 0; i < gen_param_types.length; i += 1) {
4314 calc_llvm_field_index_add(g, &arg_calc, gen_param_types.at(i));
4315 }
4316 size_t field_count = arg_calc.field_index;
4317
42764318 LLVMTypeRef *field_types = allocate_nonzero<LLVMTypeRef>(field_count);
42774319 LLVMGetStructElementTypes(LLVMGetElementType(LLVMTypeOf(frame_result_loc)), field_types);
4278 assert(LLVMCountStructElementTypes(LLVMGetElementType(LLVMTypeOf(frame_result_loc))) == arg_start_i);
4320 assert(LLVMCountStructElementTypes(LLVMGetElementType(LLVMTypeOf(frame_result_loc))) == arg_calc_start.field_index);
4321
4322 arg_calc = arg_calc_start;
42794323 for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) {
4280 field_types[arg_start_i + arg_i] = LLVMTypeOf(gen_param_values.at(arg_i));
4324 CalcLLVMFieldIndex prev = arg_calc;
4325 calc_llvm_field_index_add(g, &arg_calc, gen_param_types.at(arg_i));
4326 field_types[arg_calc.field_index - 1] = LLVMTypeOf(gen_param_values.at(arg_i));
4327 if (arg_calc.field_index - prev.field_index > 1) {
4328 // Padding field
4329 uint32_t pad_bytes = arg_calc.offset - prev.offset - gen_param_types.at(arg_i)->abi_size;
4330 LLVMTypeRef pad_llvm_type = LLVMArrayType(LLVMInt8Type(), pad_bytes);
4331 field_types[arg_calc.field_index - 2] = pad_llvm_type;
4332 }
42814333 }
42824334 LLVMTypeRef frame_with_args_type = LLVMStructType(field_types, field_count, false);
42834335 LLVMTypeRef ptr_frame_with_args_type = LLVMPointerType(frame_with_args_type, 0);
......@@ -4287,8 +4339,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn
42874339 casted_frame = frame_result_loc;
42884340 }
42894341
4342 CalcLLVMFieldIndex arg_calc = arg_calc_start;
42904343 for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) {
4291 LLVMValueRef arg_ptr = LLVMBuildStructGEP(g->builder, casted_frame, arg_start_i + arg_i, "");
4344 calc_llvm_field_index_add(g, &arg_calc, gen_param_types.at(arg_i));
4345 LLVMValueRef arg_ptr = LLVMBuildStructGEP(g->builder, casted_frame, arg_calc.field_index - 1, "");
42924346 gen_assign_raw(g, arg_ptr, get_pointer_to_type(g, gen_param_types.at(arg_i), true),
42934347 gen_param_values.at(arg_i));
42944348 }
test/stage1/behavior/async_fn.zig+42
......@@ -1329,3 +1329,45 @@ test "async call with @call" {
13291329 };
13301330 S.doTheTest();
13311331}
1332
1333test "async function passed 0-bit arg after non-0-bit arg" {
1334 const S = struct {
1335 var global_frame: anyframe = undefined;
1336 var global_int: i32 = 0;
1337
1338 fn foo() void {
1339 _ = async bar(1, .{});
1340 }
1341
1342 fn bar(x: i32, args: var) anyerror!void {
1343 global_frame = @frame();
1344 suspend;
1345 global_int = x;
1346 }
1347 };
1348 S.foo();
1349 resume S.global_frame;
1350 expect(S.global_int == 1);
1351}
1352
1353test "async function passed align(16) arg after align(8) arg" {
1354 const S = struct {
1355 var global_frame: anyframe = undefined;
1356 var global_int: u128 = 0;
1357
1358 fn foo() void {
1359 var a: u128 = 99;
1360 _ = async bar(10, .{a});
1361 }
1362
1363 fn bar(x: u64, args: var) anyerror!void {
1364 expect(x == 10);
1365 global_frame = @frame();
1366 suspend;
1367 global_int = args[0];
1368 }
1369 };
1370 S.foo();
1371 resume S.global_frame;
1372 expect(S.global_int == 99);
1373}