authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-08-30 01:12:47-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-08-30 01:12:47-04:00
log56cc62a9c7bf9bfb1daff7dc60a75c380500ebce
treef65b8b9e7e7815d04630d5aab78b7b89b12b3152
parentfa9006f8d1aa95934f31d5bedfcd3949267c9e72

@ptrCast preserves larger alignment if applicable

See #37

2 files changed, 101 insertions(+), 76 deletions(-)

src/ir.cpp+94-76
...@@ -2232,7 +2232,7 @@ static IrInstruction *ir_build_align_cast(IrBuilder *irb, Scope *scope, AstNode...@@ -2232,7 +2232,7 @@ static IrInstruction *ir_build_align_cast(IrBuilder *irb, Scope *scope, AstNode
2232 instruction->align_bytes = align_bytes;2232 instruction->align_bytes = align_bytes;
2233 instruction->target = target;2233 instruction->target = target;
22342234
2235 ir_ref_instruction(align_bytes, irb->current_basic_block);2235 if (align_bytes) ir_ref_instruction(align_bytes, irb->current_basic_block);
2236 ir_ref_instruction(target, irb->current_basic_block);2236 ir_ref_instruction(target, irb->current_basic_block);
22372237
2238 return &instruction->base;2238 return &instruction->base;
...@@ -2950,8 +2950,8 @@ static IrInstruction *ir_instruction_ptrtypeof_get_dep(IrInstructionPtrTypeOf *i...@@ -2950,8 +2950,8 @@ static IrInstruction *ir_instruction_ptrtypeof_get_dep(IrInstructionPtrTypeOf *i
29502950
2951static IrInstruction *ir_instruction_aligncast_get_dep(IrInstructionAlignCast *instruction, size_t index) {2951static IrInstruction *ir_instruction_aligncast_get_dep(IrInstructionAlignCast *instruction, size_t index) {
2952 switch (index) {2952 switch (index) {
2953 case 0: return instruction->align_bytes;2953 case 0: return instruction->target;
2954 case 1: return instruction->target;2954 case 1: return instruction->align_bytes; // can be null
2955 default: return nullptr;2955 default: return nullptr;
2956 }2956 }
2957}2957}
...@@ -14512,6 +14512,80 @@ static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructio...@@ -14512,6 +14512,80 @@ static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructio
14512 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);14512 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
14513}14513}
1451414514
14515static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint32_t align_bytes, bool safety_check_on) {
14516 TypeTableEntry *target_type = target->value.type;
14517 assert(!type_is_invalid(target_type));
14518
14519 TypeTableEntry *result_type;
14520 uint32_t old_align_bytes;
14521
14522 if (target_type->id == TypeTableEntryIdPointer) {
14523 result_type = get_pointer_to_type_extra(ira->codegen,
14524 target_type->data.pointer.child_type,
14525 target_type->data.pointer.is_const, target_type->data.pointer.is_volatile,
14526 align_bytes,
14527 target_type->data.pointer.bit_offset, target_type->data.pointer.unaligned_bit_count);
14528 } else if (target_type->id == TypeTableEntryIdFn) {
14529 FnTypeId fn_type_id = target_type->data.fn.fn_type_id;
14530 old_align_bytes = fn_type_id.alignment;
14531 fn_type_id.alignment = align_bytes;
14532 result_type = get_fn_type(ira->codegen, &fn_type_id);
14533 } else if (target_type->id == TypeTableEntryIdMaybe &&
14534 target_type->data.maybe.child_type->id == TypeTableEntryIdPointer)
14535 {
14536 TypeTableEntry *ptr_type = target_type->data.maybe.child_type;
14537 old_align_bytes = ptr_type->data.pointer.alignment;
14538 TypeTableEntry *better_ptr_type = get_pointer_to_type_extra(ira->codegen,
14539 ptr_type->data.pointer.child_type,
14540 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
14541 align_bytes,
14542 ptr_type->data.pointer.bit_offset, ptr_type->data.pointer.unaligned_bit_count);
14543
14544 result_type = get_maybe_type(ira->codegen, better_ptr_type);
14545 } else if (target_type->id == TypeTableEntryIdMaybe &&
14546 target_type->data.maybe.child_type->id == TypeTableEntryIdFn)
14547 {
14548 FnTypeId fn_type_id = target_type->data.maybe.child_type->data.fn.fn_type_id;
14549 old_align_bytes = fn_type_id.alignment;
14550 fn_type_id.alignment = align_bytes;
14551 TypeTableEntry *fn_type = get_fn_type(ira->codegen, &fn_type_id);
14552 result_type = get_maybe_type(ira->codegen, fn_type);
14553 } else if (is_slice(target_type)) {
14554 TypeTableEntry *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;
14555 old_align_bytes = slice_ptr_type->data.pointer.alignment;
14556 TypeTableEntry *result_ptr_type = get_pointer_to_type_extra(ira->codegen,
14557 slice_ptr_type->data.pointer.child_type,
14558 slice_ptr_type->data.pointer.is_const, slice_ptr_type->data.pointer.is_volatile,
14559 align_bytes,
14560 slice_ptr_type->data.pointer.bit_offset, slice_ptr_type->data.pointer.unaligned_bit_count);
14561 result_type = get_slice_type(ira->codegen, result_ptr_type);
14562 } else {
14563 ir_add_error(ira, target,
14564 buf_sprintf("expected pointer or slice, found '%s'", buf_ptr(&target_type->name)));
14565 return ira->codegen->invalid_instruction;
14566 }
14567
14568 if (instr_is_comptime(target)) {
14569 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
14570 if (!val)
14571 return ira->codegen->invalid_instruction;
14572
14573 IrInstruction *result = ir_create_const(&ira->new_irb, target->scope, target->source_node, result_type);
14574 copy_const_val(&result->value, val, false);
14575 result->value.type = result_type;
14576 return result;
14577 }
14578
14579 IrInstruction *result;
14580 if (safety_check_on && align_bytes > old_align_bytes && align_bytes != 1) {
14581 result = ir_build_align_cast(&ira->new_irb, target->scope, target->source_node, nullptr, target);
14582 } else {
14583 result = ir_build_cast(&ira->new_irb, target->scope, target->source_node, result_type, target, CastOpNoop);
14584 }
14585 result->value.type = result_type;
14586 return result;
14587}
14588
14515static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) {14589static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) {
14516 IrInstruction *dest_type_value = instruction->dest_type->other;14590 IrInstruction *dest_type_value = instruction->dest_type->other;
14517 TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value);14591 TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value);
...@@ -14557,11 +14631,21 @@ static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruc...@@ -14557,11 +14631,21 @@ static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruc
14557 return ira->codegen->builtin_types.entry_invalid;14631 return ira->codegen->builtin_types.entry_invalid;
14558 }14632 }
1455914633
14560 IrInstruction *result = ir_build_ptr_cast(&ira->new_irb, instruction->base.scope,14634 IrInstruction *casted_ptr = ir_build_ptr_cast(&ira->new_irb, instruction->base.scope,
14561 instruction->base.source_node, nullptr, ptr);14635 instruction->base.source_node, nullptr, ptr);
14636 casted_ptr->value.type = dest_type;
14637
14638 // keep the bigger alignment, it can only help
14639 IrInstruction *result;
14640 if (src_align_bytes > dest_align_bytes) {
14641 result = ir_align_cast(ira, casted_ptr, src_align_bytes, false);
14642 if (type_is_invalid(result->value.type))
14643 return ira->codegen->builtin_types.entry_invalid;
14644 } else {
14645 result = casted_ptr;
14646 }
14562 ir_link_new_instruction(result, &instruction->base);14647 ir_link_new_instruction(result, &instruction->base);
14563 result->value.type = dest_type;14648 return result->value.type;
14564 return dest_type;
14565}14649}
1456614650
14567static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) {14651static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) {
...@@ -14961,81 +15045,15 @@ static TypeTableEntry *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstr...@@ -14961,81 +15045,15 @@ static TypeTableEntry *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstr
14961 return ira->codegen->builtin_types.entry_invalid;15045 return ira->codegen->builtin_types.entry_invalid;
1496215046
14963 IrInstruction *target = instruction->target->other;15047 IrInstruction *target = instruction->target->other;
14964 TypeTableEntry *target_type = target->value.type;15048 if (type_is_invalid(target->value.type))
14965 if (type_is_invalid(target_type))
14966 return ira->codegen->builtin_types.entry_invalid;15049 return ira->codegen->builtin_types.entry_invalid;
1496715050
14968 TypeTableEntry *result_type;15051 IrInstruction *result = ir_align_cast(ira, target, align_bytes, true);
14969 uint32_t old_align_bytes;15052 if (type_is_invalid(result->value.type))
14970
14971 if (target_type->id == TypeTableEntryIdPointer) {
14972 result_type = get_pointer_to_type_extra(ira->codegen,
14973 target_type->data.pointer.child_type,
14974 target_type->data.pointer.is_const, target_type->data.pointer.is_volatile,
14975 align_bytes,
14976 target_type->data.pointer.bit_offset, target_type->data.pointer.unaligned_bit_count);
14977 } else if (target_type->id == TypeTableEntryIdFn) {
14978 FnTypeId fn_type_id = target_type->data.fn.fn_type_id;
14979 old_align_bytes = fn_type_id.alignment;
14980 fn_type_id.alignment = align_bytes;
14981 result_type = get_fn_type(ira->codegen, &fn_type_id);
14982 } else if (target_type->id == TypeTableEntryIdMaybe &&
14983 target_type->data.maybe.child_type->id == TypeTableEntryIdPointer)
14984 {
14985 TypeTableEntry *ptr_type = target_type->data.maybe.child_type;
14986 old_align_bytes = ptr_type->data.pointer.alignment;
14987 TypeTableEntry *better_ptr_type = get_pointer_to_type_extra(ira->codegen,
14988 ptr_type->data.pointer.child_type,
14989 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
14990 align_bytes,
14991 ptr_type->data.pointer.bit_offset, ptr_type->data.pointer.unaligned_bit_count);
14992
14993 result_type = get_maybe_type(ira->codegen, better_ptr_type);
14994 } else if (target_type->id == TypeTableEntryIdMaybe &&
14995 target_type->data.maybe.child_type->id == TypeTableEntryIdFn)
14996 {
14997 FnTypeId fn_type_id = target_type->data.maybe.child_type->data.fn.fn_type_id;
14998 old_align_bytes = fn_type_id.alignment;
14999 fn_type_id.alignment = align_bytes;
15000 TypeTableEntry *fn_type = get_fn_type(ira->codegen, &fn_type_id);
15001 result_type = get_maybe_type(ira->codegen, fn_type);
15002 } else if (is_slice(target_type)) {
15003 TypeTableEntry *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;
15004 old_align_bytes = slice_ptr_type->data.pointer.alignment;
15005 TypeTableEntry *result_ptr_type = get_pointer_to_type_extra(ira->codegen,
15006 slice_ptr_type->data.pointer.child_type,
15007 slice_ptr_type->data.pointer.is_const, slice_ptr_type->data.pointer.is_volatile,
15008 align_bytes,
15009 slice_ptr_type->data.pointer.bit_offset, slice_ptr_type->data.pointer.unaligned_bit_count);
15010 result_type = get_slice_type(ira->codegen, result_ptr_type);
15011 } else {
15012 ir_add_error(ira, target,
15013 buf_sprintf("expected pointer or slice, found '%s'", buf_ptr(&target_type->name)));
15014 return ira->codegen->builtin_types.entry_invalid;15053 return ira->codegen->builtin_types.entry_invalid;
15015 }
1501615054
15017 if (instr_is_comptime(target)) {
15018 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
15019 if (!val)
15020 return ira->codegen->builtin_types.entry_invalid;
15021
15022 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
15023 copy_const_val(out_val, val, false);
15024 out_val->type = result_type;
15025 return result_type;
15026 }
15027
15028 IrInstruction *result;
15029 if (align_bytes > old_align_bytes && align_bytes != 1) {
15030 result = ir_build_align_cast(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
15031 align_bytes_inst, target);
15032 } else {
15033 result = ir_build_cast(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
15034 result_type, target, CastOpNoop);
15035 }
15036 ir_link_new_instruction(result, &instruction->base);15055 ir_link_new_instruction(result, &instruction->base);
15037 result->value.type = result_type;15056 return result->value.type;
15038 return result_type;
15039}15057}
1504015058
15041static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {15059static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
test/cases/align.zig+7
...@@ -136,3 +136,10 @@ test "generic function with align param" {...@@ -136,3 +136,10 @@ test "generic function with align param" {
136}136}
137137
138fn whyWouldYouEverDoThis(comptime align_bytes: u8) align align_bytes -> u8 { 0x1 }138fn whyWouldYouEverDoThis(comptime align_bytes: u8) align align_bytes -> u8 { 0x1 }
139
140
141test "@ptrCast preserves alignment of bigger source" {
142 var x: u32 align 16 = 1234;
143 const ptr = @ptrCast(&u8, &x);
144 assert(@typeOf(ptr) == &align 16 u8);
145}