diff options
| author | LemonBoy <thatlemon@gmail.com> | 2019-12-20 10:48:03 +0100 |
|---|---|---|
| committer | LemonBoy <thatlemon@gmail.com> | 2020-01-08 20:03:03 +0100 |
| commit | e134e6c994d6ecd76dc6ae1a24b8de29c4147eab (patch) | |
| tree | 6c0b4e7a367fd0507d0f32e0de131a43d8b9e444 | |
| parent | 02ace4569ec52561f627ad3a33d7b90b7bdbb6f5 (diff) | |
| download | zig-e134e6c994d6ecd76dc6ae1a24b8de29c4147eab.tar.gz zig-e134e6c994d6ecd76dc6ae1a24b8de29c4147eab.zip | |
Pointer arithmetic affects the alignment factor
Closes #1528
| -rw-r--r-- | lib/std/start.zig | 4 | ||||
| -rw-r--r-- | src/ir.cpp | 43 | ||||
| -rw-r--r-- | test/stage1/behavior/pointers.zig | 16 |
3 files changed, 52 insertions, 11 deletions
diff --git a/lib/std/start.zig b/lib/std/start.zig index 7c1353e18b..7a10d87300 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -142,14 +142,14 @@ fn posixCallMainAndExit() noreturn { const argc = starting_stack_ptr[0]; const argv = @ptrCast([*][*:0]u8, starting_stack_ptr + 1); - const envp_optional = @ptrCast([*:null]?[*:0]u8, argv + argc + 1); + const envp_optional = @ptrCast([*:null]?[*:0]u8, @alignCast(@alignOf(usize), argv + argc + 1)); var envp_count: usize = 0; while (envp_optional[envp_count]) |_| : (envp_count += 1) {} const envp = @ptrCast([*][*:0]u8, envp_optional)[0..envp_count]; if (builtin.os == .linux) { // Find the beginning of the auxiliary vector - const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1); + const auxv = @ptrCast([*]std.elf.Auxv, @alignCast(@alignOf(usize), envp.ptr + envp_count + 1)); std.os.linux.elf_aux_maybe = auxv; // Initialize the TLS area const gnu_stack_phdr = std.os.linux.tls.initTLS() orelse @panic("ELF missing stack size"); diff --git a/src/ir.cpp b/src/ir.cpp index e841da35d0..f7e7aa8902 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15776,19 +15776,44 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp return ir_const_undef(ira, &instruction->base, op1->value->type); } + // NOTE: this variable is meaningful iff op2_val is not null! + uint64_t byte_offset; + if (op2_val != nullptr) { + uint64_t elem_offset; + if (!ir_resolve_usize(ira, casted_op2, &elem_offset)) + return ira->codegen->invalid_instruction; + + ZigType *elem_type = op1->value->type->data.pointer.child_type; + if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) + return ira->codegen->invalid_instruction; + byte_offset = type_size(ira->codegen, elem_type) * elem_offset; + } + + // Fast path for cases where the RHS is zero + if (op2_val != nullptr && byte_offset == 0) { + return op1; + } + + ZigType *result_type = op1->value->type; + // The resulting pointer may not be aligned anymore + if (op2_val != nullptr) { + uint32_t align_bytes; + if ((err = resolve_ptr_align(ira, op1->value->type, &align_bytes))) + return ira->codegen->invalid_instruction; + + if (byte_offset != 0 && byte_offset % align_bytes != 0) + result_type = adjust_ptr_align(ira->codegen, result_type, 1); + } else { + // The addend is not a comptime-known value + result_type = adjust_ptr_align(ira->codegen, result_type, 1); + } + if (op2_val != nullptr && op1_val != nullptr && (op1->value->data.x_ptr.special == ConstPtrSpecialHardCodedAddr || op1->value->data.x_ptr.special == ConstPtrSpecialNull)) { uint64_t start_addr = (op1_val->data.x_ptr.special == ConstPtrSpecialNull) ? 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr; - uint64_t elem_offset; - if (!ir_resolve_usize(ira, casted_op2, &elem_offset)) - return ira->codegen->invalid_instruction; - ZigType *elem_type = op1_val->type->data.pointer.child_type; - if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_instruction; - uint64_t byte_offset = type_size(ira->codegen, elem_type) * elem_offset; uint64_t new_addr; if (op_id == IrBinOpAdd) { new_addr = start_addr + byte_offset; @@ -15797,7 +15822,7 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp } else { zig_unreachable(); } - IrInstruction *result = ir_const(ira, &instruction->base, op1_val->type); + IrInstruction *result = ir_const(ira, &instruction->base, result_type); result->value->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; result->value->data.x_ptr.mut = ConstPtrMutRuntimeVar; result->value->data.x_ptr.data.hard_coded_addr.addr = new_addr; @@ -15806,7 +15831,7 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp IrInstruction *result = ir_build_bin_op(&ira->new_irb, instruction->base.scope, instruction->base.source_node, op_id, op1, casted_op2, true); - result->value->type = op1->value->type; + result->value->type = result_type; return result; } diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index e1004243fc..048cdb150f 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -288,3 +288,19 @@ test "pointer to array at fixed address" { // Silly check just to reference `array` expect(@ptrToInt(&array[0]) == 0x10); } + +test "pointer arithmetic affects the alignment" { + var arr: [10]u8 align(2) = undefined; + var x: usize = 1; + + const ptr = @as([*]u8, &arr); + expect(@typeInfo(@TypeOf(ptr)).Pointer.alignment == 2); + const ptr1 = ptr + 1; + expect(@typeInfo(@TypeOf(ptr1)).Pointer.alignment == 1); + const ptr2 = ptr + 4; + expect(@typeInfo(@TypeOf(ptr2)).Pointer.alignment == 2); + const ptr3 = ptr + 0; + expect(@typeInfo(@TypeOf(ptr3)).Pointer.alignment == 2); + const ptr4 = ptr + x; + expect(@typeInfo(@TypeOf(ptr4)).Pointer.alignment == 1); +} |
