From ddd98a7f10767e2bea43fb35405a9414a02ecbdf Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 26 Mar 2020 12:34:16 -0400 Subject: [PATCH] prevent ptr cast from forcing alignment resolution unnecessarily --- src/ir.cpp | 44 +++++++++++++++++-------------- test/stage1/behavior/async_fn.zig | 16 +++++++++++ test/stage1/behavior/cast.zig | 4 +-- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index da6a5cfcad..a5b40cd5bc 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -237,7 +237,8 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ZigValue *val) static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, ZigValue *out_val, ZigValue *ptr_val); static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrInstGen *ptr, - IrInst *ptr_src, ZigType *dest_type, IrInst *dest_type_src, bool safety_check_on); + IrInst *ptr_src, ZigType *dest_type, IrInst *dest_type_src, bool safety_check_on, + bool keep_bigger_alignment); static ZigValue *ir_resolve_const(IrAnalyze *ira, IrInstGen *value, UndefAllowed undef_allowed); static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align); static IrInstGen *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInst* source_instr, IrInstGen *target, @@ -15066,7 +15067,8 @@ static IrInstGen *ir_analyze_cast(IrAnalyze *ira, IrInst *source_instr, dest_ptr_type = wanted_type->data.maybe.child_type; } if (dest_ptr_type != nullptr) { - return ir_analyze_ptr_cast(ira, source_instr, value, source_instr, wanted_type, source_instr, true); + return ir_analyze_ptr_cast(ira, source_instr, value, source_instr, wanted_type, source_instr, true, + false); } } @@ -15108,7 +15110,7 @@ static IrInstGen *ir_analyze_cast(IrAnalyze *ira, IrInst *source_instr, actual_type->data.pointer.child_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) { - return ir_analyze_ptr_cast(ira, source_instr, value, source_instr, wanted_type, source_instr, true); + return ir_analyze_ptr_cast(ira, source_instr, value, source_instr, wanted_type, source_instr, true, false); } // cast from integer to C pointer @@ -18576,7 +18578,7 @@ static IrInstGen *ir_resolve_result_raw(IrAnalyze *ira, IrInst *suspend_source_i result_loc->written = true; result_loc->resolved_loc = ir_analyze_ptr_cast(ira, suspend_source_instr, parent_result_loc, - &parent_result_loc->base, ptr_type, &result_cast->base.source_instruction->base, false); + &parent_result_loc->base, ptr_type, &result_cast->base.source_instruction->base, false, false); return result_loc->resolved_loc; } case ResultLocIdBitCast: { @@ -18670,7 +18672,7 @@ static IrInstGen *ir_resolve_result_raw(IrAnalyze *ira, IrInst *suspend_source_i result_loc->written = true; result_loc->resolved_loc = ir_analyze_ptr_cast(ira, suspend_source_instr, parent_result_loc, - &parent_result_loc->base, ptr_type, &result_bit_cast->base.source_instruction->base, false); + &parent_result_loc->base, ptr_type, &result_bit_cast->base.source_instruction->base, false, false); return result_loc->resolved_loc; } } @@ -22947,7 +22949,7 @@ static IrInstGen *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstSrcSwi ref_type->data.pointer.bit_offset_in_host, ref_type->data.pointer.host_int_bytes, ref_type->data.pointer.allow_zero); return ir_analyze_ptr_cast(ira, &instruction->base.base, target_value_ptr, - &instruction->target_value_ptr->base, new_target_value_ptr_type, &instruction->base.base, false); + &instruction->target_value_ptr->base, new_target_value_ptr_type, &instruction->base.base, false, false); } else { ir_add_error(ira, &instruction->base.base, buf_sprintf("switch on type '%s' provides no expression parameter", buf_ptr(&target_type->name))); @@ -23030,7 +23032,7 @@ static IrInstGen *ir_analyze_instruction_switch_else_var(IrAnalyze *ira, ref_type->data.pointer.bit_offset_in_host, ref_type->data.pointer.host_int_bytes, ref_type->data.pointer.allow_zero); return ir_analyze_ptr_cast(ira, &instruction->base.base, target_value_ptr, - &instruction->target_value_ptr->base, new_target_value_ptr_type, &instruction->base.base, false); + &instruction->target_value_ptr->base, new_target_value_ptr_type, &instruction->base.base, false, false); } return target_value_ptr; @@ -27814,7 +27816,8 @@ static IrInstGen *ir_align_cast(IrAnalyze *ira, IrInstGen *target, uint32_t alig } static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrInstGen *ptr, - IrInst *ptr_src, ZigType *dest_type, IrInst *dest_type_src, bool safety_check_on) + IrInst *ptr_src, ZigType *dest_type, IrInst *dest_type_src, bool safety_check_on, + bool keep_bigger_alignment) { Error err; @@ -27853,14 +27856,16 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier")); return ira->codegen->invalid_inst_gen; } - uint32_t src_align_bytes; - if ((err = resolve_ptr_align(ira, src_type, &src_align_bytes))) - return ira->codegen->invalid_inst_gen; - uint32_t dest_align_bytes; if ((err = resolve_ptr_align(ira, dest_type, &dest_align_bytes))) return ira->codegen->invalid_inst_gen; + uint32_t src_align_bytes = 0; + if (keep_bigger_alignment || dest_align_bytes != 1) { + if ((err = resolve_ptr_align(ira, src_type, &src_align_bytes))) + return ira->codegen->invalid_inst_gen; + } + if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_inst_gen; @@ -27935,16 +27940,15 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn } result->value->type = dest_type; - // Keep the bigger alignment, it can only help- - // unless the target is zero bits. - if (src_align_bytes > dest_align_bytes && type_has_bits(ira->codegen, dest_type)) { + // Keep the bigger alignment, it can only help- unless the target is zero bits. + if (keep_bigger_alignment && src_align_bytes > dest_align_bytes && type_has_bits(ira->codegen, dest_type)) { result = ir_align_cast(ira, result, src_align_bytes, false); } return result; } - if (dest_align_bytes > src_align_bytes) { + if (src_align_bytes != 0 && dest_align_bytes > src_align_bytes) { ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment")); add_error_note(ira->codegen, msg, ptr_src->source_node, buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&src_type->name), src_align_bytes)); @@ -27955,10 +27959,9 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn IrInstGen *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr, safety_check_on); - // Keep the bigger alignment, it can only help- - // unless the target is zero bits. + // Keep the bigger alignment, it can only help- unless the target is zero bits. IrInstGen *result; - if (src_align_bytes > dest_align_bytes && type_has_bits(ira->codegen, dest_type)) { + if (keep_bigger_alignment && src_align_bytes > dest_align_bytes && type_has_bits(ira->codegen, dest_type)) { result = ir_align_cast(ira, casted_ptr, src_align_bytes, false); if (type_is_invalid(result->value->type)) return ira->codegen->invalid_inst_gen; @@ -27979,8 +27982,9 @@ static IrInstGen *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstSrcPtrCa if (type_is_invalid(src_type)) return ira->codegen->invalid_inst_gen; + bool keep_bigger_alignment = true; return ir_analyze_ptr_cast(ira, &instruction->base.base, ptr, &instruction->ptr->base, - dest_type, &dest_type_value->base, instruction->safety_check_on); + dest_type, &dest_type_value->base, instruction->safety_check_on, keep_bigger_alignment); } static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ZigValue *val, size_t len) { diff --git a/test/stage1/behavior/async_fn.zig b/test/stage1/behavior/async_fn.zig index 6b99187563..958e9ea55f 100644 --- a/test/stage1/behavior/async_fn.zig +++ b/test/stage1/behavior/async_fn.zig @@ -1547,3 +1547,19 @@ test "noasync on function calls" { expectEqual(@as(i32, 42), noasync S1.c().b); expectEqual(@as(i32, 42), (try noasync S1.d()).b); } + +test "avoid forcing frame alignment resolution implicit cast to *c_void" { + const S = struct { + var x: ?*c_void = null; + + fn foo() bool { + suspend { + x = @frame(); + } + return true; + } + }; + var frame = async S.foo(); + resume @ptrCast(anyframe->bool, @alignCast(@alignOf(@Frame(S.foo)), S.x)); + expect(noasync await frame); +} diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig index 91e947e97d..b7bcb92c44 100644 --- a/test/stage1/behavior/cast.zig +++ b/test/stage1/behavior/cast.zig @@ -462,10 +462,10 @@ fn foobar(func: PFN_void) void { test "implicit ptr to *c_void" { var a: u32 = 1; - var ptr: *c_void = &a; + var ptr: *align(@alignOf(u32)) c_void = &a; var b: *u32 = @ptrCast(*u32, ptr); expect(b.* == 1); - var ptr2: ?*c_void = &a; + var ptr2: ?*align(@alignOf(u32)) c_void = &a; var c: *u32 = @ptrCast(*u32, ptr2.?); expect(c.* == 1); }