| author | |
| committer | |
| log | 816689a3b1c98ec008438e7f868e1a123889b2a7 |
| tree | 84dcf5e1cb51689543fea4c39b4c9f24dde681e9 |
| parent | be94299666e57486be6bdb8fee2b79dbf3623c5d |
See #3710 files changed, 69 insertions(+), 20 deletions(-)
src/all_types.hpp+1| ... | @@ -913,6 +913,7 @@ struct FnTypeId { | ... | @@ -913,6 +913,7 @@ struct FnTypeId { |
| 913 | size_t next_param_index; | 913 | size_t next_param_index; |
| 914 | bool is_var_args; | 914 | bool is_var_args; |
| 915 | CallingConvention cc; | 915 | CallingConvention cc; |
| 916 | uint32_t alignment; | ||
| 916 | }; | 917 | }; |
| 917 | 918 | ||
| 918 | uint32_t fn_type_id_hash(FnTypeId*); | 919 | uint32_t fn_type_id_hash(FnTypeId*); |
src/analyze.cpp+21-6| ... | @@ -2899,14 +2899,29 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) { | ... | @@ -2899,14 +2899,29 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) { |
| 2899 | } | 2899 | } |
| 2900 | } | 2900 | } |
| 2901 | 2901 | ||
| 2902 | bool type_is_codegen_pointer(TypeTableEntry *type) { | 2902 | TypeTableEntry *get_codegen_ptr_type(TypeTableEntry *type) { |
| 2903 | if (type->id == TypeTableEntryIdPointer) return true; | 2903 | if (type->id == TypeTableEntryIdPointer) return type; |
| 2904 | if (type->id == TypeTableEntryIdFn) return true; | 2904 | if (type->id == TypeTableEntryIdFn) return type; |
| 2905 | if (type->id == TypeTableEntryIdMaybe) { | 2905 | if (type->id == TypeTableEntryIdMaybe) { |
| 2906 | if (type->data.maybe.child_type->id == TypeTableEntryIdPointer) return true; | 2906 | if (type->data.maybe.child_type->id == TypeTableEntryIdPointer) return type->data.maybe.child_type; |
| 2907 | if (type->data.maybe.child_type->id == TypeTableEntryIdFn) return true; | 2907 | if (type->data.maybe.child_type->id == TypeTableEntryIdFn) return type->data.maybe.child_type; |
| 2908 | } | ||
| 2909 | return nullptr; | ||
| 2910 | } | ||
| 2911 | |||
| 2912 | bool type_is_codegen_pointer(TypeTableEntry *type) { | ||
| 2913 | return get_codegen_ptr_type(type) != nullptr; | ||
| 2914 | } | ||
| 2915 | |||
| 2916 | uint32_t get_ptr_align(TypeTableEntry *type) { | ||
| 2917 | TypeTableEntry *ptr_type = get_codegen_ptr_type(type); | ||
| 2918 | if (ptr_type->id == TypeTableEntryIdPointer) { | ||
| 2919 | return ptr_type->data.pointer.alignment; | ||
| 2920 | } else if (ptr_type->id == TypeTableEntryIdFn) { | ||
| 2921 | return (ptr_type->data.fn.fn_type_id.alignment == 0) ? 1 : ptr_type->data.fn.fn_type_id.alignment; | ||
| 2922 | } else { | ||
| 2923 | zig_unreachable(); | ||
| 2908 | } | 2924 | } |
| 2909 | return false; | ||
| 2910 | } | 2925 | } |
| 2911 | 2926 | ||
| 2912 | AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index) { | 2927 | AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index) { |
src/analyze.hpp+2| ... | @@ -52,6 +52,8 @@ VariableTableEntry *find_variable(CodeGen *g, Scope *orig_context, Buf *name); | ... | @@ -52,6 +52,8 @@ VariableTableEntry *find_variable(CodeGen *g, Scope *orig_context, Buf *name); |
| 52 | Tld *find_decl(CodeGen *g, Scope *scope, Buf *name); | 52 | Tld *find_decl(CodeGen *g, Scope *scope, Buf *name); |
| 53 | void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node); | 53 | void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node); |
| 54 | bool type_is_codegen_pointer(TypeTableEntry *type); | 54 | bool type_is_codegen_pointer(TypeTableEntry *type); |
| 55 | TypeTableEntry *get_codegen_ptr_type(TypeTableEntry *type); | ||
| 56 | uint32_t get_ptr_align(TypeTableEntry *type); | ||
| 55 | TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry); | 57 | TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry); |
| 56 | TypeTableEntry *container_ref_type(TypeTableEntry *type_entry); | 58 | TypeTableEntry *container_ref_type(TypeTableEntry *type_entry); |
| 57 | bool type_is_complete(TypeTableEntry *type_entry); | 59 | bool type_is_complete(TypeTableEntry *type_entry); |
src/ir.cpp+14-3| ... | @@ -10830,7 +10830,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc | ... | @@ -10830,7 +10830,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc |
| 10830 | if (ptr_type->data.pointer.unaligned_bit_count == 0) { | 10830 | if (ptr_type->data.pointer.unaligned_bit_count == 0) { |
| 10831 | return_type = get_pointer_to_type_extra(ira->codegen, child_type, | 10831 | return_type = get_pointer_to_type_extra(ira->codegen, child_type, |
| 10832 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, | 10832 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, |
| 10833 | get_abi_alignment(ira->codegen, child_type), 0, 0); | 10833 | ptr_type->data.pointer.alignment, 0, 0); |
| 10834 | } else { | 10834 | } else { |
| 10835 | uint64_t elem_val_scalar; | 10835 | uint64_t elem_val_scalar; |
| 10836 | if (!ir_resolve_usize(ira, elem_index, &elem_val_scalar)) | 10836 | if (!ir_resolve_usize(ira, elem_index, &elem_val_scalar)) |
| ... | @@ -10841,8 +10841,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc | ... | @@ -10841,8 +10841,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc |
| 10841 | 10841 | ||
| 10842 | return_type = get_pointer_to_type_extra(ira->codegen, child_type, | 10842 | return_type = get_pointer_to_type_extra(ira->codegen, child_type, |
| 10843 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, | 10843 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, |
| 10844 | get_abi_alignment(ira->codegen, child_type), | 10844 | 1, (uint32_t)bit_offset, (uint32_t)bit_width); |
| 10845 | (uint32_t)bit_offset, (uint32_t)bit_width); | ||
| 10846 | } | 10845 | } |
| 10847 | } else if (array_type->id == TypeTableEntryIdPointer) { | 10846 | } else if (array_type->id == TypeTableEntryIdPointer) { |
| 10848 | return_type = array_type; | 10847 | return_type = array_type; |
| ... | @@ -14457,6 +14456,18 @@ static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruc | ... | @@ -14457,6 +14456,18 @@ static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruc |
| 14457 | return dest_type; | 14456 | return dest_type; |
| 14458 | } | 14457 | } |
| 14459 | 14458 | ||
| 14459 | uint32_t src_align_bytes = get_ptr_align(src_type); | ||
| 14460 | uint32_t dest_align_bytes = get_ptr_align(dest_type); | ||
| 14461 | |||
| 14462 | if (dest_align_bytes > src_align_bytes) { | ||
| 14463 | ErrorMsg *msg = ir_add_error(ira, &instruction->base, buf_sprintf("cast increases pointer alignment")); | ||
| 14464 | add_error_note(ira->codegen, msg, ptr->source_node, | ||
| 14465 | buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&src_type->name), src_align_bytes)); | ||
| 14466 | add_error_note(ira->codegen, msg, dest_type_value->source_node, | ||
| 14467 | buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&dest_type->name), dest_align_bytes)); | ||
| 14468 | return ira->codegen->builtin_types.entry_invalid; | ||
| 14469 | } | ||
| 14470 | |||
| 14460 | IrInstruction *result = ir_build_ptr_cast(&ira->new_irb, instruction->base.scope, | 14471 | IrInstruction *result = ir_build_ptr_cast(&ira->new_irb, instruction->base.scope, |
| 14461 | instruction->base.source_node, nullptr, ptr); | 14472 | instruction->base.source_node, nullptr, ptr); |
| 14462 | ir_link_new_instruction(result, &instruction->base); | 14473 | ir_link_new_instruction(result, &instruction->base); |
std/os/darwin.zig+1-1| ... | @@ -172,7 +172,7 @@ pub fn fork() -> usize { | ... | @@ -172,7 +172,7 @@ pub fn fork() -> usize { |
| 172 | 172 | ||
| 173 | pub fn pipe(fds: &[2]i32) -> usize { | 173 | pub fn pipe(fds: &[2]i32) -> usize { |
| 174 | comptime assert(i32.bit_count == c_int.bit_count); | 174 | comptime assert(i32.bit_count == c_int.bit_count); |
| 175 | errnoWrap(c.pipe(@ptrCast(&c_int, &(*fds)[0]))) | 175 | errnoWrap(c.pipe(@ptrCast(&c_int, fds))) |
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | pub fn mkdir(path: &const u8, mode: u32) -> usize { | 178 | pub fn mkdir(path: &const u8, mode: u32) -> usize { |
std/special/builtin.zig+3-3| ... | @@ -49,8 +49,8 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T { | ... | @@ -49,8 +49,8 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T { |
| 49 | const exp_bits = if (T == f32) 9 else 12; | 49 | const exp_bits = if (T == f32) 9 else 12; |
| 50 | const bits_minus_1 = T.bit_count - 1; | 50 | const bits_minus_1 = T.bit_count - 1; |
| 51 | const mask = if (T == f32) 0xff else 0x7ff; | 51 | const mask = if (T == f32) 0xff else 0x7ff; |
| 52 | var ux = *@ptrCast(&const uint, &x); | 52 | var ux = @bitCast(uint, x); |
| 53 | var uy = *@ptrCast(&const uint, &y); | 53 | var uy = @bitCast(uint, y); |
| 54 | var ex = i32((ux >> digits) & mask); | 54 | var ex = i32((ux >> digits) & mask); |
| 55 | var ey = i32((uy >> digits) & mask); | 55 | var ey = i32((uy >> digits) & mask); |
| 56 | const sx = if (T == f32) u32(ux & 0x80000000) else i32(ux >> bits_minus_1); | 56 | const sx = if (T == f32) u32(ux & 0x80000000) else i32(ux >> bits_minus_1); |
| ... | @@ -113,7 +113,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T { | ... | @@ -113,7 +113,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T { |
| 113 | } else { | 113 | } else { |
| 114 | ux |= uint(sx) << bits_minus_1; | 114 | ux |= uint(sx) << bits_minus_1; |
| 115 | } | 115 | } |
| 116 | return *@ptrCast(&const T, &ux); | 116 | return @bitCast(T, ux); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | fn isNan(comptime T: type, bits: T) -> bool { | 119 | fn isNan(comptime T: type, bits: T) -> bool { |
std/special/compiler_rt/udivmod.zig+5-5| ... | @@ -54,7 +54,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: | ... | @@ -54,7 +54,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: |
| 54 | if (maybe_rem) |rem| { | 54 | if (maybe_rem) |rem| { |
| 55 | r[high] = n[high] % d[high]; | 55 | r[high] = n[high] % d[high]; |
| 56 | r[low] = 0; | 56 | r[low] = 0; |
| 57 | *rem = *@ptrCast(&DoubleInt, &r[0]); // TODO issue #421 | 57 | *rem = *@ptrCast(&align @alignOf(SingleInt) DoubleInt, &r[0]); // TODO issue #421 |
| 58 | } | 58 | } |
| 59 | return n[high] / d[high]; | 59 | return n[high] / d[high]; |
| 60 | } | 60 | } |
| ... | @@ -66,7 +66,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: | ... | @@ -66,7 +66,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: |
| 66 | if (maybe_rem) |rem| { | 66 | if (maybe_rem) |rem| { |
| 67 | r[low] = n[low]; | 67 | r[low] = n[low]; |
| 68 | r[high] = n[high] & (d[high] - 1); | 68 | r[high] = n[high] & (d[high] - 1); |
| 69 | *rem = *@ptrCast(&DoubleInt, &r[0]); // TODO issue #421 | 69 | *rem = *@ptrCast(&align @alignOf(SingleInt) DoubleInt, &r[0]); // TODO issue #421 |
| 70 | } | 70 | } |
| 71 | return n[high] >> Log2SingleInt(@ctz(d[high])); | 71 | return n[high] >> Log2SingleInt(@ctz(d[high])); |
| 72 | } | 72 | } |
| ... | @@ -106,7 +106,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: | ... | @@ -106,7 +106,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: |
| 106 | sr = @ctz(d[low]); | 106 | sr = @ctz(d[low]); |
| 107 | q[high] = n[high] >> Log2SingleInt(sr); | 107 | q[high] = n[high] >> Log2SingleInt(sr); |
| 108 | q[low] = (n[high] << Log2SingleInt(SingleInt.bit_count - sr)) | (n[low] >> Log2SingleInt(sr)); | 108 | q[low] = (n[high] << Log2SingleInt(SingleInt.bit_count - sr)) | (n[low] >> Log2SingleInt(sr)); |
| 109 | return *@ptrCast(&DoubleInt, &q[0]); // TODO issue #421 | 109 | return *@ptrCast(&align @alignOf(SingleInt) DoubleInt, &q[0]); // TODO issue #421 |
| 110 | } | 110 | } |
| 111 | // K X | 111 | // K X |
| 112 | // --- | 112 | // --- |
| ... | @@ -180,13 +180,13 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: | ... | @@ -180,13 +180,13 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: |
| 180 | // r.all -= b; | 180 | // r.all -= b; |
| 181 | // carry = 1; | 181 | // carry = 1; |
| 182 | // } | 182 | // } |
| 183 | r_all = *@ptrCast(&DoubleInt, &r[0]); // TODO issue #421 | 183 | r_all = *@ptrCast(&align @alignOf(SingleInt) DoubleInt, &r[0]); // TODO issue #421 |
| 184 | const s: SignedDoubleInt = SignedDoubleInt(b -% r_all -% 1) >> (DoubleInt.bit_count - 1); | 184 | const s: SignedDoubleInt = SignedDoubleInt(b -% r_all -% 1) >> (DoubleInt.bit_count - 1); |
| 185 | carry = u32(s & 1); | 185 | carry = u32(s & 1); |
| 186 | r_all -= b & @bitCast(DoubleInt, s); | 186 | r_all -= b & @bitCast(DoubleInt, s); |
| 187 | r = *@ptrCast(&[2]SingleInt, &r_all); // TODO issue #421 | 187 | r = *@ptrCast(&[2]SingleInt, &r_all); // TODO issue #421 |
| 188 | } | 188 | } |
| 189 | const q_all = ((*@ptrCast(&DoubleInt, &q[0])) << 1) | carry; // TODO issue #421 | 189 | const q_all = ((*@ptrCast(&align @alignOf(SingleInt) DoubleInt, &q[0])) << 1) | carry; // TODO issue #421 |
| 190 | if (maybe_rem) |rem| { | 190 | if (maybe_rem) |rem| { |
| 191 | *rem = r_all; | 191 | *rem = r_all; |
| 192 | } | 192 | } |
test/cases/align.zig+9| ... | @@ -53,3 +53,12 @@ test "implicitly decreasing slice alignment" { | ... | @@ -53,3 +53,12 @@ test "implicitly decreasing slice alignment" { |
| 53 | assert(addUnalignedSlice((&a)[0..1], (&b)[0..1]) == 7); | 53 | assert(addUnalignedSlice((&a)[0..1], (&b)[0..1]) == 7); |
| 54 | } | 54 | } |
| 55 | fn addUnalignedSlice(a: []align 1 const u32, b: []align 1 const u32) -> u32 { a[0] + b[0] } | 55 | fn addUnalignedSlice(a: []align 1 const u32, b: []align 1 const u32) -> u32 { a[0] + b[0] } |
| 56 | |||
| 57 | test "specifying alignment allows pointer cast" { | ||
| 58 | testBytesAlign(0x33); | ||
| 59 | } | ||
| 60 | fn testBytesAlign(b: u8) { | ||
| 61 | var bytes align 4 = []u8{b, b, b, b}; | ||
| 62 | const ptr = @ptrCast(&u32, &bytes[0]); | ||
| 63 | assert(*ptr == 0x33333333); | ||
| 64 | } |
test/compare_output.zig+2-2| ... | @@ -262,8 +262,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -262,8 +262,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 262 | \\const c = @cImport(@cInclude("stdlib.h")); | 262 | \\const c = @cImport(@cInclude("stdlib.h")); |
| 263 | \\ | 263 | \\ |
| 264 | \\export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int { | 264 | \\export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int { |
| 265 | \\ const a_int = @ptrCast(&i32, a ?? unreachable); | 265 | \\ const a_int = @ptrCast(&align 1 i32, a ?? unreachable); |
| 266 | \\ const b_int = @ptrCast(&i32, b ?? unreachable); | 266 | \\ const b_int = @ptrCast(&align 1 i32, b ?? unreachable); |
| 267 | \\ if (*a_int < *b_int) { | 267 | \\ if (*a_int < *b_int) { |
| 268 | \\ -1 | 268 | \\ -1 |
| 269 | \\ } else if (*a_int > *b_int) { | 269 | \\ } else if (*a_int > *b_int) { |
test/compile_errors.zig+11| ... | @@ -2011,4 +2011,15 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -2011,4 +2011,15 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2011 | \\} | 2011 | \\} |
| 2012 | , | 2012 | , |
| 2013 | ".tmp_source.zig:9:17: error: expected type '[]u32', found '[]align 1 u32'"); | 2013 | ".tmp_source.zig:9:17: error: expected type '[]u32', found '[]align 1 u32'"); |
| 2014 | |||
| 2015 | cases.add("increase pointer alignment in @ptrCast", | ||
| 2016 | \\export fn entry() -> u32 { | ||
| 2017 | \\ var bytes: [4]u8 align 4 = []u8{0x01, 0x02, 0x03, 0x04}; | ||
| 2018 | \\ const ptr = @ptrCast(&u32, &bytes[0]); | ||
| 2019 | \\ return *ptr; | ||
| 2020 | \\} | ||
| 2021 | , | ||
| 2022 | ".tmp_source.zig:3:17: error: cast increases pointer alignment", | ||
| 2023 | ".tmp_source.zig:3:38: note: '&u8' has alignment 1", | ||
| 2024 | ".tmp_source.zig:3:27: note: '&u32' has alignment 4"); | ||
| 2014 | } | 2025 | } |