| ... | @@ -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; |
| 2234 | | 2234 | |
| 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); |
| 2237 | | 2237 | |
| 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 |
| 2950 | | 2950 | |
| 2951 | static IrInstruction *ir_instruction_aligncast_get_dep(IrInstructionAlignCast *instruction, size_t index) { | 2951 | static 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 | } |
| 14514 | | 14514 | |
| | 14515 | static 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 | |
| 14515 | static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) { | 14589 | static 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 | } |
| 14559 | | 14633 | |
| 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 | } |
| 14566 | | 14650 | |
| 14567 | static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) { | 14651 | static 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; |
| 14962 | | 15046 | |
| 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; |
| 14967 | | 15050 | |
| 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 | } | | |
| 15016 | | 15054 | |
| 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 | } |
| 15040 | | 15058 | |
| 15041 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { | 15059 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |