mirror of
https://github.com/ziglang/zig.git
synced 2025-12-08 15:23:14 +00:00
Correct alignment calculation for runtime addends
This commit is contained in:
parent
7ea7842ed0
commit
c51b79c56e
22
src/ir.cpp
22
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);
|
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!
|
// NOTE: this variable is meaningful iff op2_val is not null!
|
||||||
uint64_t byte_offset;
|
uint64_t byte_offset;
|
||||||
if (op2_val != nullptr) {
|
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))
|
if (!ir_resolve_usize(ira, casted_op2, &elem_offset))
|
||||||
return ira->codegen->invalid_instruction;
|
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;
|
byte_offset = type_size(ira->codegen, elem_type) * elem_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15795,25 +15796,24 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
|
|||||||
}
|
}
|
||||||
|
|
||||||
ZigType *result_type = op1->value->type;
|
ZigType *result_type = op1->value->type;
|
||||||
// The resulting pointer may not be aligned anymore
|
// Calculate the new alignment of the pointer
|
||||||
if (op2_val != nullptr) {
|
{
|
||||||
uint32_t align_bytes;
|
uint32_t align_bytes;
|
||||||
if ((err = resolve_ptr_align(ira, op1->value->type, &align_bytes)))
|
if ((err = resolve_ptr_align(ira, op1->value->type, &align_bytes)))
|
||||||
return ira->codegen->invalid_instruction;
|
return ira->codegen->invalid_instruction;
|
||||||
|
|
||||||
if (byte_offset & (align_bytes - 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
|
// The resulting pointer is aligned to the lcd between the
|
||||||
// offset (an arbitrary number) and the alignment factor (always
|
// offset (an arbitrary number) and the alignment factor (always
|
||||||
// a power of two, non zero)
|
// a power of two, non zero)
|
||||||
uint32_t new_align = 1 << ctzll(byte_offset | align_bytes);
|
uint32_t new_align = 1 << ctzll(addend | align_bytes);
|
||||||
// Rough guard to prevent overflows
|
// Rough guard to prevent overflows
|
||||||
assert(new_align);
|
assert(new_align);
|
||||||
result_type = adjust_ptr_align(ira->codegen, result_type, 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 (op2_val != nullptr && op1_val != nullptr &&
|
if (op2_val != nullptr && op1_val != nullptr &&
|
||||||
(op1->value->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
|
(op1->value->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
|
||||||
|
|||||||
@ -302,12 +302,19 @@ test "pointer arithmetic affects the alignment" {
|
|||||||
const ptr3 = ptr + 0; // no-op
|
const ptr3 = ptr + 0; // no-op
|
||||||
expect(@typeInfo(@TypeOf(ptr3)).Pointer.alignment == 8);
|
expect(@typeInfo(@TypeOf(ptr3)).Pointer.alignment == 8);
|
||||||
const ptr4 = ptr + x; // runtime-known addend
|
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 ptr: [*]align(8) [3]u8 = undefined;
|
||||||
|
var x: usize = 1;
|
||||||
|
|
||||||
const ptr1 = ptr + 17; // 3 * 17 = 51
|
const ptr1 = ptr + 17; // 3 * 17 = 51
|
||||||
expect(@typeInfo(@TypeOf(ptr1)).Pointer.alignment == 1);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user