aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLemonBoy <thatlemon@gmail.com>2019-12-20 10:48:03 +0100
committerLemonBoy <thatlemon@gmail.com>2020-01-08 20:03:03 +0100
commite134e6c994d6ecd76dc6ae1a24b8de29c4147eab (patch)
tree6c0b4e7a367fd0507d0f32e0de131a43d8b9e444 /src
parent02ace4569ec52561f627ad3a33d7b90b7bdbb6f5 (diff)
downloadzig-e134e6c994d6ecd76dc6ae1a24b8de29c4147eab.tar.gz
zig-e134e6c994d6ecd76dc6ae1a24b8de29c4147eab.zip
Pointer arithmetic affects the alignment factor
Closes #1528
Diffstat (limited to 'src')
-rw-r--r--src/ir.cpp43
1 files changed, 34 insertions, 9 deletions
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;
}