authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-08-30 02:25:41-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-08-30 02:25:41-04:00
log5482f9f9e8b66ba0ad1c38384b1c3df8e1381308
tree27b8a8db4aad8625bfe8037587ae0091b59b3dd7
parent56cc62a9c7bf9bfb1daff7dc60a75c380500ebce

when getting an element pointer, use the best alignment

type we can figure out is safe to use See #37

2 files changed, 89 insertions(+), 17 deletions(-)

src/ir.cpp+53-17
......@@ -8404,7 +8404,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
84048404 if (!ir_emit_global_runtime_side_effect(ira, source_instr))
84058405 return ira->codegen->invalid_instruction;
84068406 uint64_t child_type_size = type_size(ira->codegen,
8407 wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type);
8407 wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type);
84088408 if (actual_type->data.array.len % child_type_size == 0) {
84098409 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpBytesToSlice, true);
84108410 } else {
......@@ -10870,6 +10870,15 @@ static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstruct
1087010870 var_ptr_instruction->is_volatile);
1087110871}
1087210872
10873static TypeTableEntry *adjust_ptr_align(CodeGen *g, TypeTableEntry *ptr_type, uint32_t new_align) {
10874 assert(ptr_type->id == TypeTableEntryIdPointer);
10875 return get_pointer_to_type_extra(g,
10876 ptr_type->data.pointer.child_type,
10877 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
10878 new_align,
10879 ptr_type->data.pointer.bit_offset, ptr_type->data.pointer.unaligned_bit_count);
10880}
10881
1087310882static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionElemPtr *elem_ptr_instruction) {
1087410883 IrInstruction *array_ptr = elem_ptr_instruction->array_ptr->other;
1087510884 if (type_is_invalid(array_ptr->value.type))
......@@ -10888,6 +10897,9 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1088810897 assert(ptr_type->id == TypeTableEntryIdPointer);
1088910898
1089010899 TypeTableEntry *array_type = ptr_type->data.pointer.child_type;
10900
10901 // At first return_type will be the pointer type we want to return, except with an optimistic alignment.
10902 // We will adjust return_type's alignment before returning it.
1089110903 TypeTableEntry *return_type;
1089210904
1089310905 if (type_is_invalid(array_type)) {
......@@ -10918,7 +10930,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1091810930 } else if (array_type->id == TypeTableEntryIdPointer) {
1091910931 return_type = array_type;
1092010932 } else if (is_slice(array_type)) {
10921 return_type = array_type->data.structure.fields[0].type_entry;
10933 return_type = array_type->data.structure.fields[slice_ptr_index].type_entry;
1092210934 } else if (array_type->id == TypeTableEntryIdArgTuple) {
1092310935 ConstExprValue *ptr_val = ir_resolve_const(ira, array_ptr, UndefBad);
1092410936 if (!ptr_val)
......@@ -10961,6 +10973,10 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1096110973 return ira->codegen->builtin_types.entry_invalid;
1096210974
1096310975 bool safety_check_on = elem_ptr_instruction->safety_check_on;
10976 ensure_complete_type(ira->codegen, return_type->data.pointer.child_type);
10977 uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type);
10978 uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type);
10979 uint64_t ptr_align = return_type->data.pointer.alignment;
1096410980 if (instr_is_comptime(casted_elem_index)) {
1096510981 uint64_t index = bigint_as_unsigned(&casted_elem_index->value.data.x_bigint);
1096610982 if (array_type->id == TypeTableEntryIdArray) {
......@@ -10974,6 +10990,26 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1097410990 safety_check_on = false;
1097510991 }
1097610992
10993 {
10994 // figure out the largest alignment possible
10995 uint64_t chosen_align = abi_align;
10996 if (ptr_align >= abi_align) {
10997 while (ptr_align > abi_align) {
10998 if ((index * elem_size) % ptr_align == 0) {
10999 chosen_align = ptr_align;
11000 break;
11001 }
11002 ptr_align >>= 1;
11003 }
11004 } else if (elem_size >= ptr_align && elem_size % ptr_align == 0) {
11005 chosen_align = ptr_align;
11006 } else {
11007 // can't get here because guaranteed elem_size >= abi_align
11008 zig_unreachable();
11009 }
11010 return_type = adjust_ptr_align(ira->codegen, return_type, chosen_align);
11011 }
11012
1097711013 ConstExprValue *array_ptr_val;
1097811014 if (array_ptr->value.special != ConstValSpecialRuntime &&
1097911015 (array_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar || array_type->id == TypeTableEntryIdArray) &&
......@@ -11085,6 +11121,18 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1108511121 }
1108611122 }
1108711123
11124 } else {
11125 // runtime known element index
11126 if (ptr_align < abi_align) {
11127 if (elem_size >= ptr_align && elem_size % ptr_align == 0) {
11128 return_type = adjust_ptr_align(ira->codegen, return_type, ptr_align);
11129 } else {
11130 // can't get here because guaranteed elem_size >= abi_align
11131 zig_unreachable();
11132 }
11133 } else {
11134 return_type = adjust_ptr_align(ira->codegen, return_type, abi_align);
11135 }
1108811136 }
1108911137
1109011138 ir_build_elem_ptr_from(&ira->new_irb, &elem_ptr_instruction->base, array_ptr,
......@@ -14520,11 +14568,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
1452014568 uint32_t old_align_bytes;
1452114569
1452214570 if (target_type->id == TypeTableEntryIdPointer) {
14523 result_type = get_pointer_to_type_extra(ira->codegen,
14524 target_type->data.pointer.child_type,
14525 target_type->data.pointer.is_const, target_type->data.pointer.is_volatile,
14526 align_bytes,
14527 target_type->data.pointer.bit_offset, target_type->data.pointer.unaligned_bit_count);
14571 result_type = adjust_ptr_align(ira->codegen, target_type, align_bytes);
1452814572 } else if (target_type->id == TypeTableEntryIdFn) {
1452914573 FnTypeId fn_type_id = target_type->data.fn.fn_type_id;
1453014574 old_align_bytes = fn_type_id.alignment;
......@@ -14535,11 +14579,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
1453514579 {
1453614580 TypeTableEntry *ptr_type = target_type->data.maybe.child_type;
1453714581 old_align_bytes = ptr_type->data.pointer.alignment;
14538 TypeTableEntry *better_ptr_type = get_pointer_to_type_extra(ira->codegen,
14539 ptr_type->data.pointer.child_type,
14540 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
14541 align_bytes,
14542 ptr_type->data.pointer.bit_offset, ptr_type->data.pointer.unaligned_bit_count);
14582 TypeTableEntry *better_ptr_type = adjust_ptr_align(ira->codegen, ptr_type, align_bytes);
1454314583
1454414584 result_type = get_maybe_type(ira->codegen, better_ptr_type);
1454514585 } else if (target_type->id == TypeTableEntryIdMaybe &&
......@@ -14553,11 +14593,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
1455314593 } else if (is_slice(target_type)) {
1455414594 TypeTableEntry *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;
1455514595 old_align_bytes = slice_ptr_type->data.pointer.alignment;
14556 TypeTableEntry *result_ptr_type = get_pointer_to_type_extra(ira->codegen,
14557 slice_ptr_type->data.pointer.child_type,
14558 slice_ptr_type->data.pointer.is_const, slice_ptr_type->data.pointer.is_volatile,
14559 align_bytes,
14560 slice_ptr_type->data.pointer.bit_offset, slice_ptr_type->data.pointer.unaligned_bit_count);
14596 TypeTableEntry *result_ptr_type = adjust_ptr_align(ira->codegen, slice_ptr_type, align_bytes);
1456114597 result_type = get_slice_type(ira->codegen, result_ptr_type);
1456214598 } else {
1456314599 ir_add_error(ira, target,
test/cases/align.zig+36
......@@ -143,3 +143,39 @@ test "@ptrCast preserves alignment of bigger source" {
143143 const ptr = @ptrCast(&u8, &x);
144144 assert(@typeOf(ptr) == &align 16 u8);
145145}
146
147
148test "compile-time known array index has best alignment possible" {
149 // take full advantage of over-alignment
150 var array align 4 = []u8 {1, 2, 3, 4};
151 assert(@typeOf(&array[0]) == &align 4 u8);
152 assert(@typeOf(&array[1]) == &u8);
153 assert(@typeOf(&array[2]) == &align 2 u8);
154 assert(@typeOf(&array[3]) == &u8);
155
156 // because align is too small but we still figure out to use 2
157 var bigger align 2 = []u64{1, 2, 3, 4};
158 assert(@typeOf(&bigger[0]) == &align 2 u64);
159 assert(@typeOf(&bigger[1]) == &align 2 u64);
160 assert(@typeOf(&bigger[2]) == &align 2 u64);
161 assert(@typeOf(&bigger[3]) == &align 2 u64);
162
163 // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2
164 var smaller align 2 = []u32{1, 2, 3, 4};
165 testIndex(&smaller[0], 0, &align 2 u32);
166 testIndex(&smaller[0], 1, &align 2 u32);
167 testIndex(&smaller[0], 2, &align 2 u32);
168 testIndex(&smaller[0], 3, &align 2 u32);
169
170 // has to use ABI alignment because index known at runtime only
171 testIndex2(&array[0], 0, &u8);
172 testIndex2(&array[0], 1, &u8);
173 testIndex2(&array[0], 2, &u8);
174 testIndex2(&array[0], 3, &u8);
175}
176fn testIndex(smaller: &align 2 u32, index: usize, comptime T: type) {
177 assert(@typeOf(&smaller[index]) == T);
178}
179fn testIndex2(ptr: &align 4 u8, index: usize, comptime T: type) {
180 assert(@typeOf(&ptr[index]) == T);
181}