Commit c51b79c56e

LemonBoy <thatlemon@gmail.com>
2020-01-09 11:56:45
Correct alignment calculation for runtime addends
1 parent 7ea7842
Changed files (2)
src
test
stage1
behavior
src/ir.cpp
@@ -15776,6 +15776,10 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
                 return ir_const_undef(ira, &instruction->base, op1->value->type);
         }
 
+        ZigType *elem_type = op1->value->type->data.pointer.child_type;
+        if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown)))
+            return ira->codegen->invalid_instruction;
+
         // NOTE: this variable is meaningful iff op2_val is not null!
         uint64_t byte_offset;
         if (op2_val != nullptr) {
@@ -15783,9 +15787,6 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
             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;
         }
 
@@ -15795,24 +15796,23 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
         }
 
         ZigType *result_type = op1->value->type;
-        // The resulting pointer may not be aligned anymore
-        if (op2_val != nullptr) {
+        // Calculate the new alignment of the pointer
+        {
             uint32_t align_bytes;
             if ((err = resolve_ptr_align(ira, op1->value->type, &align_bytes)))
                 return ira->codegen->invalid_instruction;
 
-            if (byte_offset & (align_bytes - 1)) {
-                // The resulting pointer is aligned to the lcd between the
-                // offset (an arbitrary number) and the alignment factor (always
-                // a power of two, non zero)
-                uint32_t new_align = 1 << ctzll(byte_offset | align_bytes);
-                // Rough guard to prevent overflows
-                assert(new_align);
-                result_type = adjust_ptr_align(ira->codegen, result_type, new_align);
-            }
-        } else {
-            // The addend is not a comptime-known value
-            result_type = adjust_ptr_align(ira->codegen, result_type, 1);
+            // If the addend is not a comptime-known value we can still count on
+            // it being a multiple of the type size
+            uint32_t addend = op2_val ? byte_offset : type_size(ira->codegen, elem_type);
+
+            // The resulting pointer is aligned to the lcd between the
+            // offset (an arbitrary number) and the alignment factor (always
+            // a power of two, non zero)
+            uint32_t new_align = 1 << ctzll(addend | align_bytes);
+            // Rough guard to prevent overflows
+            assert(new_align);
+            result_type = adjust_ptr_align(ira->codegen, result_type, new_align);
         }
 
         if (op2_val != nullptr && op1_val != nullptr &&
test/stage1/behavior/pointers.zig
@@ -302,12 +302,19 @@ test "pointer arithmetic affects the alignment" {
         const ptr3 = ptr + 0; // no-op
         expect(@typeInfo(@TypeOf(ptr3)).Pointer.alignment == 8);
         const ptr4 = ptr + x; // runtime-known addend
-        expect(@typeInfo(@TypeOf(ptr4)).Pointer.alignment == 1);
+        expect(@typeInfo(@TypeOf(ptr4)).Pointer.alignment == 4);
     }
     {
         var ptr: [*]align(8) [3]u8 = undefined;
+        var x: usize = 1;
 
         const ptr1 = ptr + 17; // 3 * 17 = 51
         expect(@typeInfo(@TypeOf(ptr1)).Pointer.alignment == 1);
+        const ptr2 = ptr + x; // runtime-known addend
+        expect(@typeInfo(@TypeOf(ptr2)).Pointer.alignment == 1);
+        const ptr3 = ptr + 8; // 3 * 8 = 24 -> lcd(8,24) = 8
+        expect(@typeInfo(@TypeOf(ptr3)).Pointer.alignment == 8);
+        const ptr4 = ptr + 4; // 3 * 4 = 12 -> lcd(8,12) = 4
+        expect(@typeInfo(@TypeOf(ptr4)).Pointer.alignment == 4);
     }
 }