Commit e134e6c994

LemonBoy <thatlemon@gmail.com>
2019-12-20 10:48:03
Pointer arithmetic affects the alignment factor
Closes #1528
1 parent 02ace45
Changed files (3)
lib
src
test
stage1
behavior
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");
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;
     }
 
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);
+}